To: vim_dev@googlegroups.com Subject: Patch 8.2.3267 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3267 Problem: Vim9: crash when disassembling a function that uses a deleted script variable. Solution: Check the variable still exists. (closes #8683) Files: src/vim9execute.c, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.3266/src/vim9execute.c 2021-07-29 22:48:50.107129898 +0200 --- src/vim9execute.c 2021-08-01 13:48:21.923666805 +0200 *************** *** 1254,1279 **** return vim_strnsave(str + start_byte, end_byte - start_byte); } static svar_T * ! get_script_svar(scriptref_T *sref, ectx_T *ectx) { scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) ! + ectx->ec_dfunc_idx; svar_T *sv; if (sref->sref_seq != si->sn_script_seq) { ! // The script was reloaded after the function was ! // compiled, the script_idx may not be valid. ! semsg(_(e_script_variable_invalid_after_reload_in_function_str), ! dfunc->df_ufunc->uf_name_exp); return NULL; } sv = ((svar_T *)si->sn_var_vals.ga_data) + sref->sref_idx; if (!equal_type(sv->sv_type, sref->sref_type, 0)) { ! emsg(_(e_script_variable_type_changed)); return NULL; } return sv; --- 1254,1286 ---- return vim_strnsave(str + start_byte, end_byte - start_byte); } + /* + * Get a script variable for ISN_STORESCRIPT and ISN_LOADSCRIPT. + * When "dfunc_idx" is negative don't give an error. + * Returns NULL for an error. + */ static svar_T * ! get_script_svar(scriptref_T *sref, int dfunc_idx) { scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! dfunc_T *dfunc = dfunc_idx < 0 ? NULL ! : ((dfunc_T *)def_functions.ga_data) + dfunc_idx; svar_T *sv; if (sref->sref_seq != si->sn_script_seq) { ! // The script was reloaded after the function was compiled, the ! // script_idx may not be valid. ! if (dfunc != NULL) ! semsg(_(e_script_variable_invalid_after_reload_in_function_str), ! printable_func_name(dfunc->df_ufunc)); return NULL; } sv = ((svar_T *)si->sn_var_vals.ga_data) + sref->sref_idx; if (!equal_type(sv->sv_type, sref->sref_type, 0)) { ! if (dfunc != NULL) ! emsg(_(e_script_variable_type_changed)); return NULL; } return sv; *************** *** 1976,1982 **** scriptref_T *sref = iptr->isn_arg.script.scriptref; svar_T *sv; ! sv = get_script_svar(sref, ectx); if (sv == NULL) goto theend; allocate_if_null(sv->sv_tv); --- 1983,1989 ---- scriptref_T *sref = iptr->isn_arg.script.scriptref; svar_T *sv; ! sv = get_script_svar(sref, ectx->ec_dfunc_idx); if (sv == NULL) goto theend; allocate_if_null(sv->sv_tv); *************** *** 2189,2195 **** scriptref_T *sref = iptr->isn_arg.script.scriptref; svar_T *sv; ! sv = get_script_svar(sref, ectx); if (sv == NULL) goto theend; --ectx->ec_stack.ga_len; --- 2196,2202 ---- scriptref_T *sref = iptr->isn_arg.script.scriptref; svar_T *sv; ! sv = get_script_svar(sref, ectx->ec_dfunc_idx); if (sv == NULL) goto theend; --ectx->ec_stack.ga_len; *************** *** 4942,4953 **** break; case ISN_LOADSCRIPT: { ! scriptref_T *sref = iptr->isn_arg.script.scriptref; ! scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) ! + sref->sref_idx; ! smsg("%s%4d LOADSCRIPT %s-%d from %s", pfx, current, sv->sv_name, sref->sref_idx, si->sn_name); --- 4949,4964 ---- break; case ISN_LOADSCRIPT: { ! scriptref_T *sref = iptr->isn_arg.script.scriptref; ! scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! svar_T *sv; ! sv = get_script_svar(sref, -1); ! if (sv == NULL) ! smsg("%s%4d LOADSCRIPT [deleted] from %s", ! pfx, current, si->sn_name); ! else ! smsg("%s%4d LOADSCRIPT %s-%d from %s", pfx, current, sv->sv_name, sref->sref_idx, si->sn_name); *************** *** 4996,5002 **** smsg("%s%4d LOADENV %s", pfx, current, iptr->isn_arg.string); break; case ISN_LOADREG: ! smsg("%s%4d LOADREG @%c", pfx, current, (int)(iptr->isn_arg.number)); break; case ISN_STORE: --- 5007,5014 ---- smsg("%s%4d LOADENV %s", pfx, current, iptr->isn_arg.string); break; case ISN_LOADREG: ! smsg("%s%4d LOADREG @%c", pfx, current, ! (int)(iptr->isn_arg.number)); break; case ISN_STORE: *************** *** 5004,5010 **** smsg("%s%4d STORE arg[%lld]", pfx, current, iptr->isn_arg.number + STACK_FRAME_SIZE); else ! smsg("%s%4d STORE $%lld", pfx, current, iptr->isn_arg.number); break; case ISN_STOREOUTER: { --- 5016,5023 ---- smsg("%s%4d STORE arg[%lld]", pfx, current, iptr->isn_arg.number + STACK_FRAME_SIZE); else ! smsg("%s%4d STORE $%lld", pfx, current, ! iptr->isn_arg.number); break; case ISN_STOREOUTER: { *************** *** 5048,5059 **** break; case ISN_STORESCRIPT: { ! scriptref_T *sref = iptr->isn_arg.script.scriptref; ! scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) ! + sref->sref_idx; ! smsg("%s%4d STORESCRIPT %s-%d in %s", pfx, current, sv->sv_name, sref->sref_idx, si->sn_name); --- 5061,5076 ---- break; case ISN_STORESCRIPT: { ! scriptref_T *sref = iptr->isn_arg.script.scriptref; ! scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid); ! svar_T *sv; ! sv = get_script_svar(sref, -1); ! if (sv == NULL) ! smsg("%s%4d STORESCRIPT [deleted] in %s", ! pfx, current, si->sn_name); ! else ! smsg("%s%4d STORESCRIPT %s-%d in %s", pfx, current, sv->sv_name, sref->sref_idx, si->sn_name); *************** *** 5067,5073 **** smsg("%s%4d STOREENV $%s", pfx, current, iptr->isn_arg.string); break; case ISN_STOREREG: ! smsg("%s%4d STOREREG @%c", pfx, current, (int)iptr->isn_arg.number); break; case ISN_STORENR: smsg("%s%4d STORE %lld in $%d", pfx, current, --- 5084,5091 ---- smsg("%s%4d STOREENV $%s", pfx, current, iptr->isn_arg.string); break; case ISN_STOREREG: ! smsg("%s%4d STOREREG @%c", pfx, current, ! (int)iptr->isn_arg.number); break; case ISN_STORENR: smsg("%s%4d STORE %lld in $%d", pfx, current, *************** *** 5193,5201 **** + cdfunc->cdf_idx; smsg("%s%4d DCALL %s(argc %d)", pfx, current, ! df->df_ufunc->uf_name_exp != NULL ! ? df->df_ufunc->uf_name_exp ! : df->df_ufunc->uf_name, cdfunc->cdf_argcount); } break; case ISN_UCALL: --- 5211,5218 ---- + cdfunc->cdf_idx; smsg("%s%4d DCALL %s(argc %d)", pfx, current, ! printable_func_name(df->df_ufunc), ! cdfunc->cdf_argcount); } break; case ISN_UCALL: *************** *** 5662,5671 **** semsg(_(e_function_is_not_compiled_str), eap->arg); return; } ! if (ufunc->uf_name_exp != NULL) ! msg((char *)ufunc->uf_name_exp); ! else ! msg((char *)ufunc->uf_name); dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; switch (compile_type) --- 5679,5685 ---- semsg(_(e_function_is_not_compiled_str), eap->arg); return; } ! msg((char *)printable_func_name(ufunc)); dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; switch (compile_type) *** ../vim-8.2.3266/src/testdir/test_vim9_disassemble.vim 2021-07-31 22:51:06.930754925 +0200 --- src/testdir/test_vim9_disassemble.vim 2021-08-01 13:59:11.422146075 +0200 *************** *** 2241,2245 **** --- 2241,2293 ---- res) enddef + def Test_disassemble_after_reload() + var lines =<< trim END + vim9script + if exists('g:ThisFunc') + finish + endif + var name: any + def g:ThisFunc(): number + g:name = name + return 0 + enddef + def g:ThatFunc(): number + name = g:name + return 0 + enddef + END + lines->writefile('Xreload.vim') + + source Xreload.vim + g:ThisFunc() + g:ThatFunc() + + source Xreload.vim + var res = execute('disass g:ThisFunc') + assert_match('ThisFunc\_s*' .. + 'g:name = name\_s*' .. + '\d LOADSCRIPT \[deleted\] from .*/Xreload.vim\_s*' .. + '\d STOREG g:name\_s*' .. + 'return 0\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN\_s*', + res) + + res = execute('disass g:ThatFunc') + assert_match('ThatFunc\_s*' .. + 'name = g:name\_s*' .. + '\d LOADG g:name\_s*' .. + '\d STORESCRIPT \[deleted\] in .*/Xreload.vim\_s*' .. + 'return 0\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN\_s*', + res) + + delete('Xreload.vim') + delfunc g:ThisFunc + delfunc g:ThatFunc + enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker *** ../vim-8.2.3266/src/version.c 2021-08-01 13:17:12.862422853 +0200 --- src/version.c 2021-08-01 13:36:44.401448521 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3267, /**/ -- TALL KNIGHT OF NI: Ni! "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///