diff options
| author | Roberto I <roberto@inf.puc-rio.br> | 2025-12-27 16:22:13 -0300 |
|---|---|---|
| committer | Roberto I <roberto@inf.puc-rio.br> | 2025-12-27 16:22:13 -0300 |
| commit | 632a71b24d8661228a726deb5e1698e9638f96d8 (patch) | |
| tree | 505f6df678b0d29f6924a27f4b2e285993089b5b | |
| parent | 578ae5745cecee56d48795cd4ae1eaf13618715c (diff) | |
| download | lua-632a71b24d8661228a726deb5e1698e9638f96d8.tar.gz lua-632a71b24d8661228a726deb5e1698e9638f96d8.tar.bz2 lua-632a71b24d8661228a726deb5e1698e9638f96d8.zip | |
BUG: Arithmetic overflow in 'collectgarbage"step"'
The computation of a new debt could overflow when we give a too large
step to 'collectgarbage"step"' and the current debt was already
negative. This is only an issue if your platform cares for it or if you
compile Lua with an option like '-fsanitize=undefined'.
| -rw-r--r-- | lapi.c | 9 |
1 files changed, 7 insertions, 2 deletions
| @@ -1201,11 +1201,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
| 1201 | case LUA_GCSTEP: { | 1201 | case LUA_GCSTEP: { |
| 1202 | lu_byte oldstp = g->gcstp; | 1202 | lu_byte oldstp = g->gcstp; |
| 1203 | l_mem n = cast(l_mem, va_arg(argp, size_t)); | 1203 | l_mem n = cast(l_mem, va_arg(argp, size_t)); |
| 1204 | l_mem newdebt; | ||
| 1204 | int work = 0; /* true if GC did some work */ | 1205 | int work = 0; /* true if GC did some work */ |
| 1205 | g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ | 1206 | g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ |
| 1206 | if (n <= 0) | 1207 | if (n <= 0) |
| 1207 | n = g->GCdebt; /* force to run one basic step */ | 1208 | newdebt = 0; /* force to run one basic step */ |
| 1208 | luaE_setdebt(g, g->GCdebt - n); | 1209 | else if (g->GCdebt >= n - MAX_LMEM) /* no overflow? */ |
| 1210 | newdebt = g->GCdebt - n; | ||
| 1211 | else /* overflow */ | ||
| 1212 | newdebt = -MAX_LMEM; /* set debt to miminum value */ | ||
| 1213 | luaE_setdebt(g, newdebt); | ||
| 1209 | luaC_condGC(L, (void)0, work = 1); | 1214 | luaC_condGC(L, (void)0, work = 1); |
| 1210 | if (work && g->gcstate == GCSpause) /* end of cycle? */ | 1215 | if (work && g->gcstate == GCSpause) /* end of cycle? */ |
| 1211 | res = 1; /* signal it */ | 1216 | res = 1; /* signal it */ |
