summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lua/src/lmem.c
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-03-07 01:39:42 +1100
committer Vas Crabb <vas@vastheman.com>2023-03-07 01:39:42 +1100
commitb5475eb38b8b79a13a0a9e8a6cb68755b84f0c7b (patch)
tree005b70ffe81cab56d55873ac6ee68725e5ba9d36 /3rdparty/lua/src/lmem.c
parent2102c32d2f3f94e69e3baf60294be3c04ca8b09f (diff)
Various updates, mostly around Lua:
Compile Lua as C++. When Lua is compiled as C, it uses setjmp/longjmp for error handling, resulting in failure to unwind intermediate stack frames. Trying to ensure no objects with non-trivial destructors are in scope when raising a Lua error is error-prone. In particular, converting an exception to a Lua error becomes convoluted, and raising a Lua error from a constructor is effectively impossible. Updated Lua to 5.4.4 - this includes a brand-new garbage collector implementation with better performance. The main thing removed is the deprecated bitlib. Updated sol2 to version 3.3.0 - this adds support for Lua 5.4 and fixes a number of issues, including not correctly handling errors when Lua is built as C++. Updated LuaFileSystem to version 1.8.0 - this adds support for symbolic links on Windows, as well as Lua 5.4 compatibility. Updated LuaSQLite3 to version 0.9.5 - this fixes issues in multi-threaded environments, as well as Lua 5.4 compatibility. Fixed double-free after attempting to construct a debugger expression from Lua with an invalid string, and exposed expression error to Lua in a better way. Added warning level print function to Lua. Fixed saving cheats with shift operators in expressions, although this code isn't actually used as there's no cheat editor.
Diffstat (limited to '3rdparty/lua/src/lmem.c')
-rw-r--r--3rdparty/lua/src/lmem.c177
1 files changed, 139 insertions, 38 deletions
diff --git a/3rdparty/lua/src/lmem.c b/3rdparty/lua/src/lmem.c
index 0a0476cc773..9029d588c12 100644
--- a/3rdparty/lua/src/lmem.c
+++ b/3rdparty/lua/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
+** $Id: lmem.c $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -22,79 +22,180 @@
#include "lstate.h"
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail whenever not building initial state.
+** (This fail will trigger 'tryagain' and a full GC cycle at every
+** allocation.)
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+ if (completestate(g) && ns > 0) /* frees never fail */
+ return NULL; /* fail */
+ else /* normal allocation */
+ return (*g->frealloc)(g->ud, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
+#endif
+
+
+
+
/*
** About the realloc function:
-** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
+** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
** ('osize' is the old size, 'nsize' is the new size)
**
-** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no
-** matter 'x').
+** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL.
+** Particularly, frealloc(ud, NULL, 0, 0) does nothing,
+** which is equivalent to free(NULL) in ISO C.
**
-** * frealloc(ud, p, x, 0) frees the block 'p'
-** (in this specific case, frealloc must return NULL);
-** particularly, frealloc(ud, NULL, 0, 0) does nothing
-** (which is equivalent to free(NULL) in ISO C)
+** - frealloc(ud, NULL, x, s) creates a new block of size 's'
+** (no matter 'x'). Returns NULL if it cannot create the new block.
**
-** frealloc returns NULL if it cannot create or reallocate the area
-** (any reallocation to an equal or smaller size cannot fail!)
+** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from
+** size 'x' to size 'y'. Returns NULL if it cannot reallocate the
+** block to the new size.
*/
+
+/*
+** {==================================================================
+** Functions to allocate/deallocate arrays for the Parser
+** ===================================================================
+*/
+
+/*
+** Minimum size for arrays during parsing, to avoid overhead of
+** reallocating to size 1, then 2, and then 4. All these arrays
+** will be reallocated to exact sizes or erased when parsing ends.
+*/
#define MINSIZEARRAY 4
-void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
- int limit, const char *what) {
+void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
+ int size_elems, int limit, const char *what) {
void *newblock;
- int newsize;
- if (*size >= limit/2) { /* cannot double it? */
- if (*size >= limit) /* cannot grow even a little? */
+ int size = *psize;
+ if (nelems + 1 <= size) /* does one extra element still fit? */
+ return block; /* nothing to be done */
+ if (size >= limit / 2) { /* cannot double it? */
+ if (l_unlikely(size >= limit)) /* cannot grow even a little? */
luaG_runerror(L, "too many %s (limit is %d)", what, limit);
- newsize = limit; /* still have at least one free place */
+ size = limit; /* still have at least one free place */
}
else {
- newsize = (*size)*2;
- if (newsize < MINSIZEARRAY)
- newsize = MINSIZEARRAY; /* minimum size */
+ size *= 2;
+ if (size < MINSIZEARRAY)
+ size = MINSIZEARRAY; /* minimum size */
}
- newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
- *size = newsize; /* update only when everything else is OK */
+ lua_assert(nelems + 1 <= size && size <= limit);
+ /* 'limit' ensures that multiplication will not overflow */
+ newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems,
+ cast_sizet(size) * size_elems);
+ *psize = size; /* update only when everything else is OK */
return newblock;
}
+/*
+** In prototypes, the size of the array is also its number of
+** elements (to save memory). So, if it cannot shrink an array
+** to its number of elements, the only option is to raise an
+** error.
+*/
+void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
+ int final_n, int size_elem) {
+ void *newblock;
+ size_t oldsize = cast_sizet((*size) * size_elem);
+ size_t newsize = cast_sizet(final_n * size_elem);
+ lua_assert(newsize <= oldsize);
+ newblock = luaM_saferealloc_(L, block, oldsize, newsize);
+ *size = final_n;
+ return newblock;
+}
+
+/* }================================================================== */
+
+
l_noret luaM_toobig (lua_State *L) {
luaG_runerror(L, "memory allocation error: block too big");
}
+/*
+** Free memory
+*/
+void luaM_free_ (lua_State *L, void *block, size_t osize) {
+ global_State *g = G(L);
+ lua_assert((osize == 0) == (block == NULL));
+ (*g->frealloc)(g->ud, block, osize, 0);
+ g->GCdebt -= osize;
+}
+
+
+/*
+** In case of allocation fail, this function will do an emergency
+** collection to free some memory and then try the allocation again.
+** The GC should not be called while state is not fully built, as the
+** collector is not yet fully initialized. Also, it should not be called
+** when 'gcstopem' is true, because then the interpreter is in the
+** middle of a collection step.
+*/
+static void *tryagain (lua_State *L, void *block,
+ size_t osize, size_t nsize) {
+ global_State *g = G(L);
+ if (completestate(g) && !g->gcstopem) {
+ luaC_fullgc(L, 1); /* try to free some memory... */
+ return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ }
+ else return NULL; /* cannot free any memory without a full state */
+}
+
/*
-** generic allocation routine.
+** Generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
void *newblock;
global_State *g = G(L);
- size_t realosize = (block) ? osize : 0;
- lua_assert((realosize == 0) == (block == NULL));
-#if defined(HARDMEMTESTS)
- if (nsize > realosize && g->gcrunning)
- luaC_fullgc(L, 1); /* force a GC whenever possible */
-#endif
- newblock = (*g->frealloc)(g->ud, block, osize, nsize);
- if (newblock == NULL && nsize > 0) {
- lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
- if (g->version) { /* is state fully built? */
- luaC_fullgc(L, 1); /* try to free some memory... */
- newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
- }
- if (newblock == NULL)
- luaD_throw(L, LUA_ERRMEM);
+ lua_assert((osize == 0) == (block == NULL));
+ newblock = firsttry(g, block, osize, nsize);
+ if (l_unlikely(newblock == NULL && nsize > 0)) {
+ newblock = tryagain(L, block, osize, nsize);
+ if (newblock == NULL) /* still no memory? */
+ return NULL; /* do not update 'GCdebt' */
}
lua_assert((nsize == 0) == (newblock == NULL));
- g->GCdebt = (g->GCdebt + nsize) - realosize;
+ g->GCdebt = (g->GCdebt + nsize) - osize;
+ return newblock;
+}
+
+
+void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
+ size_t nsize) {
+ void *newblock = luaM_realloc_(L, block, osize, nsize);
+ if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */
+ luaM_error(L);
return newblock;
}
+
+void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
+ if (size == 0)
+ return NULL; /* that's all */
+ else {
+ global_State *g = G(L);
+ void *newblock = firsttry(g, NULL, tag, size);
+ if (l_unlikely(newblock == NULL)) {
+ newblock = tryagain(L, NULL, tag, size);
+ if (newblock == NULL)
+ luaM_error(L);
+ }
+ g->GCdebt += size;
+ return newblock;
+ }
+}