mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 9.0.1357: using null_object results in an internal error
Problem: Using null_object results in an internal error. (Ernie Rael) Solution: Add instructions for pushing an object and class. (closes #12044)
This commit is contained in:
parent
4f026ea9f1
commit
c4e1b86cb0
@ -3449,3 +3449,7 @@ EXTERN char e_using_null_object[]
|
|||||||
#endif
|
#endif
|
||||||
EXTERN char e_cannot_use_color_none_did_you_mean_none[]
|
EXTERN char e_cannot_use_color_none_did_you_mean_none[]
|
||||||
INIT(= N_("E1361: Cannot use color \"none\", did you mean \"NONE\"?"));
|
INIT(= N_("E1361: Cannot use color \"none\", did you mean \"NONE\"?"));
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
EXTERN char e_cannot_use_non_null_object[]
|
||||||
|
INIT(= N_("E1362: Cannot use a non-null object"));
|
||||||
|
#endif
|
||||||
|
@ -186,6 +186,23 @@ def Test_class_defined_twice()
|
|||||||
source XclassTwice.vim
|
source XclassTwice.vim
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_returning_null_object()
|
||||||
|
# this was causing an internal error
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
class BufferList
|
||||||
|
def Current(): any
|
||||||
|
return null_object
|
||||||
|
enddef
|
||||||
|
endclass
|
||||||
|
|
||||||
|
var buffers = BufferList.new()
|
||||||
|
echo buffers.Current()
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
def Test_class_interface_wrong_end()
|
def Test_class_interface_wrong_end()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1357,
|
||||||
/**/
|
/**/
|
||||||
1356,
|
1356,
|
||||||
/**/
|
/**/
|
||||||
|
@ -101,6 +101,8 @@ typedef enum {
|
|||||||
ISN_PUSHFUNC, // push func isn_arg.string
|
ISN_PUSHFUNC, // push func isn_arg.string
|
||||||
ISN_PUSHCHANNEL, // push NULL channel
|
ISN_PUSHCHANNEL, // push NULL channel
|
||||||
ISN_PUSHJOB, // push NULL job
|
ISN_PUSHJOB, // push NULL job
|
||||||
|
ISN_PUSHOBJ, // push NULL object
|
||||||
|
ISN_PUSHCLASS, // push class, uses isn_arg.class
|
||||||
ISN_NEWLIST, // push list from stack items, size is isn_arg.number
|
ISN_NEWLIST, // push list from stack items, size is isn_arg.number
|
||||||
// -1 for null_list
|
// -1 for null_list
|
||||||
ISN_NEWDICT, // push dict from stack items, size is isn_arg.number
|
ISN_NEWDICT, // push dict from stack items, size is isn_arg.number
|
||||||
@ -518,6 +520,7 @@ struct isn_S {
|
|||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
job_T *job;
|
job_T *job;
|
||||||
partial_T *partial;
|
partial_T *partial;
|
||||||
|
class_T *class;
|
||||||
jump_T jump;
|
jump_T jump;
|
||||||
jumparg_T jumparg;
|
jumparg_T jumparg;
|
||||||
forloop_T forloop;
|
forloop_T forloop;
|
||||||
|
@ -1944,8 +1944,7 @@ exec_command(isn_T *iptr)
|
|||||||
source_cookie_T cookie;
|
source_cookie_T cookie;
|
||||||
|
|
||||||
SOURCING_LNUM = iptr->isn_lnum;
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
// Pass getsourceline to get an error for a missing ":end"
|
// Pass getsourceline to get an error for a missing ":end" command.
|
||||||
// command.
|
|
||||||
CLEAR_FIELD(cookie);
|
CLEAR_FIELD(cookie);
|
||||||
cookie.sourcing_lnum = iptr->isn_lnum - 1;
|
cookie.sourcing_lnum = iptr->isn_lnum - 1;
|
||||||
if (do_cmdline(iptr->isn_arg.string,
|
if (do_cmdline(iptr->isn_arg.string,
|
||||||
@ -4018,6 +4017,8 @@ exec_instructions(ectx_T *ectx)
|
|||||||
case ISN_PUSHFUNC:
|
case ISN_PUSHFUNC:
|
||||||
case ISN_PUSHCHANNEL:
|
case ISN_PUSHCHANNEL:
|
||||||
case ISN_PUSHJOB:
|
case ISN_PUSHJOB:
|
||||||
|
case ISN_PUSHOBJ:
|
||||||
|
case ISN_PUSHCLASS:
|
||||||
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
||||||
goto theend;
|
goto theend;
|
||||||
tv = STACK_TV_BOT(0);
|
tv = STACK_TV_BOT(0);
|
||||||
@ -4064,6 +4065,14 @@ exec_instructions(ectx_T *ectx)
|
|||||||
tv->vval.v_job = NULL;
|
tv->vval.v_job = NULL;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case ISN_PUSHOBJ:
|
||||||
|
tv->v_type = VAR_OBJECT;
|
||||||
|
tv->vval.v_object = NULL;
|
||||||
|
break;
|
||||||
|
case ISN_PUSHCLASS:
|
||||||
|
tv->v_type = VAR_CLASS;
|
||||||
|
tv->vval.v_class = iptr->isn_arg.class;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
tv->v_type = VAR_STRING;
|
tv->v_type = VAR_STRING;
|
||||||
tv->vval.v_string = iptr->isn_arg.string == NULL
|
tv->vval.v_string = iptr->isn_arg.string == NULL
|
||||||
@ -6662,6 +6671,14 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
smsg("%s%4d PUSHJOB \"no process\"", pfx, current);
|
smsg("%s%4d PUSHJOB \"no process\"", pfx, current);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
case ISN_PUSHOBJ:
|
||||||
|
smsg("%s%4d PUSHOBJ null", pfx, current);
|
||||||
|
break;
|
||||||
|
case ISN_PUSHCLASS:
|
||||||
|
smsg("%s%4d PUSHCLASS %s", pfx, current,
|
||||||
|
iptr->isn_arg.class == NULL ? "null"
|
||||||
|
: (char *)iptr->isn_arg.class->class_name);
|
||||||
|
break;
|
||||||
case ISN_PUSHEXC:
|
case ISN_PUSHEXC:
|
||||||
smsg("%s%4d PUSH v:exception", pfx, current);
|
smsg("%s%4d PUSH v:exception", pfx, current);
|
||||||
break;
|
break;
|
||||||
|
@ -655,6 +655,35 @@ generate_SETTYPE(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_PUSHOBJ instruction. Object is always NULL.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
generate_PUSHOBJ(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
if (generate_instr_type(cctx, ISN_PUSHOBJ, &t_any) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_PUSHCLASS instruction. "class" can be NULL.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
generate_PUSHCLASS(cctx_T *cctx, class_T *class)
|
||||||
|
{
|
||||||
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
isn_T *isn = generate_instr_type(cctx, ISN_PUSHCLASS,
|
||||||
|
class == NULL ? &t_any : &class->class_type);
|
||||||
|
if (isn == NULL)
|
||||||
|
return FAIL;
|
||||||
|
isn->isn_arg.class = class;
|
||||||
|
if (class != NULL)
|
||||||
|
++class->class_refcount;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a PUSH instruction for "tv".
|
* Generate a PUSH instruction for "tv".
|
||||||
* "tv" will be consumed or cleared.
|
* "tv" will be consumed or cleared.
|
||||||
@ -718,6 +747,17 @@ generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
|
|||||||
generate_PUSHS(cctx, &tv->vval.v_string);
|
generate_PUSHS(cctx, &tv->vval.v_string);
|
||||||
tv->vval.v_string = NULL;
|
tv->vval.v_string = NULL;
|
||||||
break;
|
break;
|
||||||
|
case VAR_OBJECT:
|
||||||
|
if (tv->vval.v_object != NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_cannot_use_non_null_object));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
generate_PUSHOBJ(cctx);
|
||||||
|
break;
|
||||||
|
case VAR_CLASS:
|
||||||
|
generate_PUSHCLASS(cctx, tv->vval.v_class);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
siemsg("constant type %d not supported", tv->v_type);
|
siemsg("constant type %d not supported", tv->v_type);
|
||||||
clear_tv(tv);
|
clear_tv(tv);
|
||||||
@ -1937,7 +1977,8 @@ generate_PCALL(
|
|||||||
ret_type = &t_any;
|
ret_type = &t_any;
|
||||||
else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
|
else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
|
||||||
{
|
{
|
||||||
if (check_func_args_from_type(cctx, type, argcount, at_top, name) == FAIL)
|
if (check_func_args_from_type(cctx, type, argcount, at_top, name)
|
||||||
|
== FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
ret_type = type->tt_member;
|
ret_type = type->tt_member;
|
||||||
@ -2467,6 +2508,10 @@ delete_instr(isn_T *isn)
|
|||||||
blob_unref(isn->isn_arg.blob);
|
blob_unref(isn->isn_arg.blob);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ISN_PUSHCLASS:
|
||||||
|
class_unref(isn->isn_arg.class);
|
||||||
|
break;
|
||||||
|
|
||||||
case ISN_UCALL:
|
case ISN_UCALL:
|
||||||
vim_free(isn->isn_arg.ufunc.cuf_name);
|
vim_free(isn->isn_arg.ufunc.cuf_name);
|
||||||
break;
|
break;
|
||||||
@ -2659,6 +2704,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_PUSHF:
|
case ISN_PUSHF:
|
||||||
case ISN_PUSHJOB:
|
case ISN_PUSHJOB:
|
||||||
case ISN_PUSHNR:
|
case ISN_PUSHNR:
|
||||||
|
case ISN_PUSHOBJ:
|
||||||
case ISN_PUSHSPEC:
|
case ISN_PUSHSPEC:
|
||||||
case ISN_PUT:
|
case ISN_PUT:
|
||||||
case ISN_REDIREND:
|
case ISN_REDIREND:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user