diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2021-04-03 17:48:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-03 17:48:39 +0200 |
commit | 804ea22944146a6607859dbfcf35d24946b065e2 (patch) | |
tree | 94d3ebac9ae1bcbbf45cc000e644155e419d39ba /src | |
parent | abdda664108646a8f1bd3112abb8083d721d38e6 (diff) | |
parent | 2df527e1ff1c599448b6b21953132c0022a8b9ad (diff) | |
download | rneovim-804ea22944146a6607859dbfcf35d24946b065e2.tar.gz rneovim-804ea22944146a6607859dbfcf35d24946b065e2.tar.bz2 rneovim-804ea22944146a6607859dbfcf35d24946b065e2.zip |
Merge pull request #14226 from bfredl/luarefcount
lua: track reference ownership with ASAN when present
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/buffer.c | 6 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 27 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 20 | ||||
-rw-r--r-- | src/nvim/buffer_updates.c | 13 | ||||
-rw-r--r-- | src/nvim/decoration.c | 50 | ||||
-rw-r--r-- | src/nvim/eval.c | 2 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 5 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 7 | ||||
-rw-r--r-- | src/nvim/highlight.c | 4 | ||||
-rw-r--r-- | src/nvim/lua/converter.c | 2 | ||||
-rw-r--r-- | src/nvim/lua/converter.h | 1 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 188 | ||||
-rw-r--r-- | src/nvim/lua/executor.h | 2 | ||||
-rw-r--r-- | src/nvim/memory.c | 6 |
14 files changed, 178 insertions, 155 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 66c4454f7b..6142db049d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -222,11 +222,7 @@ Boolean nvim_buf_attach(uint64_t channel_id, return buf_updates_register(buf, channel_id, cb, send_buffer); error: - // TODO(bfredl): ASAN build should check that the ref table is empty? - api_free_luaref(cb.on_lines); - api_free_luaref(cb.on_bytes); - api_free_luaref(cb.on_changedtick); - api_free_luaref(cb.on_detach); + buffer_update_callbacks_free(cb); return false; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d2b787a6f5..382244d6b3 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1708,33 +1708,6 @@ const char *describe_ns(NS ns_id) return "(UNKNOWN PLUGIN)"; } -DecorProvider *get_provider(NS ns_id, bool force) -{ - ssize_t i; - for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) { - DecorProvider *item = &kv_A(decor_providers, i); - if (item->ns_id == ns_id) { - return item; - } else if (item->ns_id > ns_id) { - break; - } - } - - if (!force) { - return NULL; - } - - for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) { - // allocates if needed: - (void)kv_a(decor_providers, (size_t)j+1); - kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j); - } - DecorProvider *item = &kv_a(decor_providers, (size_t)i); - *item = DECORATION_PROVIDER_INIT(ns_id); - - return item; -} - static bool parse_float_anchor(String anchor, FloatAnchor *out) { if (anchor.size == 0) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 787b6addc9..3ae944de4d 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2708,6 +2708,7 @@ Dictionary nvim__stats(void) Dictionary rv = ARRAY_DICT_INIT; PUT(rv, "fsync", INTEGER_OBJ(g_stats.fsync)); PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw)); + PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_refcount)); return rv; } @@ -2880,19 +2881,6 @@ void nvim__screenshot(String path) ui_call_screenshot(path); } -static void clear_provider(DecorProvider *p) -{ - if (p == NULL) { - return; - } - NLUA_CLEAR_REF(p->redraw_start); - NLUA_CLEAR_REF(p->redraw_buf); - NLUA_CLEAR_REF(p->redraw_win); - NLUA_CLEAR_REF(p->redraw_line); - NLUA_CLEAR_REF(p->redraw_end); - p->active = false; -} - /// Set or change decoration provider for a namespace /// /// This is a very general purpose interface for having lua callbacks @@ -2937,8 +2925,8 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Error *err) FUNC_API_SINCE(7) FUNC_API_LUA_ONLY { - DecorProvider *p = get_provider((NS)ns_id, true); - clear_provider(p); + DecorProvider *p = get_decor_provider((NS)ns_id, true); + decor_provider_clear(p); // regardless of what happens, it seems good idea to redraw redraw_all_later(NOT_VALID); // TODO(bfredl): too soon? @@ -2981,5 +2969,5 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, p->active = true; return; error: - clear_provider(p); + decor_provider_clear(p); } diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 97562eace6..5c573530d1 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -176,7 +176,7 @@ void buf_updates_unload(buf_T *buf, bool can_reload) if (keep) { kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i); } else { - free_update_callbacks(cb); + buffer_update_callbacks_free(cb); } } kv_size(buf->update_callbacks) = j; @@ -290,7 +290,7 @@ void buf_updates_send_changes(buf_T *buf, textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { - free_update_callbacks(cb); + buffer_update_callbacks_free(cb); keep = false; } api_free_object(res); @@ -342,7 +342,7 @@ void buf_updates_send_splice( textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { - free_update_callbacks(cb); + buffer_update_callbacks_free(cb); keep = false; } } @@ -378,7 +378,7 @@ void buf_updates_changedtick(buf_T *buf) textlock--; if (res.type == kObjectTypeBoolean && res.data.boolean == true) { - free_update_callbacks(cb); + buffer_update_callbacks_free(cb); keep = false; } api_free_object(res); @@ -406,8 +406,11 @@ void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id) rpc_send_event(channel_id, "nvim_buf_changedtick_event", args); } -static void free_update_callbacks(BufUpdateCallbacks cb) +void buffer_update_callbacks_free(BufUpdateCallbacks cb) { api_free_luaref(cb.on_lines); + api_free_luaref(cb.on_bytes); api_free_luaref(cb.on_changedtick); + api_free_luaref(cb.on_reload); + api_free_luaref(cb.on_detach); } diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index e16598e7d2..52a48ae6fb 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -2,6 +2,7 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "nvim/vim.h" +#include "nvim/lua/executor.h" #include "nvim/extmark.h" #include "nvim/decoration.h" #include "nvim/screen.h" @@ -365,3 +366,52 @@ void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, decor_add(&decor_state, start_row, start_col, end_row, end_col, decor, true, priority); } + + +DecorProvider *get_decor_provider(NS ns_id, bool force) +{ + ssize_t i; + for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) { + DecorProvider *item = &kv_A(decor_providers, i); + if (item->ns_id == ns_id) { + return item; + } else if (item->ns_id > ns_id) { + break; + } + } + + if (!force) { + return NULL; + } + + for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) { + // allocates if needed: + (void)kv_a(decor_providers, (size_t)j+1); + kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j); + } + DecorProvider *item = &kv_a(decor_providers, (size_t)i); + *item = DECORATION_PROVIDER_INIT(ns_id); + + return item; +} + +void decor_provider_clear(DecorProvider *p) +{ + if (p == NULL) { + return; + } + NLUA_CLEAR_REF(p->redraw_start); + NLUA_CLEAR_REF(p->redraw_buf); + NLUA_CLEAR_REF(p->redraw_win); + NLUA_CLEAR_REF(p->redraw_line); + NLUA_CLEAR_REF(p->redraw_end); + p->active = false; +} + +void decor_free_all_mem(void) +{ + for (size_t i = 0; i < kv_size(decor_providers); i++) { + decor_provider_clear(&kv_A(decor_providers, i)); + } + kv_destroy(decor_providers); +} diff --git a/src/nvim/eval.c b/src/nvim/eval.c index c9366b3bd3..550fe8ab65 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6263,6 +6263,7 @@ void common_function(typval_T *argvars, typval_T *rettv, // function(dict.MyFunc, [arg]) arg_pt = argvars[0].vval.v_partial; s = partial_name(arg_pt); + // TODO(bfredl): do the entire nlua_is_table_from_lua dance } else { // function('MyFunc', [arg], dict) s = (char_u *)tv_get_string(&argvars[0]); @@ -7362,7 +7363,6 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg) char_u *name = nlua_register_table_as_callable(arg); if (name != NULL) { - func_ref(name); callback->data.funcref = vim_strsave(name); callback->type = kCallbackFuncref; } else { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 38002474af..51e5a27348 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -810,6 +810,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } + bool owned = false; char_u *func; partial_T *partial = NULL; dict_T *selfdict = NULL; @@ -820,6 +821,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) func = partial_name(partial); } else if (nlua_is_table_from_lua(&argvars[0])) { func = nlua_register_table_as_callable(&argvars[0]); + owned = true; } else { func = (char_u *)tv_get_string(&argvars[0]); } @@ -837,6 +839,9 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr) } func_call(func, &argvars[1], partial, selfdict, rettv); + if (owned) { + func_unref(func); + } } /* diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index fe3d147040..71e4edc667 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -219,6 +219,7 @@ list_T *tv_list_alloc(const ptrdiff_t len) list->lv_used_next = gc_first_list; gc_first_list = list; list_log(list, NULL, (void *)(uintptr_t)len, "alloc"); + list->lua_table_ref = LUA_NOREF; return list; } @@ -302,7 +303,7 @@ void tv_list_free_list(list_T *const l) } list_log(l, NULL, NULL, "freelist"); - nlua_free_typval_list(l); + NLUA_CLEAR_REF(l->lua_table_ref); xfree(l); } @@ -1404,6 +1405,8 @@ dict_T *tv_dict_alloc(void) d->dv_copyID = 0; QUEUE_INIT(&d->watchers); + d->lua_table_ref = LUA_NOREF; + return d; } @@ -1454,7 +1457,7 @@ void tv_dict_free_dict(dict_T *const d) d->dv_used_next->dv_used_prev = d->dv_used_prev; } - nlua_free_typval_dict(d); + NLUA_CLEAR_REF(d->lua_table_ref); xfree(d); } diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index f03382bea7..329c448cf0 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -151,7 +151,7 @@ int hl_get_syn_attr(int ns_id, int idx, HlAttrs at_en) void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id) { - DecorProvider *p = get_provider(ns_id, true); + DecorProvider *p = get_decor_provider(ns_id, true); if ((attrs.rgb_ae_attr & HL_DEFAULT) && map_has(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id))) { return; @@ -175,7 +175,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) ns_id = ns_hl_active; } - DecorProvider *p = get_provider(ns_id, true); + DecorProvider *p = get_decor_provider(ns_id, true); ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id)); // TODO(bfredl): map_ref true even this? bool valid_cache = it.version >= p->hl_valid; diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 83b3729ad3..ce8c9b0d06 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -400,7 +400,6 @@ nlua_pop_typval_table_processing_end: case LUA_TFUNCTION: { LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); state->lua_callable.func_ref = nlua_ref(lstate, -1); - state->lua_callable.table_ref = LUA_NOREF; char_u *name = register_cfunc( &nlua_CFunction_func_call, @@ -412,6 +411,7 @@ nlua_pop_typval_table_processing_end: break; } case LUA_TUSERDATA: { + // TODO(bfredl): check mt.__call and convert to function? nlua_pushref(lstate, nlua_nil_ref); bool is_nil = lua_rawequal(lstate, -2, -1); lua_pop(lstate, 1); diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h index 8601a32418..43a7e06019 100644 --- a/src/nvim/lua/converter.h +++ b/src/nvim/lua/converter.h @@ -11,7 +11,6 @@ typedef struct { LuaRef func_ref; - LuaRef table_ref; } LuaCallable; typedef struct { diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 03d178467b..9b8e9ff8cc 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -5,6 +5,7 @@ #include <lualib.h> #include <lauxlib.h> +#include "nvim/assert.h" #include "nvim/version.h" #include "nvim/misc1.h" #include "nvim/getchar.h" @@ -18,6 +19,7 @@ #include "nvim/vim.h" #include "nvim/ex_getln.h" #include "nvim/ex_cmds2.h" +#include "nvim/map.h" #include "nvim/message.h" #include "nvim/memline.h" #include "nvim/buffer_defs.h" @@ -32,9 +34,7 @@ #include "nvim/event/time.h" #include "nvim/event/loop.h" -#ifdef WIN32 #include "nvim/os/os.h" -#endif #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" @@ -63,6 +63,11 @@ typedef struct { } \ } +#if __has_feature(address_sanitizer) + PMap(handle_T) *nlua_ref_markers = NULL; +# define NLUA_TRACK_REFS +#endif + /// Convert lua error into a Vim error message /// /// @param lstate Lua interpreter state. @@ -547,6 +552,13 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL static lua_State *nlua_init(void) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT { +#ifdef NLUA_TRACK_REFS + const char *env = os_getenv("NVIM_LUA_NOTRACK"); + if (!env || !*env) { + nlua_ref_markers = pmap_new(handle_T)(); + } +#endif + lua_State *lstate = luaL_newstate(); if (lstate == NULL) { EMSG(_("E970: Failed to initialize lua interpreter")); @@ -554,9 +566,13 @@ static lua_State *nlua_init(void) } luaL_openlibs(lstate); nlua_state_init(lstate); + return lstate; } +// only to be used by nlua_enter and nlua_free_all_mem! +static lua_State *global_lstate = NULL; + /// Enter lua interpreter /// /// Calls nlua_init() if needed. Is responsible for pre-lua call initalization @@ -567,26 +583,39 @@ static lua_State *nlua_init(void) static lua_State *nlua_enter(void) FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT { - static lua_State *global_lstate = NULL; if (global_lstate == NULL) { global_lstate = nlua_init(); } lua_State *const lstate = global_lstate; - // Last used p_rtp value. Must not be dereferenced because value pointed to - // may already be freed. Used to check whether &runtimepath option value - // changed. - static const void *last_p_rtp = NULL; - if (last_p_rtp != (const void *)p_rtp) { - // stack: (empty) - lua_getglobal(lstate, "vim"); - // stack: vim - lua_pop(lstate, 1); - // stack: (empty) - last_p_rtp = (const void *)p_rtp; - } return lstate; } +void nlua_free_all_mem(void) +{ + if (!global_lstate) { + return; + } + lua_State *lstate = global_lstate; + + nlua_unref(lstate, nlua_nil_ref); + nlua_unref(lstate, nlua_empty_dict_ref); + +#ifdef NLUA_TRACK_REFS + if (nlua_refcount) { + fprintf(stderr, "%d lua references were leaked!", nlua_refcount); + } + + if (nlua_ref_markers) { + // in case there are leaked luarefs, leak the associated memory + // to get LeakSanitizer stacktraces on exit + pmap_free(handle_T)(nlua_ref_markers); + } +#endif + + nlua_refcount = 0; + lua_close(lstate); +} + static void nlua_print_event(void **argv) { char *str = argv[0]; @@ -866,17 +895,35 @@ static int nlua_getenv(lua_State *lstate) } #endif + /// add the value to the registry LuaRef nlua_ref(lua_State *lstate, int index) { lua_pushvalue(lstate, index); - return luaL_ref(lstate, LUA_REGISTRYINDEX); + LuaRef ref = luaL_ref(lstate, LUA_REGISTRYINDEX); + if (ref > 0) { + nlua_refcount++; +#ifdef NLUA_TRACK_REFS + if (nlua_ref_markers) { + // dummy allocation to make LeakSanitizer track our luarefs + pmap_put(handle_T)(nlua_ref_markers, ref, xmalloc(3)); + } +#endif + } + return ref; } /// remove the value from the registry void nlua_unref(lua_State *lstate, LuaRef ref) { if (ref > 0) { + nlua_refcount--; +#ifdef NLUA_TRACK_REFS + // NB: don't remove entry from map to track double-unref + if (nlua_ref_markers) { + xfree(pmap_get(handle_T)(nlua_ref_markers, ref)); + } +#endif luaL_unref(lstate, LUA_REGISTRYINDEX, ref); } } @@ -893,19 +940,11 @@ void nlua_pushref(lua_State *lstate, LuaRef ref) lua_rawgeti(lstate, LUA_REGISTRYINDEX, ref); } + /// Gets a new reference to an object stored at original_ref /// /// NOTE: It does not copy the value, it creates a new ref to the lua object. /// Leaves the stack unchanged. -LuaRef nlua_newref(lua_State *lstate, LuaRef original_ref) -{ - nlua_pushref(lstate, original_ref); - LuaRef new_ref = nlua_ref(lstate, -1); - lua_pop(lstate, 1); - - return new_ref; -} - LuaRef api_new_luaref(LuaRef original_ref) { if (original_ref == LUA_NOREF) { @@ -913,7 +952,10 @@ LuaRef api_new_luaref(LuaRef original_ref) } lua_State *const lstate = nlua_enter(); - return nlua_newref(lstate, original_ref); + nlua_pushref(lstate, original_ref); + LuaRef new_ref = nlua_ref(lstate, -1); + lua_pop(lstate, 1); + return new_ref; } @@ -1023,25 +1065,13 @@ int typval_exec_lua_callable( typval_T *rettv ) { - int offset = 0; LuaRef cb = lua_cb.func_ref; - if (cb == LUA_NOREF) { - // This shouldn't happen. - luaL_error(lstate, "Invalid function passed to VimL"); - return ERROR_OTHER; - } - nlua_pushref(lstate, cb); - if (lua_cb.table_ref != LUA_NOREF) { - offset += 1; - nlua_pushref(lstate, lua_cb.table_ref); - } - PUSH_ALL_TYPVALS(lstate, argvars, argcount, false); - if (lua_pcall(lstate, argcount + offset, 1, 0)) { + if (lua_pcall(lstate, argcount, 1, 0)) { nlua_print(lstate); return ERROR_OTHER; } @@ -1508,6 +1538,8 @@ static int regex_match_line(lua_State *lstate) return nret; } +// Required functions for lua c functions as VimL callbacks + int nlua_CFunction_func_call( int argcount, typval_T *argvars, @@ -1517,53 +1549,40 @@ int nlua_CFunction_func_call( lua_State *const lstate = nlua_enter(); LuaCFunctionState *funcstate = (LuaCFunctionState *)state; - return typval_exec_lua_callable( - lstate, - funcstate->lua_callable, - argcount, - argvars, - rettv); + return typval_exec_lua_callable(lstate, funcstate->lua_callable, + argcount, argvars, rettv); } -/// Required functions for lua c functions as VimL callbacks + void nlua_CFunction_func_free(void *state) { lua_State *const lstate = nlua_enter(); LuaCFunctionState *funcstate = (LuaCFunctionState *)state; nlua_unref(lstate, funcstate->lua_callable.func_ref); - nlua_unref(lstate, funcstate->lua_callable.table_ref); xfree(funcstate); } bool nlua_is_table_from_lua(typval_T *const arg) { - if (arg->v_type != VAR_DICT && arg->v_type != VAR_LIST) { - return false; - } - if (arg->v_type == VAR_DICT) { - return arg->vval.v_dict->lua_table_ref > 0 - && arg->vval.v_dict->lua_table_ref != LUA_NOREF; + return arg->vval.v_dict->lua_table_ref != LUA_NOREF; } else if (arg->v_type == VAR_LIST) { - return arg->vval.v_list->lua_table_ref > 0 - && arg->vval.v_list->lua_table_ref != LUA_NOREF; + return arg->vval.v_list->lua_table_ref != LUA_NOREF; + } else { + return false; } - - return false; } char_u *nlua_register_table_as_callable(typval_T *const arg) { - if (!nlua_is_table_from_lua(arg)) { - return NULL; - } - - LuaRef table_ref; + LuaRef table_ref = LUA_NOREF; if (arg->v_type == VAR_DICT) { table_ref = arg->vval.v_dict->lua_table_ref; } else if (arg->v_type == VAR_LIST) { table_ref = arg->vval.v_list->lua_table_ref; - } else { + } + + if (table_ref == LUA_NOREF) { return NULL; } @@ -1573,55 +1592,34 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) int top = lua_gettop(lstate); #endif - nlua_pushref(lstate, table_ref); + nlua_pushref(lstate, table_ref); // [table] if (!lua_getmetatable(lstate, -1)) { + lua_pop(lstate, 1); + assert(top == lua_gettop(lstate)); return NULL; - } + } // [table, mt] - lua_getfield(lstate, -1, "__call"); + lua_getfield(lstate, -1, "__call"); // [table, mt, mt.__call] if (!lua_isfunction(lstate, -1)) { + lua_pop(lstate, 3); + assert(top == lua_gettop(lstate)); return NULL; } - - LuaRef new_table_ref = nlua_newref(lstate, table_ref); + lua_pop(lstate, 2); // [table] LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); state->lua_callable.func_ref = nlua_ref(lstate, -1); - state->lua_callable.table_ref = new_table_ref; - char_u *name = register_cfunc( - &nlua_CFunction_func_call, - &nlua_CFunction_func_free, - state); + char_u *name = register_cfunc(&nlua_CFunction_func_call, + &nlua_CFunction_func_free, state); - lua_pop(lstate, 3); + lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); return name; } -/// Helper function to free a list_T -void nlua_free_typval_list(list_T *const l) -{ - if (l->lua_table_ref != LUA_NOREF && l->lua_table_ref > 0) { - lua_State *const lstate = nlua_enter(); - nlua_unref(lstate, l->lua_table_ref); - l->lua_table_ref = LUA_NOREF; - } -} - - -/// Helper function to free a dict_T -void nlua_free_typval_dict(dict_T *const d) -{ - if (d->lua_table_ref != LUA_NOREF && d->lua_table_ref > 0) { - lua_State *const lstate = nlua_enter(); - nlua_unref(lstate, d->lua_table_ref); - d->lua_table_ref = LUA_NOREF; - } -} - void nlua_execute_log_keystroke(int c) { char_u buf[NUMBUFLEN]; diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 1d7a15d9aa..ea774ac2e3 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -16,6 +16,8 @@ void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; EXTERN LuaRef nlua_nil_ref INIT(= LUA_NOREF); EXTERN LuaRef nlua_empty_dict_ref INIT(= LUA_NOREF); +EXTERN int nlua_refcount INIT(= 0); + #define set_api_error(s, err) \ do { \ Error *err_ = (err); \ diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 9bc6b23ce3..7a8fc4da75 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -19,6 +19,8 @@ #include "nvim/ui.h" #include "nvim/sign.h" #include "nvim/api/vim.h" +#include "nvim/lua/executor.h" +#include "nvim/decoration.h" #ifdef UNIT_TESTING # define malloc(size) mem_malloc(size) @@ -695,6 +697,10 @@ void free_all_mem(void) list_free_log(); check_quickfix_busy(); + + decor_free_all_mem(); + + nlua_free_all_mem(); } #endif |