Skip to content

Commit e663a24

Browse files
committed
more freedom in handling memory-allocation errors (not all allocations
automatically raise an error), which allows fixing a bug when resizing a table.
1 parent 40f823e commit e663a24

8 files changed

Lines changed: 136 additions & 95 deletions

File tree

lapi.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: lapi.c,v 2.277 2017/11/23 19:29:04 roberto Exp roberto $
2+
** $Id: lapi.c,v 2.278 2017/12/06 18:08:03 roberto Exp roberto $
33
** Lua API
44
** See Copyright Notice in lua.h
55
*/
@@ -99,16 +99,6 @@ static StkId index2stack (lua_State *L, int idx) {
9999
}
100100

101101

102-
/*
103-
** to be called by 'lua_checkstack' in protected mode, to grow stack
104-
** capturing memory errors
105-
*/
106-
static void growstack (lua_State *L, void *ud) {
107-
int size = *(int *)ud;
108-
luaD_growstack(L, size);
109-
}
110-
111-
112102
LUA_API int lua_checkstack (lua_State *L, int n) {
113103
int res;
114104
CallInfo *ci = L->ci;
@@ -121,7 +111,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
121111
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
122112
res = 0; /* no */
123113
else /* try to grow stack */
124-
res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK);
114+
res = luaD_growstack(L, n, 0);
125115
}
126116
if (res && ci->top < L->top + n)
127117
ci->top = L->top + n; /* adjust frame top */

ldo.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: ldo.c,v 2.176 2017/11/29 13:02:17 roberto Exp roberto $
2+
** $Id: ldo.c,v 2.177 2017/12/01 15:44:51 roberto Exp roberto $
33
** Stack and Call structure of Lua
44
** See Copyright Notice in lua.h
55
*/
@@ -156,17 +156,17 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
156156
** Stack reallocation
157157
** ===================================================================
158158
*/
159-
static void correctstack (lua_State *L, StkId oldstack) {
159+
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
160160
CallInfo *ci;
161161
UpVal *up;
162-
if (L->stack == oldstack)
162+
if (oldstack == newstack)
163163
return; /* stack address did not change */
164-
L->top = (L->top - oldstack) + L->stack;
164+
L->top = (L->top - oldstack) + newstack;
165165
for (up = L->openupval; up != NULL; up = up->u.open.next)
166-
up->v = s2v((uplevel(up) - oldstack) + L->stack);
166+
up->v = s2v((uplevel(up) - oldstack) + newstack);
167167
for (ci = L->ci; ci != NULL; ci = ci->previous) {
168-
ci->top = (ci->top - oldstack) + L->stack;
169-
ci->func = (ci->func - oldstack) + L->stack;
168+
ci->top = (ci->top - oldstack) + newstack;
169+
ci->func = (ci->func - oldstack) + newstack;
170170
if (isLua(ci))
171171
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
172172
}
@@ -177,36 +177,40 @@ static void correctstack (lua_State *L, StkId oldstack) {
177177
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
178178

179179

180-
void luaD_reallocstack (lua_State *L, int newsize) {
181-
StkId oldstack = L->stack;
180+
int luaD_reallocstack (lua_State *L, int newsize, int safe) {
182181
int lim = L->stacksize;
182+
StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue);
183183
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
184184
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
185-
luaM_reallocvector(L, L->stack, L->stacksize, newsize, StackValue);
185+
if (newstack == NULL) { /* reallocation failed? */
186+
if (safe) luaM_error(L);
187+
else return 0; /* no-safe mode: signal the error */
188+
}
186189
for (; lim < newsize; lim++)
187-
setnilvalue(s2v(L->stack + lim)); /* erase new segment */
190+
setnilvalue(s2v(newstack + lim)); /* erase new segment */
191+
correctstack(L, L->stack, newstack);
192+
L->stack = newstack;
188193
L->stacksize = newsize;
189194
L->stack_last = L->stack + newsize - EXTRA_STACK;
190-
correctstack(L, oldstack);
195+
return 1;
191196
}
192197

193198

194-
void luaD_growstack (lua_State *L, int n) {
199+
int luaD_growstack (lua_State *L, int n, int safe) {
195200
int size = L->stacksize;
201+
int newsize = 2 * size;
196202
if (size > LUAI_MAXSTACK) /* error after extra size? */
197203
luaD_throw(L, LUA_ERRERR);
198204
else {
199205
int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
200-
int newsize = 2 * size;
201206
if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
202207
if (newsize < needed) newsize = needed;
203208
if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
204-
luaD_reallocstack(L, ERRORSTACKSIZE);
209+
luaD_reallocstack(L, ERRORSTACKSIZE, 1);
205210
luaG_runerror(L, "stack overflow");
206211
}
207-
else
208-
luaD_reallocstack(L, newsize);
209-
}
212+
} /* else */
213+
return luaD_reallocstack(L, newsize, safe);
210214
}
211215

212216

@@ -234,7 +238,7 @@ void luaD_shrinkstack (lua_State *L) {
234238
good size is smaller than current size, shrink its stack */
235239
if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
236240
goodsize < L->stacksize)
237-
luaD_reallocstack(L, goodsize);
241+
luaD_reallocstack(L, goodsize, 0); /* ok if that fails */
238242
else /* don't change stack */
239243
condmovestack(L,{},{}); /* (change only for debugging) */
240244
}

ldo.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: ldo.h,v 2.35 2017/11/23 16:35:54 roberto Exp roberto $
2+
** $Id: ldo.h,v 2.36 2017/11/23 18:29:41 roberto Exp roberto $
33
** Stack and Call structure of Lua
44
** See Copyright Notice in lua.h
55
*/
@@ -22,7 +22,8 @@
2222
*/
2323
#define luaD_checkstackaux(L,n,pre,pos) \
2424
if (L->stack_last - L->top <= (n)) \
25-
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
25+
{ pre; luaD_growstack(L, n, 1); pos; } \
26+
else { condmovestack(L,pre,pos); }
2627

2728
/* In general, 'pre'/'pos' are empty (nothing to save) */
2829
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
@@ -55,8 +56,8 @@ LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
5556
ptrdiff_t oldtop, ptrdiff_t ef);
5657
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
5758
int nres);
58-
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
59-
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
59+
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int safe);
60+
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int safe);
6061
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
6162
LUAI_FUNC void luaD_inctop (lua_State *L);
6263

lgc.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: lgc.c,v 2.240 2017/11/30 15:37:16 roberto Exp roberto $
2+
** $Id: lgc.c,v 2.241 2017/12/01 17:38:49 roberto Exp roberto $
33
** Garbage Collector
44
** See Copyright Notice in lua.h
55
*/
@@ -816,18 +816,13 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) {
816816
*/
817817

818818
/*
819-
** If possible, shrink string table (protected from memory errors).
819+
** If possible, shrink string table.
820820
*/
821-
static void shrinkstrtable (lua_State *L, void *ud) {
822-
luaS_resize(L, *cast(int*, ud) / 2);
823-
}
824-
825-
826821
static void checkSizes (lua_State *L, global_State *g) {
827822
if (!g->gcemergency) {
828823
l_mem olddebt = g->GCdebt;
829824
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
830-
luaD_rawrunprotected(L, &shrinkstrtable, &g->strt.size);
825+
luaS_resize(L, g->strt.size / 2);
831826
g->GCestimate += g->GCdebt - olddebt; /* correct estimate */
832827
}
833828
}

lmem.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: lmem.c,v 1.92 2017/12/06 18:36:31 roberto Exp roberto $
2+
** $Id: lmem.c,v 1.93 2017/12/07 18:59:52 roberto Exp roberto $
33
** Interface to Memory Manager
44
** See Copyright Notice in lua.h
55
*/
@@ -69,9 +69,12 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
6969
if (size < MINSIZEARRAY)
7070
size = MINSIZEARRAY; /* minimum size */
7171
}
72+
lua_assert(nelems + 1 <= size && size <= limit);
7273
/* 'limit' ensures that multiplication will not overflow */
73-
newblock = luaM_realloc(L, block, cast(size_t, *psize) * size_elems,
74-
cast(size_t, size) * size_elems);
74+
newblock = luaM_realloc_(L, block, cast(size_t, *psize) * size_elems,
75+
cast(size_t, size) * size_elems);
76+
if (newblock == NULL)
77+
luaM_error(L);
7578
*psize = size; /* update only when everything else is OK */
7679
return newblock;
7780
}
@@ -115,28 +118,37 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
115118
/*
116119
** generic allocation routine.
117120
*/
118-
void *luaM_realloc (lua_State *L, void *block, size_t osize, size_t nsize) {
121+
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
119122
void *newblock;
120123
global_State *g = G(L);
121124
lua_assert((osize == 0) == (block == NULL));
122125
hardtest(L, osize, nsize);
123126
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
124127
if (newblock == NULL && nsize > 0) {
125-
lua_assert(nsize > osize); /* cannot fail when shrinking a block */
126-
if (g->version) { /* is state fully built? */
128+
/* Is state fully built? Not shrinking a block? */
129+
if (g->version && nsize > osize) {
127130
luaC_fullgc(L, 1); /* try to free some memory... */
128131
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
129132
}
130133
if (newblock == NULL)
131-
luaD_throw(L, LUA_ERRMEM);
134+
return NULL;
132135
}
133136
lua_assert((nsize == 0) == (newblock == NULL));
134137
g->GCdebt = (g->GCdebt + nsize) - osize;
135138
return newblock;
136139
}
137140

138141

139-
void *luaM_malloc (lua_State *L, size_t size, int tag) {
142+
void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
143+
size_t nsize) {
144+
void *newblock = luaM_realloc_(L, block, osize, nsize);
145+
if (newblock == NULL && nsize > 0) /* allocation failed? */
146+
luaM_error(L);
147+
return newblock;
148+
}
149+
150+
151+
void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
140152
hardtest(L, 0, size);
141153
if (size == 0)
142154
return NULL; /* that's all */
@@ -149,7 +161,7 @@ void *luaM_malloc (lua_State *L, size_t size, int tag) {
149161
newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */
150162
}
151163
if (newblock == NULL)
152-
luaD_throw(L, LUA_ERRMEM);
164+
luaM_error(L);
153165
}
154166
g->GCdebt += size;
155167
return newblock;

lmem.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: lmem.h,v 1.44 2017/12/06 18:36:31 roberto Exp roberto $
2+
** $Id: lmem.h,v 1.45 2017/12/07 18:59:52 roberto Exp roberto $
33
** Interface to Memory Manager
44
** See Copyright Notice in lua.h
55
*/
@@ -14,6 +14,9 @@
1414
#include "lua.h"
1515

1616

17+
#define luaM_error(L) luaD_throw(L, LUA_ERRMEM)
18+
19+
1720
/*
1821
** This macro tests whether it is safe to multiply 'n' by the size of
1922
** type 't' without overflows. Because 'e' is always constant, it avoids
@@ -45,42 +48,44 @@
4548
** Arrays of chars do not need any test
4649
*/
4750
#define luaM_reallocvchar(L,b,on,n) \
48-
cast(char *, luaM_realloc(L, (b), (on)*sizeof(char), (n)*sizeof(char)))
51+
cast(char *, luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char)))
4952

5053
#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s))
5154
#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b)))
5255
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
5356

54-
#define luaM_new(L,t) cast(t*, luaM_malloc(L, sizeof(t), 0))
55-
#define luaM_newvector(L,n,t) cast(t*, luaM_malloc(L, (n)*sizeof(t), 0))
57+
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
58+
#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0))
5659
#define luaM_newvectorchecked(L,n,t) \
5760
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
5861

59-
#define luaM_newobject(L,tag,s) luaM_malloc(L, (s), tag)
62+
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
6063

6164
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
6265
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
6366
luaM_limitN(limit,t),e)))
6467

6568
#define luaM_reallocvector(L, v,oldn,n,t) \
66-
((v)=cast(t *, luaM_realloc(L, v, cast(size_t, oldn) * sizeof(t), \
67-
cast(size_t, n) * sizeof(t))))
69+
(cast(t *, luaM_realloc_(L, v, cast(size_t, oldn) * sizeof(t), \
70+
cast(size_t, n) * sizeof(t))))
6871

6972
#define luaM_shrinkvector(L,v,size,fs,t) \
7073
((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t))))
7174

7275
LUAI_FUNC l_noret luaM_toobig (lua_State *L);
7376

7477
/* not to be called directly */
75-
LUAI_FUNC void *luaM_realloc (lua_State *L, void *block, size_t oldsize,
78+
LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
7679
size_t size);
80+
LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
81+
size_t size);
7782
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
7883
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
7984
int *size, int size_elem, int limit,
8085
const char *what);
8186
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
8287
int final_n, int size_elem);
83-
LUAI_FUNC void *luaM_malloc (lua_State *L, size_t size, int tag);
88+
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
8489

8590
#endif
8691

lstring.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
** $Id: lstring.c,v 2.58 2017/12/01 16:40:29 roberto Exp roberto $
2+
** $Id: lstring.c,v 2.59 2017/12/07 18:59:52 roberto Exp roberto $
33
** String table (keeps all strings handled by Lua)
44
** See Copyright Notice in lua.h
55
*/
@@ -70,12 +70,15 @@ unsigned int luaS_hashlongstr (TString *ts) {
7070

7171

7272
/*
73-
** Resizes the string table.
73+
** Resize the string table. If allocation fails, keep the current size.
74+
** (This can degrade performance, but any size should work correctly.)
7475
*/
7576
void luaS_resize (lua_State *L, int newsize) {
7677
int i;
7778
TString **newhash = luaM_newvector(L, newsize, TString *);
7879
stringtable *tb = &G(L)->strt;
80+
if (newhash == NULL) /* allocation failed? */
81+
return; /* leave hash as it is */
7982
for (i = 0; i < newsize; i++) /* initialize new hash array */
8083
newhash[i] = NULL;
8184
for (i = 0; i < tb->size; i++) { /* rehash all elements into new array */

0 commit comments

Comments
 (0)