aboutsummaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-07-23 18:12:53 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-07-23 18:12:53 -0300
commite3716ee161bb5416b5eb846eff6039d61954cfbd (patch)
tree4288e7f7ad1d74d375bb2923ad21ca7ecd44ba8f /lstrlib.c
parent303f4155593721dfd57dadc6e56122e465ce9efb (diff)
downloadlua-e3716ee161bb5416b5eb846eff6039d61954cfbd.tar.gz
lua-e3716ee161bb5416b5eb846eff6039d61954cfbd.tar.bz2
lua-e3716ee161bb5416b5eb846eff6039d61954cfbd.zip
Fix in string.repHEADmaster
The cast of n (number of repetitions) to size_t may truncate its value, causing a buffer overflow later. Better to check the buffer size using lua_Integer, as all string lengths must fit in a lua_Integer and n already is a lua_Integer. If everything fits in MAX_SIZE, then we can safely convert n to size_t and compute the buffer size as a size_t. As a corner case, n can be larger than size_t if the strings being repeated have length zero, but in this case it will be multiplied by zero, so an overflow in the cast is irrelevant.
Diffstat (limited to 'lstrlib.c')
-rw-r--r--lstrlib.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 8056c6ff..d9735903 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -132,27 +132,31 @@ static int str_upper (lua_State *L) {
132} 132}
133 133
134 134
135/*
136** MAX_SIZE is limited both by size_t and lua_Integer.
137** When x <= MAX_SIZE, x can be safely cast to size_t or lua_Integer.
138*/
135static int str_rep (lua_State *L) { 139static int str_rep (lua_State *L) {
136 size_t l, lsep; 140 size_t len, lsep;
137 const char *s = luaL_checklstring(L, 1, &l); 141 const char *s = luaL_checklstring(L, 1, &len);
138 lua_Integer n = luaL_checkinteger(L, 2); 142 lua_Integer n = luaL_checkinteger(L, 2);
139 const char *sep = luaL_optlstring(L, 3, "", &lsep); 143 const char *sep = luaL_optlstring(L, 3, "", &lsep);
140 if (n <= 0) 144 if (n <= 0)
141 lua_pushliteral(L, ""); 145 lua_pushliteral(L, "");
142 else if (l_unlikely(l + lsep < l || l + lsep > MAX_SIZE / cast_sizet(n))) 146 else if (l_unlikely(len > MAX_SIZE - lsep ||
147 cast_st2S(len + lsep) > cast_st2S(MAX_SIZE) / n))
143 return luaL_error(L, "resulting string too large"); 148 return luaL_error(L, "resulting string too large");
144 else { 149 else {
145 size_t totallen = ((size_t)n * (l + lsep)) - lsep; 150 size_t totallen = (cast_sizet(n) * (len + lsep)) - lsep;
146 luaL_Buffer b; 151 luaL_Buffer b;
147 char *p = luaL_buffinitsize(L, &b, totallen); 152 char *p = luaL_buffinitsize(L, &b, totallen);
148 while (n-- > 1) { /* first n-1 copies (followed by separator) */ 153 while (n-- > 1) { /* first n-1 copies (followed by separator) */
149 memcpy(p, s, l * sizeof(char)); p += l; 154 memcpy(p, s, len * sizeof(char)); p += len;
150 if (lsep > 0) { /* empty 'memcpy' is not that cheap */ 155 if (lsep > 0) { /* empty 'memcpy' is not that cheap */
151 memcpy(p, sep, lsep * sizeof(char)); 156 memcpy(p, sep, lsep * sizeof(char)); p += lsep;
152 p += lsep;
153 } 157 }
154 } 158 }
155 memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ 159 memcpy(p, s, len * sizeof(char)); /* last copy without separator */
156 luaL_pushresultsize(&b, totallen); 160 luaL_pushresultsize(&b, totallen);
157 } 161 }
158 return 1; 162 return 1;