From a8afcca04eb47360e4b900ebe13bfbe3e1c16cd2 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 13 Apr 2020 08:41:16 +0000 Subject: [PATCH] simplified hawk::call(). fixed a bug in copying a value for a reference upon returning from a function in hawk_rtx_evalcall(). it was unable to handle the case where a reference variable is not updated in the called function --- hawk/lib/mod-hawk.c | 52 ++++++++++++++++--------------- hawk/lib/parse.c | 4 +-- hawk/lib/run.c | 75 ++++++++++++++++++++++++++++++--------------- hawk/lib/val.c | 2 +- 4 files changed, 81 insertions(+), 52 deletions(-) diff --git a/hawk/lib/mod-hawk.c b/hawk/lib/mod-hawk.c index 540181f6..f1cddf21 100644 --- a/hawk/lib/mod-hawk.c +++ b/hawk/lib/mod-hawk.c @@ -27,8 +27,13 @@ #include "mod-hawk.h" #include "hawk-prv.h" +/* + * function abc(a, b, c) { return a + b + c; } + * BEGIN { print hawk::call("abc", 10, 20, 30); } + */ struct pafs_t { + hawk_fun_t* fun; hawk_oow_t stack_base; hawk_oow_t start_index; hawk_oow_t end_index; @@ -37,7 +42,7 @@ struct pafs_t static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data) { struct pafs_t* pasf = (struct pafs_t*)data; - hawk_oow_t org_stack_base, i; + hawk_oow_t org_stack_base, spec_len, i, j; hawk_val_t* v; if (HAWK_RTX_STACK_AVAIL(rtx) < pasf->end_index - pasf->start_index + 1) @@ -46,13 +51,21 @@ static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call return (hawk_oow_t)-1; } + spec_len = pasf->fun->argspec? hawk_count_oocstr(pasf->fun->argspec): 0; + org_stack_base = rtx->stack_base; - for (i = pasf->start_index; i <= pasf->end_index; i++) + for (i = pasf->start_index, j = 0; i <= pasf->end_index; i++, j++) { rtx->stack_base = pasf->stack_base; v = HAWK_RTX_STACK_ARG(rtx, i); rtx->stack_base = org_stack_base; + if (j < spec_len && pasf->fun->argspec[j] == 'r' && HAWK_RTX_GETVALTYPE(rtx, v) != HAWK_VAL_REF) + { + hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ENOTREF); + return (hawk_oow_t)-1; + } + HAWK_RTX_STACK_PUSH (rtx, v); hawk_rtx_refupval (rtx, v); } @@ -66,45 +79,36 @@ static int fnc_call (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) hawk_oow_t nargs; hawk_nde_fncall_t call; struct pafs_t pafs; - hawk_val_t* v, * a0; - int rx = -1; + hawk_val_t* v; /* this function is similar to hawk_rtx_callfun() but it is more simplified */ - a0 = hawk_rtx_getarg(rtx, 0); - - fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 1)); - if (!fun) goto done; + fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 0)); + if (!fun) return -1; /* hard failure */ nargs = hawk_rtx_getnargs(rtx); - if (nargs - 2 > fun->nargs) + if (nargs - 1 > fun->nargs) { - /*hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM); - return HAWK_NULL;*/ - goto done; + hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM); + return -1; /* hard failure */ } HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call)); call.type = HAWK_NDE_FNCALL_FUN; call.u.fun.name = fun->name; - call.nargs = nargs - 2; + call.nargs = nargs - 1; /* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() knows it's a fake call structure */ - call.arg_base = rtx->stack_base + 6; /* 6 = 4(stack frame prologue) + 2(the first two arguments to hawk::call()) */ + call.arg_base = rtx->stack_base + 5; /* 5 = 4(stack frame prologue) + 1(the first argument to hawk::call()) */ + pafs.fun = fun; pafs.stack_base = rtx->stack_base; - pafs.start_index = 2; + pafs.start_index = 1; pafs.end_index = nargs - 1; v = hawk_rtx_evalcall(rtx, &call, fun, push_args_from_stack, (void*)&pafs, HAWK_NULL, HAWK_NULL); - if (HAWK_LIKELY(v)) - { - hawk_rtx_refupval (rtx, v); - rx = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)a0, v); - hawk_rtx_refdownval (rtx, v); - } + if (HAWK_UNLIKELY(!v)) return -1; /* hard failure */ -done: - hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, rx)); + hawk_rtx_setretval (rtx, v); return 0; } @@ -188,7 +192,7 @@ struct inttab_t static fnctab_t fnctab[] = { /* keep this table sorted for binary search in query(). */ - { HAWK_T("call"), { { 2, A_MAX, HAWK_T("rvR") }, fnc_call, 0 } }, + { HAWK_T("call"), { { 1, A_MAX, HAWK_T("vR") }, fnc_call, 0 } }, { HAWK_T("gc"), { { 0, 1, HAWK_NULL }, fnc_gc, 0 } }, { HAWK_T("gc_get_threshold"), { { 1, 1, HAWK_NULL }, fnc_gc_get_threshold, 0 } }, { HAWK_T("gc_set_threshold"), { { 2, 2, HAWK_NULL }, fnc_gc_set_threshold, 0 } } diff --git a/hawk/lib/parse.c b/hawk/lib/parse.c index 68cbf4d2..79c9e189 100644 --- a/hawk/lib/parse.c +++ b/hawk/lib/parse.c @@ -1454,14 +1454,13 @@ static hawk_nde_t* parse_function (hawk_t* awk) nargs = HAWK_ARR_SIZE(awk->parse.params); if (nargs >= argspeccapa) { - hawk_oow_t i, newcapa = HAWK_ALIGN_POW2(nargs + 1, 64); + hawk_oow_t i, newcapa = HAWK_ALIGN_POW2(nargs + 2, 64); argspec = hawk_reallocmem(awk, argspec, newcapa * HAWK_SIZEOF(*argspec)); if (!argspec) goto oops; for (i = argspeccapa; i < newcapa; i++) argspec[i] = HAWK_T(' '); argspeccapa = newcapa; } argspec[nargs] = 'r'; - argspec[nargs + 1] = '\0'; if (get_token(awk) <= -1) goto oops; } @@ -1522,6 +1521,7 @@ static hawk_nde_t* parse_function (hawk_t* awk) while (MATCH(awk,TOK_NEWLINE)); } + if (argspec) argspec[nargs + 1] = '\0'; if (get_token(awk) <= -1) goto oops; } diff --git a/hawk/lib/run.c b/hawk/lib/run.c index 3f973521..7a628322 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -6124,27 +6124,44 @@ hawk_val_t* hawk_rtx_evalcall ( { hawk_val_t** ref; hawk_val_ref_t refv; + hawk_val_t* av; int r; - /* if an argument passed is a local variable or a parameter to the previous caller, - * the argument node information stored is relative to the previous stack frame. - * i revert rtx->stack_base to the previous stack frame base before calling - * get_reference() and restors it back to the current base. this tactic - * is very ugly because the assumptions for this is depecallnt on get_reference() - * implementation */ - rtx->stack_base = prev_stack_base; /* UGLY */ - r = get_reference(rtx, p, &ref); - rtx->stack_base = cur_stack_base; /* UGLY */ - - /* if argspec is 'r', get_reference() must succeed all the time. - * if argspec is 'R', it may fail. if it happens, don't copy the value */ - if (HAWK_LIKELY(r >= 0)) + av = HAWK_RTX_STACK_ARG(rtx, i); + if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF) { - HAWK_RTX_INIT_REF_VAL (&refv, p->type - HAWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */ - if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, &refv, HAWK_RTX_STACK_ARG(rtx, i)) <= -1)) + /* the argument still has the reference type. + * this means, the argument has not been set. + * + * function f1(&a, &b) { b = 20 } + * + * since a is not set in f1, the value for a is still the pushed value which is a reference + */ + + /* ---- DO NOTHING ---- */ + } + else + { + /* if an argument passed is a local variable or a parameter to the previous caller, + * the argument node information stored is relative to the previous stack frame. + * i revert rtx->stack_base to the previous stack frame base before calling + * get_reference() and restors it back to the current base. this tactic + * is very ugly because the assumptions for this is depecallnt on get_reference() + * implementation */ + rtx->stack_base = prev_stack_base; /* UGLY */ + r = get_reference(rtx, p, &ref); + rtx->stack_base = cur_stack_base; /* UGLY */ + + /* if argspec is 'r', get_reference() must succeed all the time. + * if argspec is 'R', it may fail. if it happens, don't copy the value */ + if (HAWK_LIKELY(r >= 0)) { - n = -1; - ADJERR_LOC (rtx, &call->loc); + HAWK_RTX_INIT_REF_VAL (&refv, p->type - HAWK_NDE_NAMED, ref, 9); /* initialize a fake reference variable. 9 chosen randomly */ + if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, &refv, av) <= -1)) + { + n = -1; + ADJERR_LOC (rtx, &call->loc); + } } } } @@ -6157,8 +6174,8 @@ hawk_val_t* hawk_rtx_evalcall ( { /* * function f1(a,&b) { b *= 20; } - * BEGIN { q = 4; hawk::call(r, "f1", 20, q); print q; -* } + * BEGIN { q = 4; hawk::call(r, "f1", 20, q); print q; } + * * the fourth argument to hawk::call() must map to the second argument to f1(). * hawk::call() accepts the third to the last arguments as reference if possible. * this function attempts to copy back the pass-by-reference values to @@ -6171,15 +6188,23 @@ hawk_val_t* hawk_rtx_evalcall ( { if (n >= 0 && (fun->argspec[i] == 'r' || fun->argspec[i] == 'R')) { - hawk_val_t* v; + hawk_val_t* v, * av; - v = rtx->stack[call->arg_base + i]; /* UGLY */ - if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF) + av = HAWK_RTX_STACK_ARG(rtx, i); + if (HAWK_RTX_GETVALTYPE(rtx, av) == HAWK_VAL_REF) { - if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)v, HAWK_RTX_STACK_ARG(rtx, i)) <= -1)) + /* ---- DO NOTHING ---- */ + } + else + { + v = rtx->stack[call->arg_base + i]; /* UGLY */ + if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF) { - n = -1; - ADJERR_LOC (rtx, &call->loc); + if (HAWK_UNLIKELY(hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)v, av) <= -1)) + { + n = -1; + ADJERR_LOC (rtx, &call->loc); + } } } } diff --git a/hawk/lib/val.c b/hawk/lib/val.c index f04fe4c9..ca35f6d4 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -2465,7 +2465,7 @@ hawk_val_t* hawk_rtx_getrefval (hawk_rtx_t* rtx, hawk_val_ref_t* ref) int hawk_rtx_setrefval (hawk_rtx_t* rtx, hawk_val_ref_t* ref, hawk_val_t* val) { - hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE (rtx, val); + hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val); if (vtype == HAWK_VAL_REX || vtype == HAWK_VAL_REF) {