Skip to content

Commit 6db660b

Browse files
committed
patch 8.2.3267: Vim9: crash when disassembling using deleted script variable
Problem: Vim9: crash when disassembling a function that uses a deleted script variable. Solution: Check the variable still exists. (closes #8683)
1 parent e97976b commit 6db660b

File tree

3 files changed

+94
-30
lines changed

3 files changed

+94
-30
lines changed

src/testdir/test_vim9_disassemble.vim

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,5 +2241,53 @@ def Test_disassemble_nextcmd()
22412241
res)
22422242
enddef
22432243

2244+
def Test_disassemble_after_reload()
2245+
var lines =<< trim END
2246+
vim9script
2247+
if exists('g:ThisFunc')
2248+
finish
2249+
endif
2250+
var name: any
2251+
def g:ThisFunc(): number
2252+
g:name = name
2253+
return 0
2254+
enddef
2255+
def g:ThatFunc(): number
2256+
name = g:name
2257+
return 0
2258+
enddef
2259+
END
2260+
lines->writefile('Xreload.vim')
2261+
2262+
source Xreload.vim
2263+
g:ThisFunc()
2264+
g:ThatFunc()
2265+
2266+
source Xreload.vim
2267+
var res = execute('disass g:ThisFunc')
2268+
assert_match('ThisFunc\_s*' ..
2269+
'g:name = name\_s*' ..
2270+
'\d LOADSCRIPT \[deleted\] from .*/Xreload.vim\_s*' ..
2271+
'\d STOREG g:name\_s*' ..
2272+
'return 0\_s*' ..
2273+
'\d PUSHNR 0\_s*' ..
2274+
'\d RETURN\_s*',
2275+
res)
2276+
2277+
res = execute('disass g:ThatFunc')
2278+
assert_match('ThatFunc\_s*' ..
2279+
'name = g:name\_s*' ..
2280+
'\d LOADG g:name\_s*' ..
2281+
'\d STORESCRIPT \[deleted\] in .*/Xreload.vim\_s*' ..
2282+
'return 0\_s*' ..
2283+
'\d PUSHNR 0\_s*' ..
2284+
'\d RETURN\_s*',
2285+
res)
2286+
2287+
delete('Xreload.vim')
2288+
delfunc g:ThisFunc
2289+
delfunc g:ThatFunc
2290+
enddef
2291+
22442292

22452293
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ static char *(features[]) =
755755

756756
static int included_patches[] =
757757
{ /* Add new patch number below this line */
758+
/**/
759+
3267,
758760
/**/
759761
3266,
760762
/**/

src/vim9execute.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,26 +1254,33 @@ string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive)
12541254
return vim_strnsave(str + start_byte, end_byte - start_byte);
12551255
}
12561256

1257+
/*
1258+
* Get a script variable for ISN_STORESCRIPT and ISN_LOADSCRIPT.
1259+
* When "dfunc_idx" is negative don't give an error.
1260+
* Returns NULL for an error.
1261+
*/
12571262
static svar_T *
1258-
get_script_svar(scriptref_T *sref, ectx_T *ectx)
1263+
get_script_svar(scriptref_T *sref, int dfunc_idx)
12591264
{
12601265
scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
1261-
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
1262-
+ ectx->ec_dfunc_idx;
1266+
dfunc_T *dfunc = dfunc_idx < 0 ? NULL
1267+
: ((dfunc_T *)def_functions.ga_data) + dfunc_idx;
12631268
svar_T *sv;
12641269

12651270
if (sref->sref_seq != si->sn_script_seq)
12661271
{
1267-
// The script was reloaded after the function was
1268-
// compiled, the script_idx may not be valid.
1269-
semsg(_(e_script_variable_invalid_after_reload_in_function_str),
1270-
dfunc->df_ufunc->uf_name_exp);
1272+
// The script was reloaded after the function was compiled, the
1273+
// script_idx may not be valid.
1274+
if (dfunc != NULL)
1275+
semsg(_(e_script_variable_invalid_after_reload_in_function_str),
1276+
printable_func_name(dfunc->df_ufunc));
12711277
return NULL;
12721278
}
12731279
sv = ((svar_T *)si->sn_var_vals.ga_data) + sref->sref_idx;
12741280
if (!equal_type(sv->sv_type, sref->sref_type, 0))
12751281
{
1276-
emsg(_(e_script_variable_type_changed));
1282+
if (dfunc != NULL)
1283+
emsg(_(e_script_variable_type_changed));
12771284
return NULL;
12781285
}
12791286
return sv;
@@ -1976,7 +1983,7 @@ exec_instructions(ectx_T *ectx)
19761983
scriptref_T *sref = iptr->isn_arg.script.scriptref;
19771984
svar_T *sv;
19781985

1979-
sv = get_script_svar(sref, ectx);
1986+
sv = get_script_svar(sref, ectx->ec_dfunc_idx);
19801987
if (sv == NULL)
19811988
goto theend;
19821989
allocate_if_null(sv->sv_tv);
@@ -2189,7 +2196,7 @@ exec_instructions(ectx_T *ectx)
21892196
scriptref_T *sref = iptr->isn_arg.script.scriptref;
21902197
svar_T *sv;
21912198

2192-
sv = get_script_svar(sref, ectx);
2199+
sv = get_script_svar(sref, ectx->ec_dfunc_idx);
21932200
if (sv == NULL)
21942201
goto theend;
21952202
--ectx->ec_stack.ga_len;
@@ -4942,12 +4949,16 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
49424949
break;
49434950
case ISN_LOADSCRIPT:
49444951
{
4945-
scriptref_T *sref = iptr->isn_arg.script.scriptref;
4946-
scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
4947-
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
4948-
+ sref->sref_idx;
4952+
scriptref_T *sref = iptr->isn_arg.script.scriptref;
4953+
scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
4954+
svar_T *sv;
49494955

4950-
smsg("%s%4d LOADSCRIPT %s-%d from %s", pfx, current,
4956+
sv = get_script_svar(sref, -1);
4957+
if (sv == NULL)
4958+
smsg("%s%4d LOADSCRIPT [deleted] from %s",
4959+
pfx, current, si->sn_name);
4960+
else
4961+
smsg("%s%4d LOADSCRIPT %s-%d from %s", pfx, current,
49514962
sv->sv_name,
49524963
sref->sref_idx,
49534964
si->sn_name);
@@ -4996,15 +5007,17 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
49965007
smsg("%s%4d LOADENV %s", pfx, current, iptr->isn_arg.string);
49975008
break;
49985009
case ISN_LOADREG:
4999-
smsg("%s%4d LOADREG @%c", pfx, current, (int)(iptr->isn_arg.number));
5010+
smsg("%s%4d LOADREG @%c", pfx, current,
5011+
(int)(iptr->isn_arg.number));
50005012
break;
50015013

50025014
case ISN_STORE:
50035015
if (iptr->isn_arg.number < 0)
50045016
smsg("%s%4d STORE arg[%lld]", pfx, current,
50055017
iptr->isn_arg.number + STACK_FRAME_SIZE);
50065018
else
5007-
smsg("%s%4d STORE $%lld", pfx, current, iptr->isn_arg.number);
5019+
smsg("%s%4d STORE $%lld", pfx, current,
5020+
iptr->isn_arg.number);
50085021
break;
50095022
case ISN_STOREOUTER:
50105023
{
@@ -5048,12 +5061,16 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
50485061
break;
50495062
case ISN_STORESCRIPT:
50505063
{
5051-
scriptref_T *sref = iptr->isn_arg.script.scriptref;
5052-
scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
5053-
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
5054-
+ sref->sref_idx;
5064+
scriptref_T *sref = iptr->isn_arg.script.scriptref;
5065+
scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
5066+
svar_T *sv;
50555067

5056-
smsg("%s%4d STORESCRIPT %s-%d in %s", pfx, current,
5068+
sv = get_script_svar(sref, -1);
5069+
if (sv == NULL)
5070+
smsg("%s%4d STORESCRIPT [deleted] in %s",
5071+
pfx, current, si->sn_name);
5072+
else
5073+
smsg("%s%4d STORESCRIPT %s-%d in %s", pfx, current,
50575074
sv->sv_name,
50585075
sref->sref_idx,
50595076
si->sn_name);
@@ -5067,7 +5084,8 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
50675084
smsg("%s%4d STOREENV $%s", pfx, current, iptr->isn_arg.string);
50685085
break;
50695086
case ISN_STOREREG:
5070-
smsg("%s%4d STOREREG @%c", pfx, current, (int)iptr->isn_arg.number);
5087+
smsg("%s%4d STOREREG @%c", pfx, current,
5088+
(int)iptr->isn_arg.number);
50715089
break;
50725090
case ISN_STORENR:
50735091
smsg("%s%4d STORE %lld in $%d", pfx, current,
@@ -5193,9 +5211,8 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
51935211
+ cdfunc->cdf_idx;
51945212

51955213
smsg("%s%4d DCALL %s(argc %d)", pfx, current,
5196-
df->df_ufunc->uf_name_exp != NULL
5197-
? df->df_ufunc->uf_name_exp
5198-
: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
5214+
printable_func_name(df->df_ufunc),
5215+
cdfunc->cdf_argcount);
51995216
}
52005217
break;
52015218
case ISN_UCALL:
@@ -5662,10 +5679,7 @@ ex_disassemble(exarg_T *eap)
56625679
semsg(_(e_function_is_not_compiled_str), eap->arg);
56635680
return;
56645681
}
5665-
if (ufunc->uf_name_exp != NULL)
5666-
msg((char *)ufunc->uf_name_exp);
5667-
else
5668-
msg((char *)ufunc->uf_name);
5682+
msg((char *)printable_func_name(ufunc));
56695683

56705684
dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
56715685
switch (compile_type)

0 commit comments

Comments
 (0)