diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-07 16:59:52 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-07 16:59:52 -0200 |
commit | 76223730332cbda5d47c09f019ce721b91bd5be2 (patch) | |
tree | 375c159891df5faf827dde4175ce42b7aa503194 | |
parent | 46bc7f2bf7cf7f48c354fde6b9571b795bdd5b4d (diff) | |
download | lua-76223730332cbda5d47c09f019ce721b91bd5be2.tar.gz lua-76223730332cbda5d47c09f019ce721b91bd5be2.tar.bz2 lua-76223730332cbda5d47c09f019ce721b91bd5be2.zip |
using explicit tests for allocation overflow whenever possible
-rw-r--r-- | lmem.c | 28 | ||||
-rw-r--r-- | lmem.h | 32 | ||||
-rw-r--r-- | lstring.c | 12 | ||||
-rw-r--r-- | ltable.c | 38 | ||||
-rw-r--r-- | lundump.c | 16 |
5 files changed, 80 insertions, 46 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp roberto $ | 2 | ** $Id: lmem.c,v 1.92 2017/12/06 18:36:31 roberto Exp roberto $ |
3 | ** Interface to Memory Manager | 3 | ** Interface to Memory Manager |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -53,24 +53,26 @@ | |||
53 | #define MINSIZEARRAY 4 | 53 | #define MINSIZEARRAY 4 |
54 | 54 | ||
55 | 55 | ||
56 | void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *size, | 56 | void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, |
57 | int size_elems, int limit, const char *what) { | 57 | int size_elems, int limit, const char *what) { |
58 | void *newblock; | 58 | void *newblock; |
59 | int newsize; | 59 | int size = *psize; |
60 | if (nelems + 1 <= *size) /* does one extra element still fit? */ | 60 | if (nelems + 1 <= size) /* does one extra element still fit? */ |
61 | return block; /* nothing to be done */ | 61 | return block; /* nothing to be done */ |
62 | if (*size >= limit/2) { /* cannot double it? */ | 62 | if (size >= limit / 2) { /* cannot double it? */ |
63 | if (*size >= limit) /* cannot grow even a little? */ | 63 | if (size >= limit) /* cannot grow even a little? */ |
64 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); | 64 | luaG_runerror(L, "too many %s (limit is %d)", what, limit); |
65 | newsize = limit; /* still have at least one free place */ | 65 | size = limit; /* still have at least one free place */ |
66 | } | 66 | } |
67 | else { | 67 | else { |
68 | newsize = (*size)*2; | 68 | size *= 2; |
69 | if (newsize < MINSIZEARRAY) | 69 | if (size < MINSIZEARRAY) |
70 | newsize = MINSIZEARRAY; /* minimum size */ | 70 | size = MINSIZEARRAY; /* minimum size */ |
71 | } | 71 | } |
72 | newblock = luaM_reallocv(L, block, *size, newsize, size_elems); | 72 | /* 'limit' ensures that multiplication will not overflow */ |
73 | *size = newsize; /* update only when everything else is OK */ | 73 | newblock = luaM_realloc(L, block, cast(size_t, *psize) * size_elems, |
74 | cast(size_t, size) * size_elems); | ||
75 | *psize = size; /* update only when everything else is OK */ | ||
74 | return newblock; | 76 | return newblock; |
75 | } | 77 | } |
76 | 78 | ||
@@ -113,7 +115,7 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { | |||
113 | /* | 115 | /* |
114 | ** generic allocation routine. | 116 | ** generic allocation routine. |
115 | */ | 117 | */ |
116 | void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { | 118 | void *luaM_realloc (lua_State *L, void *block, size_t osize, size_t nsize) { |
117 | void *newblock; | 119 | void *newblock; |
118 | global_State *g = G(L); | 120 | global_State *g = G(L); |
119 | lua_assert((osize == 0) == (block == NULL)); | 121 | lua_assert((osize == 0) == (block == NULL)); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp roberto $ | 2 | ** $Id: lmem.h,v 1.44 2017/12/06 18:36:31 roberto Exp roberto $ |
3 | ** Interface to Memory Manager | 3 | ** Interface to Memory Manager |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -31,36 +31,40 @@ | |||
31 | #define luaM_checksize(L,n,e) \ | 31 | #define luaM_checksize(L,n,e) \ |
32 | (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) | 32 | (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) |
33 | 33 | ||
34 | |||
34 | /* | 35 | /* |
35 | ** This macro reallocs a vector 'b' from 'on' to 'n' elements, where | 36 | ** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that |
36 | ** each element has size 'e'. In case of arithmetic overflow of the | 37 | ** the result is not larger than 'n' and cannot overflow a 'size_t' |
37 | ** product 'n'*'e', it raises an error (calling 'luaM_toobig'). | 38 | ** when multiplied by the size of type 't'. (Assumes that 'n' is an |
39 | ** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) | ||
38 | */ | 40 | */ |
39 | #define luaM_reallocv(L,b,on,n,e) \ | 41 | #define luaM_limitN(n,t) \ |
40 | (luaM_checksize(L,n,e), \ | 42 | ((cast(size_t, n) > MAX_SIZET/sizeof(t)) ? (MAX_SIZET/sizeof(t)) : (n)) |
41 | luaM_realloc_(L, (b), cast(size_t, on)*(e), cast(size_t, n)*(e))) | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | ** Arrays of chars do not need any test | 45 | ** Arrays of chars do not need any test |
45 | */ | 46 | */ |
46 | #define luaM_reallocvchar(L,b,on,n) \ | 47 | #define luaM_reallocvchar(L,b,on,n) \ |
47 | cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) | 48 | cast(char *, luaM_realloc(L, (b), (on)*sizeof(char), (n)*sizeof(char))) |
48 | 49 | ||
49 | #define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) | 50 | #define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) |
50 | #define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) | 51 | #define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) |
51 | #define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) | 52 | #define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) |
52 | 53 | ||
53 | #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t), 0)) | 54 | #define luaM_new(L,t) cast(t*, luaM_malloc(L, sizeof(t), 0)) |
54 | #define luaM_newvector(L,n,t) \ | 55 | #define luaM_newvector(L,n,t) cast(t*, luaM_malloc(L, (n)*sizeof(t), 0)) |
55 | (luaM_checksize(L,n,sizeof(t)), cast(t *, luaM_malloc(L, (n)*sizeof(t), 0))) | 56 | #define luaM_newvectorchecked(L,n,t) \ |
57 | (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) | ||
56 | 58 | ||
57 | #define luaM_newobject(L,tag,s) luaM_malloc(L, (s), tag) | 59 | #define luaM_newobject(L,tag,s) luaM_malloc(L, (s), tag) |
58 | 60 | ||
59 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ | 61 | #define luaM_growvector(L,v,nelems,size,t,limit,e) \ |
60 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t),limit,e))) | 62 | ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ |
63 | luaM_limitN(limit,t),e))) | ||
61 | 64 | ||
62 | #define luaM_reallocvector(L, v,oldn,n,t) \ | 65 | #define luaM_reallocvector(L, v,oldn,n,t) \ |
63 | ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) | 66 | ((v)=cast(t *, luaM_realloc(L, v, cast(size_t, oldn) * sizeof(t), \ |
67 | cast(size_t, n) * sizeof(t)))) | ||
64 | 68 | ||
65 | #define luaM_shrinkvector(L,v,size,fs,t) \ | 69 | #define luaM_shrinkvector(L,v,size,fs,t) \ |
66 | ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) | 70 | ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) |
@@ -68,7 +72,7 @@ | |||
68 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); | 72 | LUAI_FUNC l_noret luaM_toobig (lua_State *L); |
69 | 73 | ||
70 | /* not to be called directly */ | 74 | /* not to be called directly */ |
71 | LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, | 75 | LUAI_FUNC void *luaM_realloc (lua_State *L, void *block, size_t oldsize, |
72 | size_t size); | 76 | size_t size); |
73 | LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); | 77 | LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); |
74 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, | 78 | LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.c,v 2.57 2017/07/27 13:50:16 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 2.58 2017/12/01 16:40:29 roberto Exp roberto $ |
3 | ** String table (keeps all strings handled by Lua) | 3 | ** String table (keeps all strings handled by Lua) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -31,6 +31,13 @@ | |||
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | 33 | ||
34 | |||
35 | /* | ||
36 | ** Maximum size for string table. | ||
37 | */ | ||
38 | #define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) | ||
39 | |||
40 | |||
34 | /* | 41 | /* |
35 | ** equality for long strings | 42 | ** equality for long strings |
36 | */ | 43 | */ |
@@ -173,7 +180,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { | |||
173 | return ts; | 180 | return ts; |
174 | } | 181 | } |
175 | } | 182 | } |
176 | if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { | 183 | if (g->strt.nuse >= g->strt.size && |
184 | g->strt.size <= MAXSTRTB / 2) { | ||
177 | luaS_resize(L, g->strt.size * 2); | 185 | luaS_resize(L, g->strt.size * 2); |
178 | list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ | 186 | list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ |
179 | } | 187 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 2.126 2017/11/08 14:50:23 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.127 2017/11/23 19:29:04 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -40,21 +40,34 @@ | |||
40 | 40 | ||
41 | 41 | ||
42 | /* | 42 | /* |
43 | ** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is | 43 | ** MAXABITS is the largest integer such that MAXASIZE fits in an |
44 | ** the largest integer such that MAXASIZE fits in an unsigned int. | 44 | ** unsigned int. |
45 | */ | 45 | */ |
46 | #define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) | 46 | #define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) |
47 | #define MAXASIZE (1u << MAXABITS) | 47 | |
48 | 48 | ||
49 | /* | 49 | /* |
50 | ** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest | 50 | ** MAXASIZE is the maximum size of the array part. It is the minimum |
51 | ** integer such that 2^MAXHBITS fits in a signed int. (Note that the | 51 | ** between 2^MAXABITS and the maximum size such that, measured in bytes, |
52 | ** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still | 52 | ** it fits in a 'size_t'. |
53 | ** fits comfortably in an unsigned int.) | 53 | */ |
54 | #define MAXASIZE luaM_limitN(1u << MAXABITS, TValue) | ||
55 | |||
56 | /* | ||
57 | ** MAXHBITS is the largest integer such that 2^MAXHBITS fits in a | ||
58 | ** signed int. | ||
54 | */ | 59 | */ |
55 | #define MAXHBITS (MAXABITS - 1) | 60 | #define MAXHBITS (MAXABITS - 1) |
56 | 61 | ||
57 | 62 | ||
63 | /* | ||
64 | ** MAXHSIZE is the maximum size of the hash part. It is the minimum | ||
65 | ** between 2^MAXHBITS and the maximum size such that, measured in bytes, | ||
66 | ** it fits in a 'size_t'. | ||
67 | */ | ||
68 | #define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) | ||
69 | |||
70 | |||
58 | #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) | 71 | #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) |
59 | 72 | ||
60 | #define hashstr(t,str) hashpow2(t, (str)->hash) | 73 | #define hashstr(t,str) hashpow2(t, (str)->hash) |
@@ -353,6 +366,13 @@ static void setarrayvector (lua_State *L, Table *t, unsigned int size) { | |||
353 | } | 366 | } |
354 | 367 | ||
355 | 368 | ||
369 | /* | ||
370 | ** Creates an array for the hash part of a table with the given | ||
371 | ** size, or reuses the dummy node if size is zero. | ||
372 | ** The computation for size overflow is in two steps: the first | ||
373 | ** comparison ensures that the shift in the second one does not | ||
374 | ** overflow. | ||
375 | */ | ||
356 | static void setnodevector (lua_State *L, Table *t, unsigned int size) { | 376 | static void setnodevector (lua_State *L, Table *t, unsigned int size) { |
357 | if (size == 0) { /* no elements to hash part? */ | 377 | if (size == 0) { /* no elements to hash part? */ |
358 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ | 378 | t->node = cast(Node *, dummynode); /* use common 'dummynode' */ |
@@ -362,7 +382,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { | |||
362 | else { | 382 | else { |
363 | int i; | 383 | int i; |
364 | int lsize = luaO_ceillog2(size); | 384 | int lsize = luaO_ceillog2(size); |
365 | if (lsize > MAXHBITS) | 385 | if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) |
366 | luaG_runerror(L, "table overflow"); | 386 | luaG_runerror(L, "table overflow"); |
367 | size = twoto(lsize); | 387 | size = twoto(lsize); |
368 | t->node = luaM_newvector(L, size, Node); | 388 | t->node = luaM_newvector(L, size, Node); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lundump.c,v 2.47 2017/06/29 15:06:44 roberto Exp roberto $ | 2 | ** $Id: lundump.c,v 2.48 2017/11/28 11:19:07 roberto Exp roberto $ |
3 | ** load precompiled Lua chunks | 3 | ** load precompiled Lua chunks |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -114,7 +114,7 @@ static TString *LoadString (LoadState *S) { | |||
114 | 114 | ||
115 | static void LoadCode (LoadState *S, Proto *f) { | 115 | static void LoadCode (LoadState *S, Proto *f) { |
116 | int n = LoadInt(S); | 116 | int n = LoadInt(S); |
117 | f->code = luaM_newvector(S->L, n, Instruction); | 117 | f->code = luaM_newvectorchecked(S->L, n, Instruction); |
118 | f->sizecode = n; | 118 | f->sizecode = n; |
119 | LoadVector(S, f->code, n); | 119 | LoadVector(S, f->code, n); |
120 | } | 120 | } |
@@ -126,7 +126,7 @@ static void LoadFunction(LoadState *S, Proto *f, TString *psource); | |||
126 | static void LoadConstants (LoadState *S, Proto *f) { | 126 | static void LoadConstants (LoadState *S, Proto *f) { |
127 | int i; | 127 | int i; |
128 | int n = LoadInt(S); | 128 | int n = LoadInt(S); |
129 | f->k = luaM_newvector(S->L, n, TValue); | 129 | f->k = luaM_newvectorchecked(S->L, n, TValue); |
130 | f->sizek = n; | 130 | f->sizek = n; |
131 | for (i = 0; i < n; i++) | 131 | for (i = 0; i < n; i++) |
132 | setnilvalue(&f->k[i]); | 132 | setnilvalue(&f->k[i]); |
@@ -159,7 +159,7 @@ static void LoadConstants (LoadState *S, Proto *f) { | |||
159 | static void LoadProtos (LoadState *S, Proto *f) { | 159 | static void LoadProtos (LoadState *S, Proto *f) { |
160 | int i; | 160 | int i; |
161 | int n = LoadInt(S); | 161 | int n = LoadInt(S); |
162 | f->p = luaM_newvector(S->L, n, Proto *); | 162 | f->p = luaM_newvectorchecked(S->L, n, Proto *); |
163 | f->sizep = n; | 163 | f->sizep = n; |
164 | for (i = 0; i < n; i++) | 164 | for (i = 0; i < n; i++) |
165 | f->p[i] = NULL; | 165 | f->p[i] = NULL; |
@@ -173,7 +173,7 @@ static void LoadProtos (LoadState *S, Proto *f) { | |||
173 | static void LoadUpvalues (LoadState *S, Proto *f) { | 173 | static void LoadUpvalues (LoadState *S, Proto *f) { |
174 | int i, n; | 174 | int i, n; |
175 | n = LoadInt(S); | 175 | n = LoadInt(S); |
176 | f->upvalues = luaM_newvector(S->L, n, Upvaldesc); | 176 | f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); |
177 | f->sizeupvalues = n; | 177 | f->sizeupvalues = n; |
178 | for (i = 0; i < n; i++) | 178 | for (i = 0; i < n; i++) |
179 | f->upvalues[i].name = NULL; | 179 | f->upvalues[i].name = NULL; |
@@ -187,18 +187,18 @@ static void LoadUpvalues (LoadState *S, Proto *f) { | |||
187 | static void LoadDebug (LoadState *S, Proto *f) { | 187 | static void LoadDebug (LoadState *S, Proto *f) { |
188 | int i, n; | 188 | int i, n; |
189 | n = LoadInt(S); | 189 | n = LoadInt(S); |
190 | f->lineinfo = luaM_newvector(S->L, n, ls_byte); | 190 | f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); |
191 | f->sizelineinfo = n; | 191 | f->sizelineinfo = n; |
192 | LoadVector(S, f->lineinfo, n); | 192 | LoadVector(S, f->lineinfo, n); |
193 | n = LoadInt(S); | 193 | n = LoadInt(S); |
194 | f->abslineinfo = luaM_newvector(S->L, n, AbsLineInfo); | 194 | f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); |
195 | f->sizeabslineinfo = n; | 195 | f->sizeabslineinfo = n; |
196 | for (i = 0; i < n; i++) { | 196 | for (i = 0; i < n; i++) { |
197 | f->abslineinfo[i].pc = LoadInt(S); | 197 | f->abslineinfo[i].pc = LoadInt(S); |
198 | f->abslineinfo[i].line = LoadInt(S); | 198 | f->abslineinfo[i].line = LoadInt(S); |
199 | } | 199 | } |
200 | n = LoadInt(S); | 200 | n = LoadInt(S); |
201 | f->locvars = luaM_newvector(S->L, n, LocVar); | 201 | f->locvars = luaM_newvectorchecked(S->L, n, LocVar); |
202 | f->sizelocvars = n; | 202 | f->sizelocvars = n; |
203 | for (i = 0; i < n; i++) | 203 | for (i = 0; i < n; i++) |
204 | f->locvars[i].varname = NULL; | 204 | f->locvars[i].varname = NULL; |