diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-16 11:33:30 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-16 11:33:30 -0300 |
| commit | cd4de92762434e6ed0e6c207d56d365300396dd8 (patch) | |
| tree | 9bc91eb85506b89d7cba0b859e2defce86aed7fc | |
| parent | 6b45ccf4ed24dcfe437cf0159d6185119a2e8f95 (diff) | |
| download | lua-cd4de92762434e6ed0e6c207d56d365300396dd8.tar.gz lua-cd4de92762434e6ed0e6c207d56d365300396dd8.tar.bz2 lua-cd4de92762434e6ed0e6c207d56d365300396dd8.zip | |
Maximum stack size may not fit in unsigned short
Therefore, fields ftransfer/ntransfer in lua_Debug must have type
'int'. (Maximum stack size must fit in an 'int'.) Also, this commit
adds check that maximum stack size respects size_t for size in bytes.
| -rw-r--r-- | ldo.c | 43 | ||||
| -rw-r--r-- | lstate.h | 4 | ||||
| -rw-r--r-- | lua.h | 4 | ||||
| -rw-r--r-- | luaconf.h | 8 | ||||
| -rw-r--r-- | manual/manual.of | 15 |
5 files changed, 46 insertions, 28 deletions
| @@ -171,6 +171,24 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
| 171 | ** =================================================================== | 171 | ** =================================================================== |
| 172 | */ | 172 | */ |
| 173 | 173 | ||
| 174 | /* some stack space for error handling */ | ||
| 175 | #define STACKERRSPACE 200 | ||
| 176 | |||
| 177 | |||
| 178 | /* maximum stack size that respects size_t */ | ||
| 179 | #define MAXSTACK_BYSIZET ((MAX_SIZET / sizeof(StackValue)) - STACKERRSPACE) | ||
| 180 | |||
| 181 | /* | ||
| 182 | ** Minimum between LUAI_MAXSTACK and MAXSTACK_BYSIZET | ||
| 183 | ** (Maximum size for the stack must respect size_t.) | ||
| 184 | */ | ||
| 185 | #define MAXSTACK cast_int(LUAI_MAXSTACK < MAXSTACK_BYSIZET \ | ||
| 186 | ? LUAI_MAXSTACK : MAXSTACK_BYSIZET) | ||
| 187 | |||
| 188 | |||
| 189 | /* stack size with extra space for error handling */ | ||
| 190 | #define ERRORSTACKSIZE (MAXSTACK + STACKERRSPACE) | ||
| 191 | |||
| 174 | 192 | ||
| 175 | /* | 193 | /* |
| 176 | ** Change all pointers to the stack into offsets. | 194 | ** Change all pointers to the stack into offsets. |
| @@ -208,9 +226,6 @@ static void correctstack (lua_State *L) { | |||
| 208 | } | 226 | } |
| 209 | 227 | ||
| 210 | 228 | ||
| 211 | /* some space for error handling */ | ||
| 212 | #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) | ||
| 213 | |||
| 214 | /* | 229 | /* |
| 215 | ** Reallocate the stack to a new size, correcting all pointers into it. | 230 | ** Reallocate the stack to a new size, correcting all pointers into it. |
| 216 | ** In ISO C, any pointer use after the pointer has been deallocated is | 231 | ** In ISO C, any pointer use after the pointer has been deallocated is |
| @@ -227,7 +242,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
| 227 | int i; | 242 | int i; |
| 228 | StkId newstack; | 243 | StkId newstack; |
| 229 | int oldgcstop = G(L)->gcstopem; | 244 | int oldgcstop = G(L)->gcstopem; |
| 230 | lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); | 245 | lua_assert(newsize <= MAXSTACK || newsize == ERRORSTACKSIZE); |
| 231 | relstack(L); /* change pointers to offsets */ | 246 | relstack(L); /* change pointers to offsets */ |
| 232 | G(L)->gcstopem = 1; /* stop emergency collection */ | 247 | G(L)->gcstopem = 1; /* stop emergency collection */ |
| 233 | newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK, | 248 | newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK, |
| @@ -254,7 +269,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
| 254 | */ | 269 | */ |
| 255 | int luaD_growstack (lua_State *L, int n, int raiseerror) { | 270 | int luaD_growstack (lua_State *L, int n, int raiseerror) { |
| 256 | int size = stacksize(L); | 271 | int size = stacksize(L); |
| 257 | if (l_unlikely(size > LUAI_MAXSTACK)) { | 272 | if (l_unlikely(size > MAXSTACK)) { |
| 258 | /* if stack is larger than maximum, thread is already using the | 273 | /* if stack is larger than maximum, thread is already using the |
| 259 | extra space reserved for errors, that is, thread is handling | 274 | extra space reserved for errors, that is, thread is handling |
| 260 | a stack error; cannot grow further than that. */ | 275 | a stack error; cannot grow further than that. */ |
| @@ -263,14 +278,14 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { | |||
| 263 | luaD_throw(L, LUA_ERRERR); /* error inside message handler */ | 278 | luaD_throw(L, LUA_ERRERR); /* error inside message handler */ |
| 264 | return 0; /* if not 'raiseerror', just signal it */ | 279 | return 0; /* if not 'raiseerror', just signal it */ |
| 265 | } | 280 | } |
| 266 | else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */ | 281 | else if (n < MAXSTACK) { /* avoids arithmetic overflows */ |
| 267 | int newsize = 2 * size; /* tentative new size */ | 282 | int newsize = 2 * size; /* tentative new size */ |
| 268 | int needed = cast_int(L->top.p - L->stack.p) + n; | 283 | int needed = cast_int(L->top.p - L->stack.p) + n; |
| 269 | if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ | 284 | if (newsize > MAXSTACK) /* cannot cross the limit */ |
| 270 | newsize = LUAI_MAXSTACK; | 285 | newsize = MAXSTACK; |
| 271 | if (newsize < needed) /* but must respect what was asked for */ | 286 | if (newsize < needed) /* but must respect what was asked for */ |
| 272 | newsize = needed; | 287 | newsize = needed; |
| 273 | if (l_likely(newsize <= LUAI_MAXSTACK)) | 288 | if (l_likely(newsize <= MAXSTACK)) |
| 274 | return luaD_reallocstack(L, newsize, raiseerror); | 289 | return luaD_reallocstack(L, newsize, raiseerror); |
| 275 | } | 290 | } |
| 276 | /* else stack overflow */ | 291 | /* else stack overflow */ |
| @@ -306,17 +321,17 @@ static int stackinuse (lua_State *L) { | |||
| 306 | ** to twice the current use. (So, the final stack size is at most 2/3 the | 321 | ** to twice the current use. (So, the final stack size is at most 2/3 the |
| 307 | ** previous size, and half of its entries are empty.) | 322 | ** previous size, and half of its entries are empty.) |
| 308 | ** As a particular case, if stack was handling a stack overflow and now | 323 | ** As a particular case, if stack was handling a stack overflow and now |
| 309 | ** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than | 324 | ** it is not, 'max' (limited by MAXSTACK) will be smaller than |
| 310 | ** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack | 325 | ** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack |
| 311 | ** will be reduced to a "regular" size. | 326 | ** will be reduced to a "regular" size. |
| 312 | */ | 327 | */ |
| 313 | void luaD_shrinkstack (lua_State *L) { | 328 | void luaD_shrinkstack (lua_State *L) { |
| 314 | int inuse = stackinuse(L); | 329 | int inuse = stackinuse(L); |
| 315 | int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3; | 330 | int max = (inuse > MAXSTACK / 3) ? MAXSTACK : inuse * 3; |
| 316 | /* if thread is currently not handling a stack overflow and its | 331 | /* if thread is currently not handling a stack overflow and its |
| 317 | size is larger than maximum "reasonable" size, shrink it */ | 332 | size is larger than maximum "reasonable" size, shrink it */ |
| 318 | if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) { | 333 | if (inuse <= MAXSTACK && stacksize(L) > max) { |
| 319 | int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2; | 334 | int nsize = (inuse > MAXSTACK / 2) ? MAXSTACK : inuse * 2; |
| 320 | luaD_reallocstack(L, nsize, 0); /* ok if that fails */ | 335 | luaD_reallocstack(L, nsize, 0); /* ok if that fails */ |
| 321 | } | 336 | } |
| 322 | else /* don't change stack */ | 337 | else /* don't change stack */ |
| @@ -408,7 +423,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { | |||
| 408 | delta = ci->u.l.nextraargs + p->numparams + 1; | 423 | delta = ci->u.l.nextraargs + p->numparams + 1; |
| 409 | } | 424 | } |
| 410 | ci->func.p += delta; /* if vararg, back to virtual 'func' */ | 425 | ci->func.p += delta; /* if vararg, back to virtual 'func' */ |
| 411 | ftransfer = cast(unsigned short, firstres - ci->func.p); | 426 | ftransfer = cast_int(firstres - ci->func.p); |
| 412 | luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ | 427 | luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ |
| 413 | ci->func.p -= delta; | 428 | ci->func.p -= delta; |
| 414 | } | 429 | } |
| @@ -207,8 +207,8 @@ struct CallInfo { | |||
| 207 | int nyield; /* number of values yielded */ | 207 | int nyield; /* number of values yielded */ |
| 208 | int nres; /* number of values returned */ | 208 | int nres; /* number of values returned */ |
| 209 | struct { /* info about transferred values (for call/return hooks) */ | 209 | struct { /* info about transferred values (for call/return hooks) */ |
| 210 | unsigned short ftransfer; /* offset of first value transferred */ | 210 | int ftransfer; /* offset of first value transferred */ |
| 211 | unsigned short ntransfer; /* number of values transferred */ | 211 | int ntransfer; /* number of values transferred */ |
| 212 | } transferinfo; | 212 | } transferinfo; |
| 213 | } u2; | 213 | } u2; |
| 214 | short nresults; /* expected number of results from this function */ | 214 | short nresults; /* expected number of results from this function */ |
| @@ -503,8 +503,8 @@ struct lua_Debug { | |||
| 503 | unsigned char nparams;/* (u) number of parameters */ | 503 | unsigned char nparams;/* (u) number of parameters */ |
| 504 | char isvararg; /* (u) */ | 504 | char isvararg; /* (u) */ |
| 505 | char istailcall; /* (t) */ | 505 | char istailcall; /* (t) */ |
| 506 | unsigned short ftransfer; /* (r) index of first value transferred */ | 506 | int ftransfer; /* (r) index of first value transferred */ |
| 507 | unsigned short ntransfer; /* (r) number of transferred values */ | 507 | int ntransfer; /* (r) number of transferred values */ |
| 508 | char short_src[LUA_IDSIZE]; /* (S) */ | 508 | char short_src[LUA_IDSIZE]; /* (S) */ |
| 509 | /* private part */ | 509 | /* private part */ |
| 510 | struct CallInfo *i_ci; /* active function */ | 510 | struct CallInfo *i_ci; /* active function */ |
| @@ -750,13 +750,13 @@ | |||
| 750 | @@ LUAI_MAXSTACK limits the size of the Lua stack. | 750 | @@ LUAI_MAXSTACK limits the size of the Lua stack. |
| 751 | ** CHANGE it if you need a different limit. This limit is arbitrary; | 751 | ** CHANGE it if you need a different limit. This limit is arbitrary; |
| 752 | ** its only purpose is to stop Lua from consuming unlimited stack | 752 | ** its only purpose is to stop Lua from consuming unlimited stack |
| 753 | ** space (and to reserve some numbers for pseudo-indices). | 753 | ** space and to reserve some numbers for pseudo-indices. |
| 754 | ** (It must fit into max(size_t)/32 and max(int)/2.) | 754 | ** (It must fit into max(int)/2.) |
| 755 | */ | 755 | */ |
| 756 | #if LUAI_IS32INT | 756 | #if 1000000 < (INT_MAX / 2) |
| 757 | #define LUAI_MAXSTACK 1000000 | 757 | #define LUAI_MAXSTACK 1000000 |
| 758 | #else | 758 | #else |
| 759 | #define LUAI_MAXSTACK 15000 | 759 | #define LUAI_MAXSTACK (INT_MAX / 2u) |
| 760 | #endif | 760 | #endif |
| 761 | 761 | ||
| 762 | 762 | ||
diff --git a/manual/manual.of b/manual/manual.of index 56619afe..1069f644 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -4262,8 +4262,9 @@ you push the main function plus any arguments | |||
| 4262 | onto the empty stack of the thread. | 4262 | onto the empty stack of the thread. |
| 4263 | then you call @Lid{lua_resume}, | 4263 | then you call @Lid{lua_resume}, |
| 4264 | with @id{nargs} being the number of arguments. | 4264 | with @id{nargs} being the number of arguments. |
| 4265 | This call returns when the coroutine suspends or finishes its execution. | 4265 | The function returns when the coroutine suspends, |
| 4266 | When it returns, | 4266 | finishes its execution, or raises an unprotected error. |
| 4267 | When it returns without errors, | ||
| 4267 | @id{*nresults} is updated and | 4268 | @id{*nresults} is updated and |
| 4268 | the top of the stack contains | 4269 | the top of the stack contains |
| 4269 | the @id{*nresults} values passed to @Lid{lua_yield} | 4270 | the @id{*nresults} values passed to @Lid{lua_yield} |
| @@ -4274,9 +4275,11 @@ or returned by the body function. | |||
| 4274 | without errors, | 4275 | without errors, |
| 4275 | or an error code in case of errors @see{statuscodes}. | 4276 | or an error code in case of errors @see{statuscodes}. |
| 4276 | In case of errors, | 4277 | In case of errors, |
| 4277 | the error object is on the top of the stack. | 4278 | the error object is pushed on the top of the stack. |
| 4279 | (In that case, @id{nresults} is not updated, | ||
| 4280 | as its value would have to be 1 for the sole error object.) | ||
| 4278 | 4281 | ||
| 4279 | To resume a coroutine, | 4282 | To resume a suspended coroutine, |
| 4280 | you remove the @id{*nresults} yielded values from its stack, | 4283 | you remove the @id{*nresults} yielded values from its stack, |
| 4281 | push the values to be passed as results from @id{yield}, | 4284 | push the values to be passed as results from @id{yield}, |
| 4282 | and then call @Lid{lua_resume}. | 4285 | and then call @Lid{lua_resume}. |
| @@ -4822,8 +4825,8 @@ typedef struct lua_Debug { | |||
| 4822 | unsigned char nparams; /* (u) number of parameters */ | 4825 | unsigned char nparams; /* (u) number of parameters */ |
| 4823 | char isvararg; /* (u) */ | 4826 | char isvararg; /* (u) */ |
| 4824 | char istailcall; /* (t) */ | 4827 | char istailcall; /* (t) */ |
| 4825 | unsigned short ftransfer; /* (r) index of first value transferred */ | 4828 | int ftransfer; /* (r) index of first value transferred */ |
| 4826 | unsigned short ntransfer; /* (r) number of transferred values */ | 4829 | int ntransfer; /* (r) number of transferred values */ |
| 4827 | char short_src[LUA_IDSIZE]; /* (S) */ | 4830 | char short_src[LUA_IDSIZE]; /* (S) */ |
| 4828 | /* private part */ | 4831 | /* private part */ |
| 4829 | @rep{other fields} | 4832 | @rep{other fields} |
