Patch 8.1.1019
Problem: Lua: may garbage collect function reference in use.
Solution: Keep the function name instead of the typeval. Make luaV_setref()
handle funcref objects. (Ozaki Kiichi, closes #4127)
Files: src/if_lua.c, src/testdir/test_lua.vim
*** ../vim-8.1.1018/src/if_lua.c 2019-03-16 16:38:37.560654505 +0100
--- src/if_lua.c 2019-03-19 21:57:33.226164566 +0100
***************
*** 29,36 ****
typedef dict_T *luaV_Dict;
typedef list_T *luaV_List;
typedef struct {
! typval_T tv; // funcref
! typval_T args;
dict_T *self; // selfdict
} luaV_Funcref;
typedef void (*msgfunc_T)(char_u *);
--- 29,35 ----
typedef dict_T *luaV_Dict;
typedef list_T *luaV_List;
typedef struct {
! char_u *name; // funcref
dict_T *self; // selfdict
} luaV_Funcref;
typedef void (*msgfunc_T)(char_u *);
***************
*** 69,75 ****
static luaV_List *luaV_pushlist(lua_State *L, list_T *lis);
static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic);
! static luaV_Funcref *luaV_pushfuncref(lua_State *L, typval_T *tv);
#if LUA_VERSION_NUM <= 501
#define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
--- 68,74 ----
static luaV_List *luaV_pushlist(lua_State *L, list_T *lis);
static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic);
! static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name);
#if LUA_VERSION_NUM <= 501
#define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n)
***************
*** 443,449 ****
#if LUA_VERSION_NUM > 501
static int
! luaL_typeerror (lua_State *L, int narg, const char *tname)
{
const char *msg = lua_pushfstring(L, "%s expected, got %s",
tname, luaL_typename(L, narg));
--- 442,448 ----
#if LUA_VERSION_NUM > 501
static int
! luaL_typeerror(lua_State *L, int narg, const char *tname)
{
const char *msg = lua_pushfstring(L, "%s expected, got %s",
tname, luaL_typename(L, narg));
***************
*** 540,546 ****
lua_pushnil(L);
break;
case VAR_FUNC:
! luaV_pushfuncref(L, tv);
break;
default:
lua_pushnil(L);
--- 539,545 ----
lua_pushnil(L);
break;
case VAR_FUNC:
! luaV_pushfuncref(L, tv->vval.v_string);
break;
default:
lua_pushnil(L);
***************
*** 610,616 ****
if (lua_rawequal(L, -1, -4))
{
luaV_Funcref *f = (luaV_Funcref *) p;
! copy_tv(&f->tv, tv);
lua_pop(L, 4); /* MTs */
break;
}
--- 609,617 ----
if (lua_rawequal(L, -1, -4))
{
luaV_Funcref *f = (luaV_Funcref *) p;
! func_ref(f->name);
! tv->v_type = VAR_FUNC;
! tv->vval.v_string = vim_strsave(f->name);
lua_pop(L, 4); /* MTs */
break;
}
***************
*** 693,699 ****
#define luaV_newtype(typ,tname,luatyp,luatname) \
static luatyp * \
! luaV_new##tname (lua_State *L, typ *obj) \
{ \
luatyp *o = (luatyp *) lua_newuserdata(L, sizeof(luatyp)); \
*o = obj; \
--- 694,700 ----
#define luaV_newtype(typ,tname,luatyp,luatname) \
static luatyp * \
! luaV_new##tname(lua_State *L, typ *obj) \
{ \
luatyp *o = (luatyp *) lua_newuserdata(L, sizeof(luatyp)); \
*o = obj; \
***************
*** 725,731 ****
#define luaV_type_tostring(tname,luatname) \
static int \
! luaV_##tname##_tostring (lua_State *L) \
{ \
lua_pushfstring(L, "%s: %p", luatname, lua_touserdata(L, 1)); \
return 1; \
--- 726,732 ----
#define luaV_type_tostring(tname,luatname) \
static int \
! luaV_##tname##_tostring(lua_State *L) \
{ \
lua_pushfstring(L, "%s: %p", luatname, lua_touserdata(L, 1)); \
return 1; \
***************
*** 734,740 ****
/* ======= List type ======= */
static luaV_List *
! luaV_newlist (lua_State *L, list_T *lis)
{
luaV_List *l = (luaV_List *) lua_newuserdata(L, sizeof(luaV_List));
*l = lis;
--- 735,741 ----
/* ======= List type ======= */
static luaV_List *
! luaV_newlist(lua_State *L, list_T *lis)
{
luaV_List *l = (luaV_List *) lua_newuserdata(L, sizeof(luaV_List));
*l = lis;
***************
*** 749,755 ****
luaV_type_tostring(list, LUAVIM_LIST)
static int
! luaV_list_len (lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
lua_pushinteger(L, (l == NULL) ? 0 : (int) l->lv_len);
--- 750,756 ----
luaV_type_tostring(list, LUAVIM_LIST)
static int
! luaV_list_len(lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
lua_pushinteger(L, (l == NULL) ? 0 : (int) l->lv_len);
***************
*** 757,763 ****
}
static int
! luaV_list_iter (lua_State *L)
{
listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2));
if (li == NULL) return 0;
--- 758,764 ----
}
static int
! luaV_list_iter(lua_State *L)
{
listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2));
if (li == NULL) return 0;
***************
*** 768,774 ****
}
static int
! luaV_list_call (lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
--- 769,775 ----
}
static int
! luaV_list_call(lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
lua_pushvalue(L, lua_upvalueindex(1)); /* pass cache table along */
***************
*** 778,784 ****
}
static int
! luaV_list_index (lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
if (lua_isnumber(L, 2)) /* list item? */
--- 779,785 ----
}
static int
! luaV_list_index(lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
if (lua_isnumber(L, 2)) /* list item? */
***************
*** 807,813 ****
}
static int
! luaV_list_newindex (lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
long n = (long) luaL_checkinteger(L, 2);
--- 808,814 ----
}
static int
! luaV_list_newindex(lua_State *L)
{
list_T *l = luaV_unbox(L, luaV_List, 1);
long n = (long) luaL_checkinteger(L, 2);
***************
*** 834,840 ****
}
static int
! luaV_list_add (lua_State *L)
{
luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
--- 835,841 ----
}
static int
! luaV_list_add(lua_State *L)
{
luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
***************
*** 851,857 ****
}
static int
! luaV_list_insert (lua_State *L)
{
luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
--- 852,858 ----
}
static int
! luaV_list_insert(lua_State *L)
{
luaV_List *lis = luaV_checkudata(L, 1, LUAVIM_LIST);
list_T *l = (list_T *) luaV_checkcache(L, (void *) *lis);
***************
*** 890,896 ****
/* ======= Dict type ======= */
static luaV_Dict *
! luaV_newdict (lua_State *L, dict_T *dic)
{
luaV_Dict *d = (luaV_Dict *) lua_newuserdata(L, sizeof(luaV_Dict));
*d = dic;
--- 891,897 ----
/* ======= Dict type ======= */
static luaV_Dict *
! luaV_newdict(lua_State *L, dict_T *dic)
{
luaV_Dict *d = (luaV_Dict *) lua_newuserdata(L, sizeof(luaV_Dict));
*d = dic;
***************
*** 905,911 ****
luaV_type_tostring(dict, LUAVIM_DICT)
static int
! luaV_dict_len (lua_State *L)
{
dict_T *d = luaV_unbox(L, luaV_Dict, 1);
lua_pushinteger(L, (d == NULL) ? 0 : (int) d->dv_hashtab.ht_used);
--- 906,912 ----
luaV_type_tostring(dict, LUAVIM_DICT)
static int
! luaV_dict_len(lua_State *L)
{
dict_T *d = luaV_unbox(L, luaV_Dict, 1);
lua_pushinteger(L, (d == NULL) ? 0 : (int) d->dv_hashtab.ht_used);
***************
*** 913,919 ****
}
static int
! luaV_dict_iter (lua_State *L UNUSED)
{
#ifdef FEAT_EVAL
hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2));
--- 914,920 ----
}
static int
! luaV_dict_iter(lua_State *L UNUSED)
{
#ifdef FEAT_EVAL
hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2));
***************
*** 935,941 ****
}
static int
! luaV_dict_call (lua_State *L)
{
dict_T *d = luaV_unbox(L, luaV_Dict, 1);
hashtab_T *ht = &d->dv_hashtab;
--- 936,942 ----
}
static int
! luaV_dict_call(lua_State *L)
{
dict_T *d = luaV_unbox(L, luaV_Dict, 1);
hashtab_T *ht = &d->dv_hashtab;
***************
*** 1037,1047 ****
if (name != NULL)
{
! func_ref(name); /* as in copy_tv */
! f->tv.vval.v_string = vim_strsave(name);
}
- f->tv.v_type = VAR_FUNC;
- f->args.v_type = VAR_LIST;
f->self = NULL;
luaV_getfield(L, LUAVIM_FUNCREF);
lua_setmetatable(L, -2);
--- 1038,1046 ----
if (name != NULL)
{
! func_ref(name);
! f->name = vim_strsave(name);
}
f->self = NULL;
luaV_getfield(L, LUAVIM_FUNCREF);
lua_setmetatable(L, -2);
***************
*** 1049,1060 ****
}
static luaV_Funcref *
! luaV_pushfuncref(lua_State *L, typval_T *tv)
{
! luaV_Funcref *f = luaV_newfuncref(L, NULL);
! copy_tv(tv, &f->tv);
! clear_tv(tv);
! return f;
}
--- 1048,1056 ----
}
static luaV_Funcref *
! luaV_pushfuncref(lua_State *L, char_u *name)
{
! return luaV_newfuncref(L, name);
}
***************
*** 1065,1073 ****
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! func_unref(f->tv.vval.v_string);
! vim_free(f->tv.vval.v_string);
! dict_unref(f->self);
return 0;
}
--- 1061,1070 ----
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! func_unref(f->name);
! vim_free(f->name);
! // NOTE: Don't call "dict_unref(f->self)", because the dict of "f->self"
! // will be (or has been already) freed by Vim's garbage collection.
return 0;
}
***************
*** 1077,1083 ****
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! lua_pushstring(L, (const char *) f->tv.vval.v_string);
return 1;
}
--- 1074,1080 ----
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! lua_pushstring(L, (const char *) f->name);
return 1;
}
***************
*** 1085,1111 ****
luaV_funcref_call(lua_State *L)
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! int i, n = lua_gettop(L) - 1; /* #args */
! int status;
! typval_T v, rettv;
!
! f->args.vval.v_list = list_alloc();
! rettv.v_type = VAR_UNKNOWN; /* as in clear_tv */
! if (f->args.vval.v_list == NULL)
! status = FAIL;
! else
{
for (i = 0; i < n; i++)
{
luaV_checktypval(L, i + 2, &v, "calling funcref");
! list_append_tv(f->args.vval.v_list, &v);
clear_tv(&v);
}
! status = func_call(f->tv.vval.v_string, &f->args,
! NULL, f->self, &rettv);
if (status == OK)
luaV_pushtypval(L, &rettv);
! clear_tv(&f->args);
clear_tv(&rettv);
}
if (status != OK)
--- 1082,1109 ----
luaV_funcref_call(lua_State *L)
{
luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1);
! int i, n = lua_gettop(L) - 1; // #args
! int status = FAIL;
! typval_T args;
! typval_T rettv;
!
! args.v_type = VAR_LIST;
! args.vval.v_list = list_alloc();
! rettv.v_type = VAR_UNKNOWN; // as in clear_tv
! if (args.vval.v_list != NULL)
{
+ typval_T v;
+
for (i = 0; i < n; i++)
{
luaV_checktypval(L, i + 2, &v, "calling funcref");
! list_append_tv(args.vval.v_list, &v);
clear_tv(&v);
}
! status = func_call(f->name, &args, NULL, f->self, &rettv);
if (status == OK)
luaV_pushtypval(L, &rettv);
! clear_tv(&args);
clear_tv(&rettv);
}
if (status != OK)
***************
*** 1368,1374 ****
}
static int
! luaV_window_newindex (lua_State *L)
{
win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
const char *s = luaL_checkstring(L, 2);
--- 1366,1372 ----
}
static int
! luaV_window_newindex(lua_State *L)
{
win_T *w = (win_T *) luaV_checkvalid(L, luaV_Window, 1);
const char *s = luaL_checkstring(L, 2);
***************
*** 1768,1774 ****
}
static int
! luaV_luaeval (lua_State *L)
{
luaL_Buffer b;
size_t l;
--- 1766,1772 ----
}
static int
! luaV_luaeval(lua_State *L)
{
luaL_Buffer b;
size_t l;
***************
*** 1797,1828 ****
}
static int
! luaV_setref (lua_State *L)
{
! int copyID = lua_tointeger(L, 1);
! int abort = FALSE;
! typval_T tv;
luaV_getfield(L, LUAVIM_LIST);
luaV_getfield(L, LUAVIM_DICT);
lua_pushnil(L);
! /* traverse cache table */
while (!abort && lua_next(L, lua_upvalueindex(1)) != 0)
{
lua_getmetatable(L, -1);
! if (lua_rawequal(L, -1, 2)) /* list? */
{
! tv.v_type = VAR_LIST;
! tv.vval.v_list = (list_T *) lua_touserdata(L, 4); /* key */
! abort = set_ref_in_item(&tv, copyID, NULL, NULL);
}
! else if (lua_rawequal(L, -1, 3)) /* dict? */
{
! tv.v_type = VAR_DICT;
! tv.vval.v_dict = (dict_T *) lua_touserdata(L, 4); /* key */
! abort = set_ref_in_item(&tv, copyID, NULL, NULL);
}
! lua_pop(L, 2); /* metatable and value */
}
lua_pushinteger(L, abort);
return 1;
--- 1795,1844 ----
}
static int
! luaV_setref(lua_State *L)
{
! int copyID = lua_tointeger(L, 1);
! int abort = FALSE;
luaV_getfield(L, LUAVIM_LIST);
luaV_getfield(L, LUAVIM_DICT);
+ luaV_getfield(L, LUAVIM_FUNCREF);
lua_pushnil(L);
! // traverse cache table
while (!abort && lua_next(L, lua_upvalueindex(1)) != 0)
{
lua_getmetatable(L, -1);
! if (lua_rawequal(L, -1, 2)) // list?
! {
! list_T *l = (list_T *)lua_touserdata(L, 5); // key
!
! if (l->lv_copyID != copyID)
! {
! l->lv_copyID = copyID;
! abort = set_ref_in_list(l, copyID, NULL);
! }
! }
! else if (lua_rawequal(L, -1, 3)) // dict?
{
! dict_T *d = (dict_T *)lua_touserdata(L, 5); // key
!
! if (d->dv_copyID != copyID)
! {
! d->dv_copyID = copyID;
! abort = set_ref_in_ht(&d->dv_hashtab, copyID, NULL);
! }
}
! else if (lua_rawequal(L, -1, 4)) // funcref?
{
! luaV_Funcref *f = (luaV_Funcref *)lua_touserdata(L, 5); // key
!
! if (f->self != NULL && f->self->dv_copyID != copyID)
! {
! f->self->dv_copyID = copyID;
! abort = set_ref_in_ht(&f->self->dv_hashtab, copyID, NULL);
! }
}
! lua_pop(L, 2); // metatable and value
}
lua_pushinteger(L, abort);
return 1;
***************
*** 2053,2059 ****
luaV_freetype(win_T, window)
void
! do_luaeval (char_u *str, typval_T *arg, typval_T *rettv)
{
lua_init();
luaV_getfield(L, LUAVIM_LUAEVAL);
--- 2069,2075 ----
luaV_freetype(win_T, window)
void
! do_luaeval(char_u *str, typval_T *arg, typval_T *rettv)
{
lua_init();
luaV_getfield(L, LUAVIM_LUAEVAL);
***************
*** 2064,2070 ****
}
int
! set_ref_in_lua (int copyID)
{
int aborted = 0;
--- 2080,2086 ----
}
int
! set_ref_in_lua(int copyID)
{
int aborted = 0;
*** ../vim-8.1.1018/src/testdir/test_lua.vim 2019-03-10 09:48:55.711808501
+0100
--- src/testdir/test_lua.vim 2019-03-19 21:50:17.437605532 +0100
***************
*** 449,454 ****
--- 449,455 ----
lua d.len = vim.funcref"Mylen" -- assign d as 'self'
lua res = (d.len() == vim.funcref"len"(vim.eval"l")) and "OK" or "FAIL"
call assert_equal("OK", luaeval('res'))
+ call assert_equal(function('Mylen', {'data': l, 'len': function('Mylen')}),
mydict.len)
lua i1, i2, msg, d, res = nil
endfunc
*** ../vim-8.1.1018/src/version.c 2019-03-19 20:50:40.290035255 +0100
--- src/version.c 2019-03-19 21:53:59.151973880 +0100
***************
*** 781,782 ****
--- 781,784 ----
{ /* Add new patch number below this line */
+ /**/
+ 1019,
/**/
--
>From "know your smileys":
:-O>-o Smiley American tourist (note big mouth and camera)
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.