aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-12-08 15:28:25 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-12-08 15:28:25 -0200
commite663a24ab03a54fa221c20a793812e5c5ffdf94f (patch)
tree8fbd40f779f0eed29d46f26c07e1234fd5df8bae
parent40f823ec907fd725617e37199199b3ed424bd88c (diff)
downloadlua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.gz
lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.tar.bz2
lua-e663a24ab03a54fa221c20a793812e5c5ffdf94f.zip
more freedom in handling memory-allocation errors (not all allocations
automatically raise an error), which allows fixing a bug when resizing a table.
-rw-r--r--lapi.c14
-rw-r--r--ldo.c42
-rw-r--r--ldo.h9
-rw-r--r--lgc.c11
-rw-r--r--lmem.c30
-rw-r--r--lmem.h23
-rw-r--r--lstring.c7
-rw-r--r--ltable.c95
8 files changed, 136 insertions, 95 deletions
diff --git a/lapi.c b/lapi.c
index 3098cb9c..d6aaf8a8 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
1/* 1/*
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 $
3** Lua API 3** Lua API
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -99,16 +99,6 @@ static StkId index2stack (lua_State *L, int idx) {
99} 99}
100 100
101 101
102/*
103** to be called by 'lua_checkstack' in protected mode, to grow stack
104** capturing memory errors
105*/
106static void growstack (lua_State *L, void *ud) {
107 int size = *(int *)ud;
108 luaD_growstack(L, size);
109}
110
111
112LUA_API int lua_checkstack (lua_State *L, int n) { 102LUA_API int lua_checkstack (lua_State *L, int n) {
113 int res; 103 int res;
114 CallInfo *ci = L->ci; 104 CallInfo *ci = L->ci;
@@ -121,7 +111,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
121 if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ 111 if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
122 res = 0; /* no */ 112 res = 0; /* no */
123 else /* try to grow stack */ 113 else /* try to grow stack */
124 res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); 114 res = luaD_growstack(L, n, 0);
125 } 115 }
126 if (res && ci->top < L->top + n) 116 if (res && ci->top < L->top + n)
127 ci->top = L->top + n; /* adjust frame top */ 117 ci->top = L->top + n; /* adjust frame top */
diff --git a/ldo.c b/ldo.c
index fe1fcb25..136aef55 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
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 $
3** Stack and Call structure of Lua 3** Stack and Call structure of Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -156,17 +156,17 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
156** Stack reallocation 156** Stack reallocation
157** =================================================================== 157** ===================================================================
158*/ 158*/
159static void correctstack (lua_State *L, StkId oldstack) { 159static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
160 CallInfo *ci; 160 CallInfo *ci;
161 UpVal *up; 161 UpVal *up;
162 if (L->stack == oldstack) 162 if (oldstack == newstack)
163 return; /* stack address did not change */ 163 return; /* stack address did not change */
164 L->top = (L->top - oldstack) + L->stack; 164 L->top = (L->top - oldstack) + newstack;
165 for (up = L->openupval; up != NULL; up = up->u.open.next) 165 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);
167 for (ci = L->ci; ci != NULL; ci = ci->previous) { 167 for (ci = L->ci; ci != NULL; ci = ci->previous) {
168 ci->top = (ci->top - oldstack) + L->stack; 168 ci->top = (ci->top - oldstack) + newstack;
169 ci->func = (ci->func - oldstack) + L->stack; 169 ci->func = (ci->func - oldstack) + newstack;
170 if (isLua(ci)) 170 if (isLua(ci))
171 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ 171 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
172 } 172 }
@@ -177,36 +177,40 @@ static void correctstack (lua_State *L, StkId oldstack) {
177#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) 177#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
178 178
179 179
180void luaD_reallocstack (lua_State *L, int newsize) { 180int luaD_reallocstack (lua_State *L, int newsize, int safe) {
181 StkId oldstack = L->stack;
182 int lim = L->stacksize; 181 int lim = L->stacksize;
182 StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue);
183 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); 183 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
184 lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); 184 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 }
186 for (; lim < newsize; lim++) 189 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;
188 L->stacksize = newsize; 193 L->stacksize = newsize;
189 L->stack_last = L->stack + newsize - EXTRA_STACK; 194 L->stack_last = L->stack + newsize - EXTRA_STACK;
190 correctstack(L, oldstack); 195 return 1;
191} 196}
192 197
193 198
194void luaD_growstack (lua_State *L, int n) { 199int luaD_growstack (lua_State *L, int n, int safe) {
195 int size = L->stacksize; 200 int size = L->stacksize;
201 int newsize = 2 * size;
196 if (size > LUAI_MAXSTACK) /* error after extra size? */ 202 if (size > LUAI_MAXSTACK) /* error after extra size? */
197 luaD_throw(L, LUA_ERRERR); 203 luaD_throw(L, LUA_ERRERR);
198 else { 204 else {
199 int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; 205 int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
200 int newsize = 2 * size;
201 if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; 206 if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
202 if (newsize < needed) newsize = needed; 207 if (newsize < needed) newsize = needed;
203 if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ 208 if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
204 luaD_reallocstack(L, ERRORSTACKSIZE); 209 luaD_reallocstack(L, ERRORSTACKSIZE, 1);
205 luaG_runerror(L, "stack overflow"); 210 luaG_runerror(L, "stack overflow");
206 } 211 }
207 else 212 } /* else */
208 luaD_reallocstack(L, newsize); 213 return luaD_reallocstack(L, newsize, safe);
209 }
210} 214}
211 215
212 216
@@ -234,7 +238,7 @@ void luaD_shrinkstack (lua_State *L) {
234 good size is smaller than current size, shrink its stack */ 238 good size is smaller than current size, shrink its stack */
235 if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && 239 if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
236 goodsize < L->stacksize) 240 goodsize < L->stacksize)
237 luaD_reallocstack(L, goodsize); 241 luaD_reallocstack(L, goodsize, 0); /* ok if that fails */
238 else /* don't change stack */ 242 else /* don't change stack */
239 condmovestack(L,{},{}); /* (change only for debugging) */ 243 condmovestack(L,{},{}); /* (change only for debugging) */
240} 244}
diff --git a/ldo.h b/ldo.h
index a9b46cdf..388f6c3e 100644
--- a/ldo.h
+++ b/ldo.h
@@ -1,5 +1,5 @@
1/* 1/*
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 $
3** Stack and Call structure of Lua 3** Stack and Call structure of Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -22,7 +22,8 @@
22*/ 22*/
23#define luaD_checkstackaux(L,n,pre,pos) \ 23#define luaD_checkstackaux(L,n,pre,pos) \
24 if (L->stack_last - L->top <= (n)) \ 24 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); }
26 27
27/* In general, 'pre'/'pos' are empty (nothing to save) */ 28/* In general, 'pre'/'pos' are empty (nothing to save) */
28#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) 29#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,
55 ptrdiff_t oldtop, ptrdiff_t ef); 56 ptrdiff_t oldtop, ptrdiff_t ef);
56LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, 57LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
57 int nres); 58 int nres);
58LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); 59LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int safe);
59LUAI_FUNC void luaD_growstack (lua_State *L, int n); 60LUAI_FUNC int luaD_growstack (lua_State *L, int n, int safe);
60LUAI_FUNC void luaD_shrinkstack (lua_State *L); 61LUAI_FUNC void luaD_shrinkstack (lua_State *L);
61LUAI_FUNC void luaD_inctop (lua_State *L); 62LUAI_FUNC void luaD_inctop (lua_State *L);
62 63
diff --git a/lgc.c b/lgc.c
index f893e122..8d28d3bf 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
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 $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -816,18 +816,13 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) {
816*/ 816*/
817 817
818/* 818/*
819** If possible, shrink string table (protected from memory errors). 819** If possible, shrink string table.
820*/ 820*/
821static void shrinkstrtable (lua_State *L, void *ud) {
822 luaS_resize(L, *cast(int*, ud) / 2);
823}
824
825
826static void checkSizes (lua_State *L, global_State *g) { 821static void checkSizes (lua_State *L, global_State *g) {
827 if (!g->gcemergency) { 822 if (!g->gcemergency) {
828 l_mem olddebt = g->GCdebt; 823 l_mem olddebt = g->GCdebt;
829 if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ 824 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);
831 g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ 826 g->GCestimate += g->GCdebt - olddebt; /* correct estimate */
832 } 827 }
833} 828}
diff --git a/lmem.c b/lmem.c
index 23dc14d6..afacbb9f 100644
--- a/lmem.c
+++ b/lmem.c
@@ -1,5 +1,5 @@
1/* 1/*
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 $
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*/
@@ -69,9 +69,12 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
69 if (size < MINSIZEARRAY) 69 if (size < MINSIZEARRAY)
70 size = MINSIZEARRAY; /* minimum size */ 70 size = MINSIZEARRAY; /* minimum size */
71 } 71 }
72 lua_assert(nelems + 1 <= size && size <= limit);
72 /* 'limit' ensures that multiplication will not overflow */ 73 /* 'limit' ensures that multiplication will not overflow */
73 newblock = luaM_realloc(L, block, cast(size_t, *psize) * size_elems, 74 newblock = luaM_realloc_(L, block, cast(size_t, *psize) * size_elems,
74 cast(size_t, size) * size_elems); 75 cast(size_t, size) * size_elems);
76 if (newblock == NULL)
77 luaM_error(L);
75 *psize = size; /* update only when everything else is OK */ 78 *psize = size; /* update only when everything else is OK */
76 return newblock; 79 return newblock;
77} 80}
@@ -115,20 +118,20 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
115/* 118/*
116** generic allocation routine. 119** generic allocation routine.
117*/ 120*/
118void *luaM_realloc (lua_State *L, void *block, size_t osize, size_t nsize) { 121void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
119 void *newblock; 122 void *newblock;
120 global_State *g = G(L); 123 global_State *g = G(L);
121 lua_assert((osize == 0) == (block == NULL)); 124 lua_assert((osize == 0) == (block == NULL));
122 hardtest(L, osize, nsize); 125 hardtest(L, osize, nsize);
123 newblock = (*g->frealloc)(g->ud, block, osize, nsize); 126 newblock = (*g->frealloc)(g->ud, block, osize, nsize);
124 if (newblock == NULL && nsize > 0) { 127 if (newblock == NULL && nsize > 0) {
125 lua_assert(nsize > osize); /* cannot fail when shrinking a block */ 128 /* Is state fully built? Not shrinking a block? */
126 if (g->version) { /* is state fully built? */ 129 if (g->version && nsize > osize) {
127 luaC_fullgc(L, 1); /* try to free some memory... */ 130 luaC_fullgc(L, 1); /* try to free some memory... */
128 newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ 131 newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
129 } 132 }
130 if (newblock == NULL) 133 if (newblock == NULL)
131 luaD_throw(L, LUA_ERRMEM); 134 return NULL;
132 } 135 }
133 lua_assert((nsize == 0) == (newblock == NULL)); 136 lua_assert((nsize == 0) == (newblock == NULL));
134 g->GCdebt = (g->GCdebt + nsize) - osize; 137 g->GCdebt = (g->GCdebt + nsize) - osize;
@@ -136,7 +139,16 @@ void *luaM_realloc (lua_State *L, void *block, size_t osize, size_t nsize) {
136} 139}
137 140
138 141
139void *luaM_malloc (lua_State *L, size_t size, int tag) { 142void *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
151void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
140 hardtest(L, 0, size); 152 hardtest(L, 0, size);
141 if (size == 0) 153 if (size == 0)
142 return NULL; /* that's all */ 154 return NULL; /* that's all */
@@ -149,7 +161,7 @@ void *luaM_malloc (lua_State *L, size_t size, int tag) {
149 newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */ 161 newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */
150 } 162 }
151 if (newblock == NULL) 163 if (newblock == NULL)
152 luaD_throw(L, LUA_ERRMEM); 164 luaM_error(L);
153 } 165 }
154 g->GCdebt += size; 166 g->GCdebt += size;
155 return newblock; 167 return newblock;
diff --git a/lmem.h b/lmem.h
index 3c828789..e98aabdb 100644
--- a/lmem.h
+++ b/lmem.h
@@ -1,5 +1,5 @@
1/* 1/*
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 $
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*/
@@ -14,6 +14,9 @@
14#include "lua.h" 14#include "lua.h"
15 15
16 16
17#define luaM_error(L) luaD_throw(L, LUA_ERRMEM)
18
19
17/* 20/*
18** This macro tests whether it is safe to multiply 'n' by the size of 21** This macro tests whether it is safe to multiply 'n' by the size of
19** type 't' without overflows. Because 'e' is always constant, it avoids 22** type 't' without overflows. Because 'e' is always constant, it avoids
@@ -45,26 +48,26 @@
45** Arrays of chars do not need any test 48** Arrays of chars do not need any test
46*/ 49*/
47#define luaM_reallocvchar(L,b,on,n) \ 50#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)))
49 52
50#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) 53#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s))
51#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) 54#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b)))
52#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) 55#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
53 56
54#define luaM_new(L,t) cast(t*, luaM_malloc(L, sizeof(t), 0)) 57#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)) 58#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0))
56#define luaM_newvectorchecked(L,n,t) \ 59#define luaM_newvectorchecked(L,n,t) \
57 (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) 60 (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
58 61
59#define luaM_newobject(L,tag,s) luaM_malloc(L, (s), tag) 62#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
60 63
61#define luaM_growvector(L,v,nelems,size,t,limit,e) \ 64#define luaM_growvector(L,v,nelems,size,t,limit,e) \
62 ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ 65 ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
63 luaM_limitN(limit,t),e))) 66 luaM_limitN(limit,t),e)))
64 67
65#define luaM_reallocvector(L, v,oldn,n,t) \ 68#define luaM_reallocvector(L, v,oldn,n,t) \
66 ((v)=cast(t *, luaM_realloc(L, v, cast(size_t, oldn) * sizeof(t), \ 69 (cast(t *, luaM_realloc_(L, v, cast(size_t, oldn) * sizeof(t), \
67 cast(size_t, n) * sizeof(t)))) 70 cast(size_t, n) * sizeof(t))))
68 71
69#define luaM_shrinkvector(L,v,size,fs,t) \ 72#define luaM_shrinkvector(L,v,size,fs,t) \
70 ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) 73 ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t))))
@@ -72,15 +75,17 @@
72LUAI_FUNC l_noret luaM_toobig (lua_State *L); 75LUAI_FUNC l_noret luaM_toobig (lua_State *L);
73 76
74/* not to be called directly */ 77/* not to be called directly */
75LUAI_FUNC void *luaM_realloc (lua_State *L, void *block, size_t oldsize, 78LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
76 size_t size); 79 size_t size);
80LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
81 size_t size);
77LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); 82LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
78LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, 83LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
79 int *size, int size_elem, int limit, 84 int *size, int size_elem, int limit,
80 const char *what); 85 const char *what);
81LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, 86LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
82 int final_n, int size_elem); 87 int final_n, int size_elem);
83LUAI_FUNC void *luaM_malloc (lua_State *L, size_t size, int tag); 88LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
84 89
85#endif 90#endif
86 91
diff --git a/lstring.c b/lstring.c
index 1b3f53e1..1675b87a 100644
--- a/lstring.c
+++ b/lstring.c
@@ -1,5 +1,5 @@
1/* 1/*
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 $
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*/
@@ -70,12 +70,15 @@ unsigned int luaS_hashlongstr (TString *ts) {
70 70
71 71
72/* 72/*
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.)
74*/ 75*/
75void luaS_resize (lua_State *L, int newsize) { 76void luaS_resize (lua_State *L, int newsize) {
76 int i; 77 int i;
77 TString **newhash = luaM_newvector(L, newsize, TString *); 78 TString **newhash = luaM_newvector(L, newsize, TString *);
78 stringtable *tb = &G(L)->strt; 79 stringtable *tb = &G(L)->strt;
80 if (newhash == NULL) /* allocation failed? */
81 return; /* leave hash as it is */
79 for (i = 0; i < newsize; i++) /* initialize new hash array */ 82 for (i = 0; i < newsize; i++) /* initialize new hash array */
80 newhash[i] = NULL; 83 newhash[i] = NULL;
81 for (i = 0; i < tb->size; i++) { /* rehash all elements into new array */ 84 for (i = 0; i < tb->size; i++) { /* rehash all elements into new array */
diff --git a/ltable.c b/ltable.c
index d1345009..85101a8a 100644
--- a/ltable.c
+++ b/ltable.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltable.c,v 2.127 2017/11/23 19:29:04 roberto Exp roberto $ 2** $Id: ltable.c,v 2.128 2017/12/07 18:59:52 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*/
@@ -357,15 +357,6 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
357} 357}
358 358
359 359
360static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
361 unsigned int i;
362 luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
363 for (i=t->sizearray; i<size; i++)
364 setnilvalue(&t->array[i]);
365 t->sizearray = size;
366}
367
368
369/* 360/*
370** Creates an array for the hash part of a table with the given 361** Creates an array for the hash part of a table with the given
371** size, or reuses the dummy node if size is zero. 362** size, or reuses the dummy node if size is zero.
@@ -398,39 +389,79 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
398} 389}
399 390
400 391
401void luaH_resize (lua_State *L, Table *t, unsigned int nasize, 392/*
393** (Re)insert all elements from list 'nodes' into table 't'.
394*/
395static void reinsert(lua_State *L, Node *nodes, int nsize, Table *t) {
396 int j;
397 for (j = nsize - 1; j >= 0; j--) {
398 Node *old = nodes + j;
399 if (!ttisnil(gval(old))) {
400 /* doesn't need barrier/invalidate cache, as entry was
401 already present in the table */
402 TValue k;
403 getnodekey(L, &k, old);
404 setobjt2t(L, luaH_set(L, t, &k), gval(old));
405 }
406 }
407}
408
409
410/*
411** Resize table 't' for the new given sizes. Both allocations
412** (for the hash part and for the array part) can fail, which
413** creates some subtleties. If the first allocation, for the hash
414** part, fails, an error is raised and that is it. Otherwise,
415** copy the elements in the shrinking part of the array (if it
416** is shrinking) into the new hash. Then it reallocates the array part.
417** If that fails, it frees the new hash part and restores the old hash
418** part (to restore the original state of the table), and then raises
419** the allocation error. Otherwise, initialize the new part of the
420** array (if any) with nils and reinsert the elements in the old
421** hash back into the new parts of the table.
422*/
423void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
402 unsigned int nhsize) { 424 unsigned int nhsize) {
403 unsigned int i; 425 unsigned int i;
404 int j; 426 Node *oldnode = t->node; /* save old hash ... */
405 unsigned int oldasize = t->sizearray; 427 Node *oldlastfree = t->lastfree;
428 int oldlsizenode = t->lsizenode;
406 int oldhsize = allocsizenode(t); 429 int oldhsize = allocsizenode(t);
407 Node *nold = t->node; /* save old hash ... */ 430 unsigned int oldasize = t->sizearray;
408 if (nasize > oldasize) /* array part must grow? */ 431 TValue *newarray;
409 setarrayvector(L, t, nasize);
410 /* create new hash part with appropriate size */ 432 /* create new hash part with appropriate size */
411 setnodevector(L, t, nhsize); 433 setnodevector(L, t, nhsize);
412 if (nasize < oldasize) { /* array part must shrink? */ 434 if (newasize < oldasize) { /* will array shrink? */
413 t->sizearray = nasize; 435 /* re-insert into the hash the elements from vanishing slice */
414 /* re-insert elements from vanishing slice */ 436 t->sizearray = newasize; /* pretend array has new size */
415 for (i=nasize; i<oldasize; i++) { 437 for (i = newasize; i < oldasize; i++) {
416 if (!ttisnil(&t->array[i])) 438 if (!ttisnil(&t->array[i]))
417 luaH_setint(L, t, i + 1, &t->array[i]); 439 luaH_setint(L, t, i + 1, &t->array[i]);
418 } 440 }
419 /* shrink array */ 441 t->sizearray = oldasize; /* restore current size */
420 luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
421 } 442 }
422 /* re-insert elements from hash part */ 443 /* allocate new array */
423 for (j = oldhsize - 1; j >= 0; j--) { 444 newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
424 Node *old = nold + j; 445 if (newarray == NULL && newasize > 0) { /* allocation failed? */
425 if (!ttisnil(gval(old))) { 446 if (nhsize > 0) /* not the dummy node? */
426 /* doesn't need barrier/invalidate cache, as entry was 447 luaM_freearray(L, t->node, allocsizenode(t)); /* release new hash part */
427 already present in the table */ 448 t->node = oldnode; /* restore original hash part */
428 TValue k; getnodekey(L, &k, old); 449 t->lastfree = oldlastfree;
429 setobjt2t(L, luaH_set(L, t, &k), gval(old)); 450 t->lsizenode = oldlsizenode;
430 } 451 lua_assert(!isdummy(t) == (t->node != dummynode));
452 luaM_error(L); /* error with array unchanged */
431 } 453 }
454 /* allocation ok; initialize new part of the array */
455 t->array = newarray;
456 t->sizearray = newasize;
457 for (i = oldasize; i < newasize; i++)
458 setnilvalue(&t->array[i]);
459 /* re-insert elements from old hash part into new parts */
460 reinsert(L, oldnode, oldhsize, t);
461 /* free old hash */
432 if (oldhsize > 0) /* not the dummy node? */ 462 if (oldhsize > 0) /* not the dummy node? */
433 luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ 463 luaM_freearray(L, oldnode, cast(size_t, oldhsize));
464 lua_assert(!isdummy(t) == (t->node != dummynode));
434} 465}
435 466
436 467