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
-~----------~----~----~----~------~----~------~--~---

Raspunde prin e-mail lui