diff options
-rw-r--r-- | ldo.c | 13 | ||||
-rw-r--r-- | lstate.c | 53 | ||||
-rw-r--r-- | lstate.h | 51 | ||||
-rw-r--r-- | testes/all.lua | 14 |
4 files changed, 80 insertions, 51 deletions
@@ -139,9 +139,8 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
139 | 139 | ||
140 | 140 | ||
141 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | 141 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { |
142 | l_uint32 oldnCcalls = L->nCcalls - L->nci; | 142 | l_uint32 oldnCcalls = L->nCcalls + L->nci; |
143 | struct lua_longjmp lj; | 143 | struct lua_longjmp lj; |
144 | lua_assert(L->nCcalls >= L->nci); | ||
145 | lj.status = LUA_OK; | 144 | lj.status = LUA_OK; |
146 | lj.previous = L->errorJmp; /* chain new error handler */ | 145 | lj.previous = L->errorJmp; /* chain new error handler */ |
147 | L->errorJmp = &lj; | 146 | L->errorJmp = &lj; |
@@ -149,7 +148,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
149 | (*f)(L, ud); | 148 | (*f)(L, ud); |
150 | ); | 149 | ); |
151 | L->errorJmp = lj.previous; /* restore old error handler */ | 150 | L->errorJmp = lj.previous; /* restore old error handler */ |
152 | L->nCcalls = oldnCcalls + L->nci; | 151 | L->nCcalls = oldnCcalls - L->nci; |
153 | return lj.status; | 152 | return lj.status; |
154 | } | 153 | } |
155 | 154 | ||
@@ -521,7 +520,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
521 | */ | 520 | */ |
522 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 521 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { |
523 | incXCcalls(L); | 522 | incXCcalls(L); |
524 | if (getCcalls(L) >= LUAI_MAXCSTACK) /* possible stack overflow? */ | 523 | if (getCcalls(L) <= CSTACKERR) /* possible stack overflow? */ |
525 | luaE_freeCI(L); | 524 | luaE_freeCI(L); |
526 | luaD_call(L, func, nResults); | 525 | luaD_call(L, func, nResults); |
527 | decXCcalls(L); | 526 | decXCcalls(L); |
@@ -672,10 +671,10 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
672 | else if (L->status != LUA_YIELD) /* ended with errors? */ | 671 | else if (L->status != LUA_YIELD) /* ended with errors? */ |
673 | return resume_error(L, "cannot resume dead coroutine", nargs); | 672 | return resume_error(L, "cannot resume dead coroutine", nargs); |
674 | if (from == NULL) | 673 | if (from == NULL) |
675 | L->nCcalls = 1; | 674 | L->nCcalls = LUAI_MAXCSTACK; |
676 | else /* correct 'nCcalls' for this thread */ | 675 | else /* correct 'nCcalls' for this thread */ |
677 | L->nCcalls = getCcalls(from) - from->nci + L->nci + CSTACKCF; | 676 | L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF; |
678 | if (L->nCcalls >= LUAI_MAXCSTACK) | 677 | if (L->nCcalls <= CSTACKERR) |
679 | return resume_error(L, "C stack overflow", nargs); | 678 | return resume_error(L, "C stack overflow", nargs); |
680 | luai_userstateresume(L, nargs); | 679 | luai_userstateresume(L, nargs); |
681 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 680 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
@@ -97,35 +97,34 @@ void luaE_setdebt (global_State *g, l_mem debt) { | |||
97 | 97 | ||
98 | 98 | ||
99 | /* | 99 | /* |
100 | ** Increment count of "C calls" and check for overflows. In case of | 100 | ** Decrement count of "C calls" and check for overflows. In case of |
101 | ** a stack overflow, check appropriate error ("regular" overflow or | 101 | ** a stack overflow, check appropriate error ("regular" overflow or |
102 | ** overflow while handling stack overflow). | 102 | ** overflow while handling stack overflow). If 'nCcalls' is smaller |
103 | ** If 'nCcalls' is larger than LUAI_MAXCSTACK but smaller than | 103 | ** than CSTACKERR but larger than CSTACKMARK, it means it has just |
104 | ** LUAI_MAXCSTACK + CSTACKCF (plus 2 to avoid by-one errors), it means | 104 | ** entered the "overflow zone", so the function raises an overflow |
105 | ** it has just entered the "overflow zone", so the function raises an | 105 | ** error. If 'nCcalls' is smaller than CSTACKMARK (which means it is |
106 | ** overflow error. | 106 | ** already handling an overflow) but larger than CSTACKERRMARK, does |
107 | ** If 'nCcalls' is larger than LUAI_MAXCSTACK + CSTACKCF + 2 | 107 | ** not report an error (to allow message handling to work). Otherwise, |
108 | ** (which means it is already handling an overflow) but smaller than | 108 | ** report a stack overflow while handling a stack overflow (probably |
109 | ** 9/8 of LUAI_MAXCSTACK, does not report an error (to allow message | 109 | ** caused by a repeating error in the message handling function). |
110 | ** handling to work). | ||
111 | ** Otherwise, report a stack overflow while handling a stack overflow | ||
112 | ** (probably caused by a repeating error in the message handling | ||
113 | ** function). | ||
114 | */ | 110 | */ |
111 | |||
115 | void luaE_enterCcall (lua_State *L) { | 112 | void luaE_enterCcall (lua_State *L) { |
116 | int ncalls = getCcalls(L); | 113 | int ncalls = getCcalls(L); |
117 | L->nCcalls++; | 114 | L->nCcalls--; |
118 | if (ncalls >= LUAI_MAXCSTACK) { /* possible overflow? */ | 115 | if (ncalls <= CSTACKERR) { /* possible overflow? */ |
119 | luaE_freeCI(L); /* release unused CIs */ | 116 | luaE_freeCI(L); /* release unused CIs */ |
120 | ncalls = getCcalls(L); /* update call count */ | 117 | ncalls = getCcalls(L); /* update call count */ |
121 | if (ncalls >= LUAI_MAXCSTACK) { /* still overflow? */ | 118 | if (ncalls <= CSTACKERR) { /* still overflow? */ |
122 | if (ncalls <= LUAI_MAXCSTACK + CSTACKCF + 2) { | 119 | if (ncalls <= CSTACKERRMARK) /* below error-handling zone? */ |
123 | /* no error before increments; raise the error now */ | ||
124 | L->nCcalls += (CSTACKCF + 4); /* avoid raising it again */ | ||
125 | luaG_runerror(L, "C stack overflow"); | ||
126 | } | ||
127 | else if (ncalls >= (LUAI_MAXCSTACK + (LUAI_MAXCSTACK >> 3))) | ||
128 | luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ | 120 | luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ |
121 | else if (ncalls >= CSTACKMARK) { | ||
122 | /* not in error-handling zone; raise the error now */ | ||
123 | L->nCcalls = (CSTACKMARK - 1); /* enter error-handling zone */ | ||
124 | luaG_runerror(L, "C stack overflow1"); | ||
125 | } | ||
126 | /* else stack is in the error-handling zone; | ||
127 | allow message handler to work */ | ||
129 | } | 128 | } |
130 | } | 129 | } |
131 | } | 130 | } |
@@ -153,13 +152,13 @@ void luaE_freeCI (lua_State *L) { | |||
153 | CallInfo *ci = L->ci; | 152 | CallInfo *ci = L->ci; |
154 | CallInfo *next = ci->next; | 153 | CallInfo *next = ci->next; |
155 | ci->next = NULL; | 154 | ci->next = NULL; |
156 | L->nCcalls -= L->nci; /* subtract removed elements from 'nCcalls' */ | 155 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ |
157 | while ((ci = next) != NULL) { | 156 | while ((ci = next) != NULL) { |
158 | next = ci->next; | 157 | next = ci->next; |
159 | luaM_free(L, ci); | 158 | luaM_free(L, ci); |
160 | L->nci--; | 159 | L->nci--; |
161 | } | 160 | } |
162 | L->nCcalls += L->nci; /* adjust result */ | 161 | L->nCcalls -= L->nci; /* adjust result */ |
163 | } | 162 | } |
164 | 163 | ||
165 | 164 | ||
@@ -169,7 +168,7 @@ void luaE_freeCI (lua_State *L) { | |||
169 | void luaE_shrinkCI (lua_State *L) { | 168 | void luaE_shrinkCI (lua_State *L) { |
170 | CallInfo *ci = L->ci; | 169 | CallInfo *ci = L->ci; |
171 | CallInfo *next2; /* next's next */ | 170 | CallInfo *next2; /* next's next */ |
172 | L->nCcalls -= L->nci; /* subtract removed elements from 'nCcalls' */ | 171 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ |
173 | /* while there are two nexts */ | 172 | /* while there are two nexts */ |
174 | while (ci->next != NULL && (next2 = ci->next->next) != NULL) { | 173 | while (ci->next != NULL && (next2 = ci->next->next) != NULL) { |
175 | luaM_free(L, ci->next); /* free next */ | 174 | luaM_free(L, ci->next); /* free next */ |
@@ -178,7 +177,7 @@ void luaE_shrinkCI (lua_State *L) { | |||
178 | next2->previous = ci; | 177 | next2->previous = ci; |
179 | ci = next2; /* keep next's next */ | 178 | ci = next2; /* keep next's next */ |
180 | } | 179 | } |
181 | L->nCcalls += L->nci; /* adjust result */ | 180 | L->nCcalls -= L->nci; /* adjust result */ |
182 | } | 181 | } |
183 | 182 | ||
184 | 183 | ||
@@ -264,7 +263,7 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
264 | L->stacksize = 0; | 263 | L->stacksize = 0; |
265 | L->twups = L; /* thread has no upvalues */ | 264 | L->twups = L; /* thread has no upvalues */ |
266 | L->errorJmp = NULL; | 265 | L->errorJmp = NULL; |
267 | L->nCcalls = 0; | 266 | L->nCcalls = LUAI_MAXCSTACK + CSTACKERR; |
268 | L->hook = NULL; | 267 | L->hook = NULL; |
269 | L->hookmask = 0; | 268 | L->hookmask = 0; |
270 | L->basehookcount = 0; | 269 | L->basehookcount = 0; |
@@ -64,28 +64,45 @@ | |||
64 | 64 | ||
65 | /* | 65 | /* |
66 | ** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of | 66 | ** About 'nCcalls': each thread in Lua (a lua_State) keeps a count of |
67 | ** how many "C calls" it can do in the C stack, to avoid C-stack overflow. | 67 | ** how many "C calls" it still can do in the C stack, to avoid C-stack |
68 | ** This count is very rough approximation; it considers only recursive | 68 | ** overflow. This count is very rough approximation; it considers only |
69 | ** functions inside the interpreter, as non-recursive calls can be | 69 | ** recursive functions inside the interpreter, as non-recursive calls |
70 | ** considered using a fixed (although unknown) amount of stack space. | 70 | ** can be considered using a fixed (although unknown) amount of stack |
71 | ** space. | ||
71 | ** | 72 | ** |
72 | ** The count itself has two parts: the lower part is the count itself; | 73 | ** The count has two parts: the lower part is the count itself; the |
73 | ** the higher part counts the number of non-yieldable calls in the stack. | 74 | ** higher part counts the number of non-yieldable calls in the stack. |
75 | ** (They are together so that we can change both with one instruction.) | ||
74 | ** | 76 | ** |
75 | ** Because calls to external C functions can use of unkown amount | 77 | ** Because calls to external C functions can use of unkown amount |
76 | ** of space (e.g., functions using an auxiliary buffer), calls | 78 | ** of space (e.g., functions using an auxiliary buffer), calls |
77 | ** to these functions add more than one to the count. | 79 | ** to these functions add more than one to the count (see CSTACKCF). |
78 | ** | 80 | ** |
79 | ** The proper count also includes the number of CallInfo structures | 81 | ** The proper count excludes the number of CallInfo structures allocated |
80 | ** allocated by Lua, as a kind of "potential" calls. So, when Lua | 82 | ** by Lua, as a kind of "potential" calls. So, when Lua calls a function |
81 | ** calls a function (and "consumes" one CallInfo), it needs neither to | 83 | ** (and "consumes" one CallInfo), it needs neither to decrement nor to |
82 | ** increment nor to check 'nCcalls', as its use of C stack is already | 84 | ** check 'nCcalls', as its use of C stack is already accounted for. |
83 | ** accounted for. | ||
84 | */ | 85 | */ |
85 | 86 | ||
86 | /* number of "C stack slots" used by an external C function */ | 87 | /* number of "C stack slots" used by an external C function */ |
87 | #define CSTACKCF 10 | 88 | #define CSTACKCF 10 |
88 | 89 | ||
90 | |||
91 | /* | ||
92 | ** The C-stack size is sliced in the following zones: | ||
93 | ** - larger than CSTACKERR: normal stack; | ||
94 | ** - [CSTACKMARK, CSTACKERR]: buffer zone to signal a stack overflow; | ||
95 | ** - [CSTACKCF, CSTACKERRMARK]: error-handling zone; | ||
96 | ** - below CSTACKERRMARK: buffer zone to signal overflow during overflow; | ||
97 | ** (Because the counter can be decremented CSTACKCF at once, we need | ||
98 | ** the so called "buffer zones", with at least that size, to properly | ||
99 | ** detect a change from one zone to the next.) | ||
100 | */ | ||
101 | #define CSTACKERR (8 * CSTACKCF) | ||
102 | #define CSTACKMARK (CSTACKERR - (CSTACKCF + 2)) | ||
103 | #define CSTACKERRMARK (CSTACKCF + 2) | ||
104 | |||
105 | |||
89 | /* true if this thread does not have non-yieldable calls in the stack */ | 106 | /* true if this thread does not have non-yieldable calls in the stack */ |
90 | #define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0) | 107 | #define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0) |
91 | 108 | ||
@@ -99,11 +116,11 @@ | |||
99 | /* Decrement the number of non-yieldable calls */ | 116 | /* Decrement the number of non-yieldable calls */ |
100 | #define decnny(L) ((L)->nCcalls -= 0x10000) | 117 | #define decnny(L) ((L)->nCcalls -= 0x10000) |
101 | 118 | ||
102 | /* Increment the number of non-yieldable calls and nCcalls */ | 119 | /* Increment the number of non-yieldable calls and decrement nCcalls */ |
103 | #define incXCcalls(L) ((L)->nCcalls += 0x10000 + CSTACKCF) | 120 | #define incXCcalls(L) ((L)->nCcalls += 0x10000 - CSTACKCF) |
104 | 121 | ||
105 | /* Decrement the number of non-yieldable calls and nCcalls */ | 122 | /* Decrement the number of non-yieldable calls and increment nCcalls */ |
106 | #define decXCcalls(L) ((L)->nCcalls -= 0x10000 + CSTACKCF) | 123 | #define decXCcalls(L) ((L)->nCcalls -= 0x10000 - CSTACKCF) |
107 | 124 | ||
108 | 125 | ||
109 | 126 | ||
@@ -336,7 +353,7 @@ LUAI_FUNC void luaE_enterCcall (lua_State *L); | |||
336 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); | 353 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); |
337 | 354 | ||
338 | 355 | ||
339 | #define luaE_exitCcall(L) ((L)->nCcalls--) | 356 | #define luaE_exitCcall(L) ((L)->nCcalls++) |
340 | 357 | ||
341 | #endif | 358 | #endif |
342 | 359 | ||
diff --git a/testes/all.lua b/testes/all.lua index 2e6fe038..72121e8d 100644 --- a/testes/all.lua +++ b/testes/all.lua | |||
@@ -95,6 +95,8 @@ local function F (m) | |||
95 | end | 95 | end |
96 | end | 96 | end |
97 | 97 | ||
98 | local Cstacklevel | ||
99 | |||
98 | local showmem | 100 | local showmem |
99 | if not T then | 101 | if not T then |
100 | local max = 0 | 102 | local max = 0 |
@@ -104,6 +106,7 @@ if not T then | |||
104 | print(format(" ---- total memory: %s, max memory: %s ----\n", | 106 | print(format(" ---- total memory: %s, max memory: %s ----\n", |
105 | F(m), F(max))) | 107 | F(m), F(max))) |
106 | end | 108 | end |
109 | Cstacklevel = function () return 0 end -- no info about stack level | ||
107 | else | 110 | else |
108 | showmem = function () | 111 | showmem = function () |
109 | T.checkmemory() | 112 | T.checkmemory() |
@@ -117,9 +120,16 @@ else | |||
117 | T.totalmem"string", T.totalmem"table", T.totalmem"function", | 120 | T.totalmem"string", T.totalmem"table", T.totalmem"function", |
118 | T.totalmem"userdata", T.totalmem"thread")) | 121 | T.totalmem"userdata", T.totalmem"thread")) |
119 | end | 122 | end |
123 | |||
124 | Cstacklevel = function () | ||
125 | local _, _, ncalls, nci = T.stacklevel() | ||
126 | return ncalls + nci -- number of free slots in the C stack | ||
127 | end | ||
120 | end | 128 | end |
121 | 129 | ||
122 | 130 | ||
131 | local Cstack = Cstacklevel() | ||
132 | |||
123 | -- | 133 | -- |
124 | -- redefine dofile to run files through dump/undump | 134 | -- redefine dofile to run files through dump/undump |
125 | -- | 135 | -- |
@@ -211,6 +221,10 @@ debug.sethook(function (a) assert(type(a) == 'string') end, "cr") | |||
211 | -- to survive outside block | 221 | -- to survive outside block |
212 | _G.showmem = showmem | 222 | _G.showmem = showmem |
213 | 223 | ||
224 | |||
225 | assert(Cstack == Cstacklevel(), | ||
226 | "should be at the same C-stack level it was when started the tests") | ||
227 | |||
214 | end --) | 228 | end --) |
215 | 229 | ||
216 | local _G, showmem, print, format, clock, time, difftime, | 230 | local _G, showmem, print, format, clock, time, difftime, |