On 17/12/08 13:34, Bram Moolenaar wrote: > > Dominique Pelle wrote: > >> 2008/12/16 Bram Moolenaar<b...@moolenaar.net>: >>> >>> Matt Wozniski wrote: >>> >>>> function! ReturnArgs(...) >>>> return a:000 >>>> endfunction >>>> >>>> " Seems to work fine? >>>> echo ReturnArgs(1, 2, 3) >>>> >>>> " SEGV >>>> echo string(ReturnArgs(1, 2, 3)) >>>> >>>> function! MakeArgsDict(...) >>>> return { 'args': a:000 } >>>> endfunction >>>> >>>> " E685 Internal Error >>>> echo MakeArgsDict(1, 2, 3) >>>> >>>> " SEGV >>>> echo string(MakeArgsDict(1, 2, 3)) >>> For it crashes a while after trying these things. Most likely the >>> reference count for a:000 is wrong. Never thought of someone returning >>> it... >> When I debugged, I found that v_list was pointing to an invalid address, >> which had been set in call_user_func() to&fc.l_varlist; This variable is >> in the stack and was only valid while in call_user_func() and the functions >> it >> may calls. Somehow, a list still refers to this address after returning from >> call_user_func() so v_list points then to an invalid address. >> >> Making variable fc static (in function call_user_func()) avoids using an >> invalid address and thus avoids a crash, but it's still not the right way >> to fix it. >> >>> " Seems to work fine? >>> echo ReturnArgs(1, 2, 3) >> Actually, even though this appears to work, valgrind memory checker >> already sees a problem there: >> >> ==23275== Invalid read of size 4 >> ==23275== at 0x809C577: echo_string (eval.c:7232) >> ==23275== by 0x80AD48C: ex_echo (eval.c:19481) >> ==23275== by 0x80C71C6: do_one_cmd (ex_docmd.c:2622) >> ==23275== by 0x80C4A46: do_cmdline (ex_docmd.c:1096) >> ==23275== by 0x8149D7A: nv_colon (normal.c:5233) >> ==23275== by 0x81433FE: normal_cmd (normal.c:1200) >> ==23275== by 0x810678D: main_loop (main.c:1180) >> ==23275== by 0x81062DA: main (main.c:939) >> ==23275== Address 0xbef5e280 is not stack'd, malloc'd or (recently) free'd >> ==23275== >> ==23275== Invalid write of size 4 >> ==23275== at 0x809C59D: echo_string (eval.c:7239) >> ==23275== by 0x80AD48C: ex_echo (eval.c:19481) >> ==23275== by 0x80C71C6: do_one_cmd (ex_docmd.c:2622) >> ==23275== by 0x80C4A46: do_cmdline (ex_docmd.c:1096) >> ==23275== by 0x8149D7A: nv_colon (normal.c:5233) >> ==23275== by 0x81433FE: normal_cmd (normal.c:1200) >> ==23275== by 0x810678D: main_loop (main.c:1180) >> ==23275== by 0x81062DA: main (main.c:939) >> ==23275== Address 0xbef5e280 is not stack'd, malloc'd or (recently) free'd >> >> (etc, more errors to follow) >> >> Line eval.c:7232 is: >> >> 7232 else if (copyID != 0&& tv->vval.v_list->lv_copyID == >> copyID) >> 7233 { >> 7234 *tofree = NULL; >> 7235 r = (char_u *)"[...]"; >> 7236 } >> >> 'tv->vval.v_list' points to the invalid address which set as there >> at line 21193: >> >> 21191 v->di_tv.v_type = VAR_LIST; >> 21192 v->di_tv.v_lock = VAR_FIXED; >> 21193 v->di_tv.vval.v_list =&fc.l_varlist; >> >> (fc being a local var in the stack) > > What is happening here is that a few things are put on the stack to > avoid malloc()/free() calls. These are quite expensive and adds > overhead to every function call. > > The reference count of these are not used. When the function returns, > the items automatically disappear. That's a bit of a problem if you > return the value or assigned it to a global variable. > > I think the only proper solution is to do that malloc()/free(). > Not only for a:000, but also for l: and a:. And all elements > contained in them, that's going to be time consuming. > > Another method would be to disallow passing these dictionaries to > outside the function scope. One would have to make a copy instead. > Checking for this may be complicated though. And this also doesn't > solve the problem for variables such as a:firstline that are also on the > stack. > > It looks like the best solution is to put the whole funccall_T in > allocated memory. And only free it when all the reference counts are > back to zero. Need to make a list of them and add some code to the > garbage collector. >
When returning a Number (e.g. ":return a:lastline") or a Float, I suppose the return method guarantees that there'll be no problem. I'm less certain about returning a String variable local to the function, but I suppose existing code already provides for that. A Funcref to a function defined inside the function should remain valid -- or does it? But what we're talking about here is when the returned object is a List or Dictionary containing (at any level of depth) something local to the function, which would disappear at return-time. (Returning a pointer to a _global_ List or Dictionary ought to be no problem if no local elements or sub-elements have been added by the function.) Proposed solution: returning a List or Dictionary local to the function is forbidden (and generates an error). But what about returning a List or Dictionary containing _elements_ local to the function? Maybe nondestructively check (recursively, but breaking out on first error). The user can of course catch the error by wrapping the return statement in a try block (if he wants to), triggering a deepcopy() to a global variable if caught. Alternative solution: returning a List or Dictionary actually returns a global deepcopy(). But this would impair performance, and it might have other unobvious consequences. Best regards, Tony. -- GUARD #1: What, ridden on a horse? ARTHUR: Yes! GUARD #1: You're using coconuts! ARTHUR: What? GUARD #1: You've got two empty halves of coconut and you're bangin' 'em together. The Quest for the Holy Grail (Monty Python) --~--~---------~--~----~------------~-------~--~----~ You received this message from the "vim_dev" maillist. For more information, visit http://www.vim.org/maillist.php -~----------~----~----~----~------~----~------~--~---