comparison src/if_lua.c @ 32807:0582b3b40319 v9.0.1719

patch 9.0.1719: if_lua: crash for for Lua functions invoked via Vim callbacks Commit: https://github.com/vim/vim/commit/8a35033782de4e1f43fba15543fc8fb458944194 Author: Jesse Pavel <jpavel@alum.mit.edu> Date: Sun Aug 13 22:05:45 2023 -0400 patch 9.0.1719: if_lua: crash for for Lua functions invoked via Vim callbacks Problem: if_lua: crash for Lua functions invoked via Vim callbacks Solution: Use Lua registry rather than upvalues for udata cache closes: #12785 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Jesse Pavel <jpavel@alum.mit.edu>
author Christian Brabandt <cb@256bit.org>
date Tue, 15 Aug 2023 23:30:03 +0200
parents 4545f58c8490
children cf6d98955c64
comparison
equal deleted inserted replaced
32806:7328cddca686 32807:0582b3b40319
14 14
15 #include <lua.h> 15 #include <lua.h>
16 #include <lualib.h> 16 #include <lualib.h>
17 #include <lauxlib.h> 17 #include <lauxlib.h>
18 18
19 #if __STDC_VERSION__ >= 199901L
20 # define LUAV_INLINE inline
21 #else
22 # define LUAV_INLINE
23 #endif
24
19 // Only do the following when the feature is enabled. Needed for "make 25 // Only do the following when the feature is enabled. Needed for "make
20 // depend". 26 // depend".
21 #if defined(FEAT_LUA) || defined(PROTO) 27 #if defined(FEAT_LUA) || defined(PROTO)
22 28
23 #define LUAVIM_CHUNKNAME "vim chunk" 29 #define LUAVIM_CHUNKNAME "vim chunk"
59 static const char LUAVIM_LUAEVAL[] = "luaV_luaeval"; 65 static const char LUAVIM_LUAEVAL[] = "luaV_luaeval";
60 static const char LUAVIM_SETREF[] = "luaV_setref"; 66 static const char LUAVIM_SETREF[] = "luaV_setref";
61 67
62 static const char LUA___CALL[] = "__call"; 68 static const char LUA___CALL[] = "__call";
63 69
64 // most functions are closures with a cache table as first upvalue; 70 // get/setudata manage references to vim userdata in a cache table through
65 // get/setudata manage references to vim userdata in cache table through 71 // object pointers (light userdata). The cache table itself is retrieved
66 // object pointers (light userdata) 72 // from the registry.
67 #define luaV_getudata(L, v) \ 73
68 lua_pushlightuserdata((L), (void *) (v)); \ 74 static const char LUAVIM_UDATA_CACHE[] = "luaV_udata_cache";
69 lua_rawget((L), lua_upvalueindex(1)) 75
70 #define luaV_setudata(L, v) \ 76 static void LUAV_INLINE
71 lua_pushlightuserdata((L), (void *) (v)); \ 77 luaV_getudata(lua_State *L, void *v)
72 lua_pushvalue((L), -2); \ 78 {
73 lua_rawset((L), lua_upvalueindex(1)) 79 lua_pushlightuserdata(L, (void *) LUAVIM_UDATA_CACHE);
80 lua_rawget(L, LUA_REGISTRYINDEX); // now the cache table is at the top of the stack
81 lua_pushlightuserdata(L, v);
82 lua_rawget(L, -2);
83 lua_remove(L, -2); // remove the cache table from the stack
84 }
85
86 static void LUAV_INLINE
87 luaV_setudata(lua_State *L, void *v)
88 {
89 lua_pushlightuserdata(L, (void *) LUAVIM_UDATA_CACHE);
90 lua_rawget(L, LUA_REGISTRYINDEX); // cache table is at -1
91 lua_pushlightuserdata(L, v); // ...now at -2
92 lua_pushvalue(L, -3); // copy the userdata (cache at -3)
93 lua_rawset(L, -3); // consumes two stack items
94 lua_pop(L, 1); // and remove the cache table
95 }
96
74 #define luaV_getfield(L, s) \ 97 #define luaV_getfield(L, s) \
75 lua_pushlightuserdata((L), (void *)(s)); \ 98 lua_pushlightuserdata((L), (void *)(s)); \
76 lua_rawget((L), LUA_REGISTRYINDEX) 99 lua_rawget((L), LUA_REGISTRYINDEX)
77 #define luaV_checksandbox(L) \ 100 #define luaV_checksandbox(L) \
78 if (sandbox) luaL_error((L), "not allowed in sandbox") 101 if (sandbox) luaL_error((L), "not allowed in sandbox")
90 static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); 113 static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name);
91 static int luaV_call_lua_func(int argcount, typval_T *argvars, typval_T *rettv, void *state); 114 static int luaV_call_lua_func(int argcount, typval_T *argvars, typval_T *rettv, void *state);
92 static void luaV_call_lua_func_free(void *state); 115 static void luaV_call_lua_func_free(void *state);
93 116
94 #if LUA_VERSION_NUM <= 501 117 #if LUA_VERSION_NUM <= 501
95 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n) 118 #define luaV_register(L, l) luaL_register(L, NULL, l)
96 #define luaL_typeerror luaL_typerror 119 #define luaL_typeerror luaL_typerror
97 #else 120 #else
98 #define luaV_openlib luaL_setfuncs 121 #define luaV_register(L, l) luaL_setfuncs(L, l, 0)
99 #endif 122 #endif
100 123
101 #ifdef DYNAMIC_LUA 124 #ifdef DYNAMIC_LUA
102 125
103 #ifndef MSWIN 126 #ifndef MSWIN
877 } 900 }
878 901
879 static int 902 static int
880 luaV_list_iter(lua_State *L) 903 luaV_list_iter(lua_State *L)
881 { 904 {
882 listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(2)); 905 listitem_T *li = (listitem_T *) lua_touserdata(L, lua_upvalueindex(1));
883 if (li == NULL) return 0; 906 if (li == NULL) return 0;
884 luaV_pushtypval(L, &li->li_tv); 907 luaV_pushtypval(L, &li->li_tv);
885 lua_pushlightuserdata(L, (void *) li->li_next); 908 lua_pushlightuserdata(L, (void *) li->li_next);
886 lua_replace(L, lua_upvalueindex(2)); 909 lua_replace(L, lua_upvalueindex(1));
887 return 1; 910 return 1;
888 } 911 }
889 912
890 static int 913 static int
891 luaV_list_call(lua_State *L) 914 luaV_list_call(lua_State *L)
892 { 915 {
893 list_T *l = luaV_unbox(L, luaV_List, 1); 916 list_T *l = luaV_unbox(L, luaV_List, 1);
894 lua_pushvalue(L, lua_upvalueindex(1)); // pass cache table along
895 lua_pushlightuserdata(L, (void *) l->lv_first); 917 lua_pushlightuserdata(L, (void *) l->lv_first);
896 lua_pushcclosure(L, luaV_list_iter, 2); 918 lua_pushcclosure(L, luaV_list_iter, 1);
897 return 1; 919 return 1;
898 } 920 }
899 921
900 static int 922 static int
901 luaV_list_index(lua_State *L) 923 luaV_list_index(lua_State *L)
1055 1077
1056 static int 1078 static int
1057 luaV_dict_iter(lua_State *L UNUSED) 1079 luaV_dict_iter(lua_State *L UNUSED)
1058 { 1080 {
1059 #ifdef FEAT_EVAL 1081 #ifdef FEAT_EVAL
1060 hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(2)); 1082 hashitem_T *hi = (hashitem_T *) lua_touserdata(L, lua_upvalueindex(1));
1061 int n = lua_tointeger(L, lua_upvalueindex(3)); 1083 int n = lua_tointeger(L, lua_upvalueindex(2));
1062 dictitem_T *di; 1084 dictitem_T *di;
1063 if (n <= 0) return 0; 1085 if (n <= 0) return 0;
1064 while (HASHITEM_EMPTY(hi)) hi++; 1086 while (HASHITEM_EMPTY(hi)) hi++;
1065 di = dict_lookup(hi); 1087 di = dict_lookup(hi);
1066 lua_pushstring(L, (char *) hi->hi_key); 1088 lua_pushstring(L, (char *) hi->hi_key);
1067 luaV_pushtypval(L, &di->di_tv); 1089 luaV_pushtypval(L, &di->di_tv);
1068 lua_pushlightuserdata(L, (void *) (hi + 1)); 1090 lua_pushlightuserdata(L, (void *) (hi + 1));
1091 lua_replace(L, lua_upvalueindex(1));
1092 lua_pushinteger(L, n - 1);
1069 lua_replace(L, lua_upvalueindex(2)); 1093 lua_replace(L, lua_upvalueindex(2));
1070 lua_pushinteger(L, n - 1);
1071 lua_replace(L, lua_upvalueindex(3));
1072 return 2; 1094 return 2;
1073 #else 1095 #else
1074 return 0; 1096 return 0;
1075 #endif 1097 #endif
1076 } 1098 }
1078 static int 1100 static int
1079 luaV_dict_call(lua_State *L) 1101 luaV_dict_call(lua_State *L)
1080 { 1102 {
1081 dict_T *d = luaV_unbox(L, luaV_Dict, 1); 1103 dict_T *d = luaV_unbox(L, luaV_Dict, 1);
1082 hashtab_T *ht = &d->dv_hashtab; 1104 hashtab_T *ht = &d->dv_hashtab;
1083 lua_pushvalue(L, lua_upvalueindex(1)); // pass cache table along
1084 lua_pushlightuserdata(L, (void *) ht->ht_array); 1105 lua_pushlightuserdata(L, (void *) ht->ht_array);
1085 lua_pushinteger(L, ht->ht_used); // # remaining items 1106 lua_pushinteger(L, ht->ht_used); // # remaining items
1086 lua_pushcclosure(L, luaV_dict_iter, 3); 1107 lua_pushcclosure(L, luaV_dict_iter, 2);
1087 return 1; 1108 return 1;
1088 } 1109 }
1089 1110
1090 static int 1111 static int
1091 luaV_dict_index(lua_State *L) 1112 luaV_dict_index(lua_State *L)
2320 luaV_setref(lua_State *L) 2341 luaV_setref(lua_State *L)
2321 { 2342 {
2322 int copyID = lua_tointeger(L, 1); 2343 int copyID = lua_tointeger(L, 1);
2323 int abort = FALSE; 2344 int abort = FALSE;
2324 2345
2346 lua_pushlightuserdata(L, (void *) LUAVIM_UDATA_CACHE);
2347 lua_rawget(L, LUA_REGISTRYINDEX); // the cache table
2348
2325 luaV_getfield(L, LUAVIM_LIST); 2349 luaV_getfield(L, LUAVIM_LIST);
2326 luaV_getfield(L, LUAVIM_DICT); 2350 luaV_getfield(L, LUAVIM_DICT);
2327 luaV_getfield(L, LUAVIM_FUNCREF); 2351 luaV_getfield(L, LUAVIM_FUNCREF);
2328 lua_pushnil(L); 2352 lua_pushnil(L);
2329 // traverse cache table 2353 // traverse cache table
2330 while (!abort && lua_next(L, lua_upvalueindex(1)) != 0) 2354 while (!abort && lua_next(L, 2) != 0)
2331 { 2355 {
2332 lua_getmetatable(L, -1); 2356 lua_getmetatable(L, -1);
2333 if (lua_rawequal(L, -1, 2)) // list? 2357 if (lua_rawequal(L, -1, 3)) // list?
2334 { 2358 {
2335 list_T *l = (list_T *)lua_touserdata(L, 5); // key 2359 list_T *l = (list_T *)lua_touserdata(L, 6); // key
2336 2360
2337 abort = set_ref_in_list(l, copyID); 2361 abort = set_ref_in_list(l, copyID);
2338 } 2362 }
2339 else if (lua_rawequal(L, -1, 3)) // dict? 2363 else if (lua_rawequal(L, -1, 4)) // dict?
2340 { 2364 {
2341 dict_T *d = (dict_T *)lua_touserdata(L, 5); // key 2365 dict_T *d = (dict_T *)lua_touserdata(L, 6); // key
2342 2366
2343 abort = set_ref_in_dict(d, copyID); 2367 abort = set_ref_in_dict(d, copyID);
2344 } 2368 }
2345 else if (lua_rawequal(L, -1, 4)) // funcref? 2369 else if (lua_rawequal(L, -1, 5)) // funcref?
2346 { 2370 {
2347 luaV_Funcref *f = (luaV_Funcref *)lua_touserdata(L, 5); // key 2371 luaV_Funcref *f = (luaV_Funcref *)lua_touserdata(L, 6); // key
2348 2372
2349 abort = set_ref_in_dict(f->self, copyID); 2373 abort = set_ref_in_dict(f->self, copyID);
2350 } 2374 }
2351 lua_pop(L, 2); // metatable and value 2375 lua_pop(L, 2); // metatable and value
2352 } 2376 }
2464 "end" 2488 "end"
2465 2489
2466 static int 2490 static int
2467 luaopen_vim(lua_State *L) 2491 luaopen_vim(lua_State *L)
2468 { 2492 {
2469 // set cache table 2493 lua_newtable(L); // cache table
2470 lua_newtable(L); 2494 lua_newtable(L); // cache table's metatable
2471 lua_newtable(L);
2472 lua_pushstring(L, "v"); 2495 lua_pushstring(L, "v");
2473 lua_setfield(L, -2, "__mode"); 2496 lua_setfield(L, -2, "__mode");
2474 lua_setmetatable(L, -2); // cache is weak-valued 2497 lua_setmetatable(L, -2); // cache is weak-valued
2498 // put the cache table in the registry for luaV_get/setudata()
2499 lua_pushlightuserdata(L, (void *) LUAVIM_UDATA_CACHE);
2500 lua_pushvalue(L, -2);
2501 lua_rawset(L, LUA_REGISTRYINDEX);
2502 lua_pop(L, 1); // we don't need the cache table here anymore
2475 // print 2503 // print
2476 lua_pushcfunction(L, luaV_print); 2504 lua_pushcfunction(L, luaV_print);
2477 lua_setglobal(L, "print"); 2505 lua_setglobal(L, "print");
2478 // debug.debug 2506 // debug.debug
2479 lua_getglobal(L, "debug"); 2507 lua_getglobal(L, "debug");
2480 lua_pushcfunction(L, luaV_debug); 2508 lua_pushcfunction(L, luaV_debug);
2481 lua_setfield(L, -2, "debug"); 2509 lua_setfield(L, -2, "debug");
2482 lua_pop(L, 1); 2510 lua_pop(L, 1);
2483 // free 2511 // free
2484 lua_pushlightuserdata(L, (void *) LUAVIM_FREE); 2512 lua_pushlightuserdata(L, (void *) LUAVIM_FREE);
2485 lua_pushvalue(L, 1); // cache table 2513 lua_pushcfunction(L, luaV_free);
2486 lua_pushcclosure(L, luaV_free, 1);
2487 lua_rawset(L, LUA_REGISTRYINDEX); 2514 lua_rawset(L, LUA_REGISTRYINDEX);
2488 // luaeval 2515 // luaeval
2489 lua_pushlightuserdata(L, (void *) LUAVIM_LUAEVAL); 2516 lua_pushlightuserdata(L, (void *) LUAVIM_LUAEVAL);
2490 lua_pushvalue(L, 1); // cache table 2517 lua_pushcfunction(L, luaV_luaeval);
2491 lua_pushcclosure(L, luaV_luaeval, 1);
2492 lua_rawset(L, LUA_REGISTRYINDEX); 2518 lua_rawset(L, LUA_REGISTRYINDEX);
2493 // setref 2519 // setref
2494 lua_pushlightuserdata(L, (void *) LUAVIM_SETREF); 2520 lua_pushlightuserdata(L, (void *) LUAVIM_SETREF);
2495 lua_pushvalue(L, 1); // cache table 2521 lua_pushcfunction(L, luaV_setref);
2496 lua_pushcclosure(L, luaV_setref, 1);
2497 lua_rawset(L, LUA_REGISTRYINDEX); 2522 lua_rawset(L, LUA_REGISTRYINDEX);
2498 // register 2523 // register
2499 luaV_newmetatable(L, LUAVIM_LIST); 2524 luaV_newmetatable(L, LUAVIM_LIST);
2500 lua_pushvalue(L, 1); 2525 luaV_register(L, luaV_List_mt);
2501 luaV_openlib(L, luaV_List_mt, 1); 2526 lua_pop(L, 1);
2502 luaV_newmetatable(L, LUAVIM_DICT); 2527 luaV_newmetatable(L, LUAVIM_DICT);
2503 lua_pushvalue(L, 1); 2528 luaV_register(L, luaV_Dict_mt);
2504 luaV_openlib(L, luaV_Dict_mt, 1); 2529 lua_pop(L, 1);
2505 luaV_newmetatable(L, LUAVIM_BLOB); 2530 luaV_newmetatable(L, LUAVIM_BLOB);
2506 lua_pushvalue(L, 1); 2531 luaV_register(L, luaV_Blob_mt);
2507 luaV_openlib(L, luaV_Blob_mt, 1); 2532 lua_pop(L, 1);
2508 luaV_newmetatable(L, LUAVIM_FUNCREF); 2533 luaV_newmetatable(L, LUAVIM_FUNCREF);
2509 lua_pushvalue(L, 1); 2534 luaV_register(L, luaV_Funcref_mt);
2510 luaV_openlib(L, luaV_Funcref_mt, 1); 2535 lua_pop(L, 1);
2511 luaV_newmetatable(L, LUAVIM_BUFFER); 2536 luaV_newmetatable(L, LUAVIM_BUFFER);
2512 lua_pushvalue(L, 1); // cache table 2537 luaV_register(L, luaV_Buffer_mt);
2513 luaV_openlib(L, luaV_Buffer_mt, 1); 2538 lua_pop(L, 1);
2514 luaV_newmetatable(L, LUAVIM_WINDOW); 2539 luaV_newmetatable(L, LUAVIM_WINDOW);
2515 lua_pushvalue(L, 1); // cache table 2540 luaV_register(L, luaV_Window_mt);
2516 luaV_openlib(L, luaV_Window_mt, 1); 2541 lua_pop(L, 1);
2517 lua_newtable(L); // vim table 2542 lua_newtable(L); // vim table
2518 lua_pushvalue(L, 1); // cache table 2543 luaV_register(L, luaV_module);
2519 luaV_openlib(L, luaV_module, 1);
2520 luaV_pushversion(L); 2544 luaV_pushversion(L);
2521 lua_setfield(L, -2, "lua_version"); 2545 lua_setfield(L, -2, "lua_version");
2522 lua_setglobal(L, LUAVIM_NAME); 2546 lua_setglobal(L, LUAVIM_NAME);
2523 // custom code 2547 // custom code
2524 (void)luaL_dostring(L, LUA_VIM_FN_CODE); 2548 (void)luaL_dostring(L, LUA_VIM_FN_CODE);
2525 (void)luaL_dostring(L, LUA_VIM_UPDATE_PACKAGE_PATHS); 2549 (void)luaL_dostring(L, LUA_VIM_UPDATE_PACKAGE_PATHS);
2526 (void)luaL_dostring(L, LUA_VIM_SETUP_VARIABLE_DICTS); 2550 (void)luaL_dostring(L, LUA_VIM_SETUP_VARIABLE_DICTS);
2527 2551
2528 lua_getglobal(L, "vim"); 2552 lua_getglobal(L, LUAVIM_NAME);
2529 lua_getfield(L, -1, "_update_package_paths"); 2553 lua_getfield(L, -1, "_update_package_paths");
2530 2554
2531 if (lua_pcall(L, 0, 0, 0)) 2555 if (lua_pcall(L, 0, 0, 0))
2532 luaV_emsg(L); 2556 luaV_emsg(L);
2533 2557