Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined variable when redirecting command output into a string variable #33

Open
Yilin-Yang opened this issue May 14, 2022 · 3 comments

Comments

@Yilin-Yang
Copy link
Owner

Yilin-Yang commented May 14, 2022

Running vim-markbar's test suite keeps throwing error messages like:

"~/plugin/vim-markbar/plugin/vim-markbar.vim" line 1 of 332 --0%-- col 1
Error detected while processing function markbar#helpers#GetOpenBuffers:
line    2:
E121: Undefined variable: l:to_return

That don't seem to appear during normal use on my machine. This might be related to an issue mentioned by @mwgkgk in #3 (comment)

Relevant lines of code (that also don't reference a variable named l:to_return):

" RETURNS:  (v:t_list)      A list populated with the numbers of every
"                           buffer, listed or unlisted.
function! markbar#helpers#GetOpenBuffers() abort
    let l:buffers_str = ''
    redir => l:buffers_str
    silent ls!
    redir end

Lower down in the same file:

" RETURNS:  (v:t_string)    All buffer-local marks active within the current
"                           file as a 'raw' string.
function! markbar#helpers#GetLocalMarks() abort
    let l:to_return = ''
    try
        redir => l:to_return
        silent marks abcdefghijklmnopqrstuvwxyz[]<>'`\"^.(){}
        redir end
        let l:to_return .= "\n"

When I change the above into:

" RETURNS:  (v:t_string)    All buffer-local marks active within the current
"                           file as a 'raw' string.
function! markbar#helpers#GetLocalMarks() abort
    let l:FromGetLocalMarks = ''
    try
        redir => l:FromGetLocalMarks
        silent marks abcdefghijklmnopqrstuvwxyz[]<>'`\"^.(){}
        redir end
        let l:FromGetLocalMarks .= "\n"
    catch /E283/
        let l:FromGetLocalMarks = 'mark line  col file/text\n'
    endtry
    for l:mark in ['(',')','{','}']
        try
            let l:FromGetLocalMarks .= markbar#helpers#MakeMarkString(l:mark)."\n"
        catch
        endtry
    endfor
    return l:FromGetLocalMarks
endfunction

I see error messages like:

"10lines.txt" line 9 of 10 --90%-- col 1
Error detected while processing VimEnter Autocommands for "*"..function MarkbarVimEnter[12]..markbar#helpers#GetOpenBuffers:
line    2:
E121: Undefined variable: l:FromGetLocalMarks

And actual test failures like:

     (4/8) [     DO] (X) Vim(redir):E121: Undefined variable: l:to_return
       > command line..function <SNR>41_vader[5]..vader#run[63]..<SNR>43_run[46]..vader#window#replay[2]..<SNR>28_Apostrophe[1]..<SNR>28_OpenPeekaboo[13]..markbar#MarkbarController#openMarkbar[11]..markbar#MarkbarController#refreshContents[6]..markbar#MarkbarModel#updateCurrentAndGlobal[26]..markbar#helpers#GetLocalMarks, line 3

This occurs in both vim and neovim.

This may be an upstream issue in which the redir => command isn't properly remembering which variables were declared in which stack frames.

@Yilin-Yang
Copy link
Owner Author

Did some debugging in nvim with vim-markbar commit b6b43ca by:

  • Adding let g:foo = input('pause until something is entered') to .travis_vimrc, to make vim pause before running Vader tests,
  • Running ./run_tests.sh -v --neovim -f standalone-test-foldopen-init-false.vader -e $HOME/temp/nvim/bin/nvim, where temp/nvim/bin/nvim is a Debug build of neovim tag: v0.7.0,
  • Attaching a GDB instance (like https://github.com/neovim/neovim/wiki/FAQ#using-gdb, but using CGDB rather than "vanilla" GDB),
  • Setting a breakpoint on static void ex_redir(exarg_T *eap) in ex_docmd.c and a watchpoint on redir_vname,
  • Watching what happens right before the erroneous E121: Undefined variable message fires.

It looks like (neo)vim maintains static variables like redir_vname, which is a flag that's true when a redir => l:some_vim_variable is active; and static variables like redir_lval and redir_varname that store information about the l:some_vim_variable into which output is being redirected.

The redir_vname flag is set after a redir => inside of g:MarkbarVimEnter..MarkbarModel#updateCurrentAndGlobal..BufferCache#updateCache..helpers#GetGlobalMarks:

Thread 1 "nvim" hit Hardware watchpoint 1: redir_vname

Old value = 0
New value = 1
ex_redir (eap=0x7ffc28d5abe0) at /home/yiliny/neovim/src/nvim/ex_docmd.c:8346
8346        } else if (*arg == '=' && arg[1] == '>') {
(gdb) p *eap
$1 = {arg = 0x55d83cacdf5e "=> l:to_return", nextcmd = 0x0, cmd = 0x55d83cacdf58 "redir => l:to_return", cmdlinep = 0x7ffc28d5adf0,
  cmdidx = CMD_redir, argt = 524558, skip = 0, forceit = 0, addr_count = 0, line1 = 1, line2 = 1, addr_type = ADDR_NONE, flags = 0,
  do_ecmd_cmd = 0x0, do_ecmd_lnum = 0, append = 0, usefilter = 0, amount = 0, regname = 0, force_bin = 0, read_edit = 0,
  force_ff = 0, force_enc = 0, bad_char = 0, useridx = 0, errmsg = 0x0, getline = 0x55d83a5caece <get_func_line>,
  cookie = 0x55d83cb09740, cstack = 0x7ffc28d5af10, verbose_save = -1, save_msg_silent = -1, did_esilent = 0, did_sandbox = false}
#0  ex_redir (eap=0x7ffc28d5abe0) at /home/yiliny/neovim/src/nvim/ex_docmd.c:8346
#1  0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5adf0, flags=7, cstack=0x7ffc28d5af10,
    fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83cb09740) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#2  0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83cb09740, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#3  0x000055d83a5c558c in call_user_func (fp=0x55d83ca68920, argcount=0, argvars=0x7ffc28d5bb20, rettv=0x7ffc28d5c1e0, firstline=11,
    lastline=11, selfdict=0x0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1110
#4  0x000055d83a5c67ce in call_func (funcname=0x55d83cabab20 "markbar#helpers#GetGlobalMarks", len=30, rettv=0x7ffc28d5c1e0,
    argcount_in=0, argvars_in=0x7ffc28d5bb20, funcexe=0x7ffc28d5bce0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1576
#5  0x000055d83a5c3b84 in get_func_tv (name=0x55d83cabab20 "markbar#helpers#GetGlobalMarks", len=30, rettv=0x7ffc28d5c1e0,
    arg=0x7ffc28d5c1d8, funcexe=0x7ffc28d5bce0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:458
#6  0x000055d83a578db8 in eval_func (arg=0x7ffc28d5c1d8, name=0x55d83cacd90b "markbar#helpers#GetGlobalMarks(), '', '')",
    name_len=30, rettv=0x7ffc28d5c1e0, evaluate=true, basetv=0x0) at /home/yiliny/neovim/src/nvim/eval.c:3324
#7  0x000055d83a57abac in eval7 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1, want_string=0)
    at /home/yiliny/neovim/src/nvim/eval.c:4234
#8  0x000055d83a579f44 in eval6 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1, want_string=0)
    at /home/yiliny/neovim/src/nvim/eval.c:3912
#9  0x000055d83a57981e in eval5 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3737
#10 0x000055d83a5794eb in eval4 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3633
#11 0x000055d83a579337 in eval3 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3554
#12 0x000055d83a57918d in eval2 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3485
#13 0x000055d83a578fa3 in eval1 (arg=0x7ffc28d5c1d8, rettv=0x7ffc28d5c1e0, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3411
#14 0x000055d83a5c3a07 in get_func_tv (name=0x55d83cb0a0e0 "markbar#BufferCache#updateCache", len=-1, rettv=0x7ffc28d5c3a0,
    arg=0x7ffc28d5c370, funcexe=0x7ffc28d5c3d0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:429
#15 0x000055d83a5caa7c in ex_call (eap=0x7ffc28d5c4e0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:2993
#16 0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5c6f0, flags=7, cstack=0x7ffc28d5c810,
    fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83caa5d00) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#17 0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83caa5d00, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#18 0x000055d83a5c558c in call_user_func (fp=0x55d83ca64d10, argcount=0, argvars=0x7ffc28d5d420, rettv=0x7ffc28d5d5e0, firstline=11,
    lastline=11, selfdict=0x55d83ca4be00) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1110
#19 0x000055d83a5c67ce in call_func (funcname=0x55d83caffed0 "markbar#MarkbarModel#updateCurrentAndGlobal", len=43,
    rettv=0x7ffc28d5d5e0, argcount_in=0, argvars_in=0x7ffc28d5d420, funcexe=0x7ffc28d5d610)
    at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1576
#20 0x000055d83a5c3b84 in get_func_tv (name=0x55d83caffed0 "markbar#MarkbarModel#updateCurrentAndGlobal", len=-1,
    rettv=0x7ffc28d5d5e0, arg=0x7ffc28d5d5b0, funcexe=0x7ffc28d5d610) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:458
#21 0x000055d83a5caa7c in ex_call (eap=0x7ffc28d5d720) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:2993
#22 0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5d930, flags=7, cstack=0x7ffc28d5da50,
    fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83ca8c4a0) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#23 0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83ca8c4a0, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#24 0x000055d83a5c558c in call_user_func (fp=0x55d83ca76eb0, argcount=0, argvars=0x7ffc28d5e660, rettv=0x7ffc28d5e820, firstline=11,
    lastline=11, selfdict=0x0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1110
#25 0x000055d83a5c67ce in call_func (funcname=0x55d83cae7560 "MarkbarVimEnter", len=15, rettv=0x7ffc28d5e820, argcount_in=0,
    argvars_in=0x7ffc28d5e660, funcexe=0x7ffc28d5e850) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1576
#26 0x000055d83a5c3b84 in get_func_tv (name=0x55d83cae7560 "MarkbarVimEnter", len=-1, rettv=0x7ffc28d5e820, arg=0x7ffc28d5e7f0,
    funcexe=0x7ffc28d5e850) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:458
#27 0x000055d83a5caa7c in ex_call (eap=0x7ffc28d5e960) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:2993
#28 0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5eb70, flags=7, cstack=0x7ffc28d5ec90, fgetline=0x55d83a52f268 <getnextac>,
    cookie=0x7ffc28d5f290) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#29 0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a52f268 <getnextac>, cookie=0x7ffc28d5f290, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#30 0x000055d83a52e466 in apply_autocmds_group (event=EVENT_VIMENTER,
    fname=0x55d83cad80c0 "/home/yiliny/plugin/vim-markbar/test/[Vader]", fname_io=0x0, force=false, group=-3, buf=0x55d83cac2820,
    eap=0x0) at /home/yiliny/neovim/src/nvim/autocmd.c:1834
#31 0x000055d83a52daba in apply_autocmds (event=EVENT_VIMENTER, fname=0x0, fname_io=0x0, force=false, buf=0x55d83cac2820)
    at /home/yiliny/neovim/src/nvim/autocmd.c:1504
#32 0x000055d83a66eecb in main (argc=7, argv=0x7ffc28d5f638) at /home/yiliny/neovim/src/nvim/main.c:538

Then, before (neo)vim parses and executes a redir END that would call static void close_redir(void) // ex_docmd.c and zero the redir_vname flag, it processes another redir => from markbar#helpers#GetOpenBuffers() while executing the VimEnter autocommand from:

" plugin/vim-markbar.vim
augroup markbar_model_update
    au!
    autocmd VimEnter * call g:markbar_model.pushNewBuffer(markbar#helpers#GetOpenBuffers())
    autocmd BufEnter * call g:markbar_model.pushNewBuffer(expand('<abuf>') + 0)
    autocmd BufDelete,BufWipeout *
        \ call g:markbar_model.evictBufferCache(expand('<abuf>') + 0)
augroup end

markbar#helpers#GetOpenBuffers() does a redir => l:buffers_str, which calls ex_redir, which calls close_redir prior to starting a new redirection into l:buffers_str. But redir_varname is still l:to_return from the earlier call to markbar#helpers#GetGlobalMarks, and apparently that earlier redirection is still "in flight" when the new redirection to l:buffers_str is starting.

close_redir sees that redir_vname is 1, so it calls void var_redir_stop(void) // eval.c, which tries to look up l:to_return, and throws an E121: Undefined variable because l:to_return isn't defined in markbar#helpers#GetOpenBuffers().

(gdb) p *eap
$2 = {arg = 0x55d83cb00e5a "=> l:buffers_str", nextcmd = 0x0, cmd = 0x55d83cb00e54 "redir => l:buffers_str",
  cmdlinep = 0x7ffc28d5d270, cmdidx = CMD_redir, argt = 524558, skip = 0, forceit = 0, addr_count = 0, line1 = 1, line2 = 1,
  addr_type = ADDR_NONE, flags = 0, do_ecmd_cmd = 0x0, do_ecmd_lnum = 0, append = 0, usefilter = 0, amount = 0, regname = 0,
  force_bin = 0, read_edit = 0, force_ff = 0, force_enc = 0, bad_char = 0, useridx = 0, errmsg = 0x0,
  getline = 0x55d83a5caece <get_func_line>, cookie = 0x55d83ca8c4a0, cstack = 0x7ffc28d5d390, verbose_save = -1,
  save_msg_silent = -1, did_esilent = 0, did_sandbox = false}
(gdb) p redir_vname
$3 = 1
(gdb)
#0  ex_redir (eap=0x7ffc28d5d060) at /home/yiliny/neovim/src/nvim/ex_docmd.c:8350
#1  0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5d270, flags=7, cstack=0x7ffc28d5d390,
    fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83ca8c4a0) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#2  0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a5caece <get_func_line>, cookie=0x55d83ca8c4a0, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#3  0x000055d83a5c558c in call_user_func (fp=0x55d83ca65a90, argcount=0, argvars=0x7ffc28d5dfa0, rettv=0x7ffc28d5e660, firstline=11,
    lastline=11, selfdict=0x0) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1110
#4  0x000055d83a5c67ce in call_func (funcname=0x55d83cb00e20 "markbar#helpers#GetOpenBuffers", len=30, rettv=0x7ffc28d5e660,
    argcount_in=0, argvars_in=0x7ffc28d5dfa0, funcexe=0x7ffc28d5e160) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:1576
#5  0x000055d83a5c3b84 in get_func_tv (name=0x55d83cb00e20 "markbar#helpers#GetOpenBuffers", len=30, rettv=0x7ffc28d5e660,
    arg=0x7ffc28d5e658, funcexe=0x7ffc28d5e160) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:458
#6  0x000055d83a578db8 in eval_func (arg=0x7ffc28d5e658, name=0x55d83cac90c3 "markbar#helpers#GetOpenBuffers())", name_len=30,
    rettv=0x7ffc28d5e660, evaluate=true, basetv=0x0) at /home/yiliny/neovim/src/nvim/eval.c:3324
#7  0x000055d83a57abac in eval7 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1, want_string=0)
    at /home/yiliny/neovim/src/nvim/eval.c:4234
#8  0x000055d83a579f44 in eval6 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1, want_string=0)
    at /home/yiliny/neovim/src/nvim/eval.c:3912
#9  0x000055d83a57981e in eval5 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3737
#10 0x000055d83a5794eb in eval4 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3633
#11 0x000055d83a579337 in eval3 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3554
#12 0x000055d83a57918d in eval2 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3485
#13 0x000055d83a578fa3 in eval1 (arg=0x7ffc28d5e658, rettv=0x7ffc28d5e660, evaluate=1) at /home/yiliny/neovim/src/nvim/eval.c:3411
#14 0x000055d83a5c3a07 in get_func_tv (name=0x55d83cace8f0 "markbar#MarkbarModel#pushNewBuffer", len=-1, rettv=0x7ffc28d5e820,
    arg=0x7ffc28d5e7f0, funcexe=0x7ffc28d5e850) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:429
#15 0x000055d83a5caa7c in ex_call (eap=0x7ffc28d5e960) at /home/yiliny/neovim/src/nvim/eval/userfunc.c:2993
#16 0x000055d83a5ec8eb in do_one_cmd (cmdlinep=0x7ffc28d5eb70, flags=7, cstack=0x7ffc28d5ec90, fgetline=0x55d83a52f268 <getnextac>,
    cookie=0x7ffc28d5f290) at /home/yiliny/neovim/src/nvim/ex_docmd.c:1972
#17 0x000055d83a5e97b0 in do_cmdline (cmdline=0x0, fgetline=0x55d83a52f268 <getnextac>, cookie=0x7ffc28d5f290, flags=7)
    at /home/yiliny/neovim/src/nvim/ex_docmd.c:595
#18 0x000055d83a52e466 in apply_autocmds_group (event=EVENT_VIMENTER,
    fname=0x55d83cad80c0 "/home/yiliny/plugin/vim-markbar/test/[Vader]", fname_io=0x0, force=false, group=-3, buf=0x55d83cac2820,
    eap=0x0) at /home/yiliny/neovim/src/nvim/autocmd.c:1834
#19 0x000055d83a52daba in apply_autocmds (event=EVENT_VIMENTER, fname=0x0, fname_io=0x0, force=false, buf=0x55d83cac2820)
    at /home/yiliny/neovim/src/nvim/autocmd.c:1504
#20 0x000055d83a66eecb in main (argc=7, argv=0x7ffc28d5f638) at /home/yiliny/neovim/src/nvim/main.c:538

tl;dr it looks like autocommands can interrupt/"interleave" with earlier autocommands as those earlier autocommands are still executing a redir => variable redirection, i.e. (neo)vim's autocommand logic may be interfering with its redir => variable redirection.

Commenting out autocmd VimEnter * call g:markbar_model.pushNewBuffer(markbar#helpers#GetOpenBuffers()) silences the E121: Undefined variable error message in standalone-test-foldopen-init-false.vader but not in some other tests, like standalone-test-foldopen.vader. That suggests that it's a broader issue with autocommands in general, not just VimEnter specifically.

Yilin-Yang added a commit that referenced this issue Jun 24, 2022
Work around Issue #33, in which a call like `redir => l:buffer_str` will
throw an error message like `E121: Undefined variable: l:to_return`
because (neo)vim didn't process another function call's `redir END`.

If we're always redirecting into a variable named `l:redir_output`, then
the variable lookup won't fail and spit out an error message.

Also remove a superfluous VimEnter autocommand, because "interleaving"
autocommands seem to be the source of the wonky redir behavior.
Yilin-Yang added a commit that referenced this issue Jun 24, 2022
Work around Issue #33, in which a call like `redir => l:buffer_str` will
throw an error message like `E121: Undefined variable: l:to_return`
because (neo)vim didn't process another function call's `redir END`.

If we're always redirecting into a variable named `l:redir_output`, then
the variable lookup won't fail and spit out an error message.

Also remove a superfluous VimEnter autocommand, because "interleaving"
autocommands seem to be the source of the wonky redir behavior.
@Yilin-Yang
Copy link
Owner Author

Always using the same name for the variable storing redir => output is a quick-and-dirty fix for the error message.

The underlying issue in (neo)vim still exists, but it doesn't seem to affect markbar's functionality (the markbar still works), so the error message is our main concern for now. The error message shouldn't crop up again unless some other plugin's autocommands interleave with vim-markbar's.

(If you're a user and encounter this error message, please post about that here!)

Yilin-Yang added a commit that referenced this issue Jun 24, 2022
The erroneous E121 from #33 only fires once after a `redir =>`, so we
can try-catch it, and then just try the same `redir =>` again.
Yilin-Yang added a commit that referenced this issue Jun 24, 2022
The erroneous E121 from #33 only fires once after a `redir =>`, so we
can try-catch it, and then just try the same `redir =>` again.
Yilin-Yang added a commit that referenced this issue Jun 24, 2022
The erroneous E121 from #33 only fires once after a `redir =>`, so we
can try-catch it, and then just try the same `redir =>` again.
@Yilin-Yang
Copy link
Owner Author

Yilin-Yang commented Jun 25, 2022

Repeated my debugging process from earlier, but with vim v8.2.5157 instead of neovim.

  1. Checked out commit b6b43ca of vim-markbar,
  2. Added let g:foo = input('pause until something is entered') to .travis_vimrc to make vim pause before running Vader tests,
  3. Ran ./run_tests.sh -v -e ~/temp/vim/usr/local/bin/vim -f standalone-test-foldopen-init-false.vader, where ~/.../bin/vim is a build of vim v8.2.5157 with debugging symbols,
  4. Attached a GDB instance like cgdb -- -p 28086 ~/temp/vim/usr/local/bin/vim, where 28086 is the PID of the ~/.../bin/vim instance from (3),
  5. Set a watchpoint on redir_vname and ran continue,
  6. Pressed ENTER to make vim move past the input prompt from 2,
  7. Hit the redir_vname watchpoint 5 times, set a breakpoint on var_redir_stop(), then ran continue one more time,

From inside var_redir_stop(),

(gdb) p *redir_lval
$3 = {ll_name = 0x55ad464a04f0 "l:to_return", ll_name_end = 0x55ad464a04fb "", ll_type = 0x0, ll_exp_name = 0x0, ll_sid = 0,
  ll_tv = 0x0, ll_li = 0x0, ll_list = 0x0, ll_range = 0, ll_empty2 = 0, ll_n1 = 0, ll_n2 = 0, ll_dict = 0x0, ll_di = 0x0,
  ll_newkey = 0x0, ll_valtype = 0x0, ll_blob = 0x0}
#0  var_redir_stop () at evalvars.c:4507
#1  0x000055ad4481f9ca in close_redir () at ex_docmd.c:8444
#2  0x000055ad4481f72f in ex_redir (eap=0x7ffeb89e5280) at ex_docmd.c:8318
#3  0x000055ad4481465a in do_one_cmd (cmdlinep=0x7ffeb89e54b0, flags=7, cstack=0x7ffeb89e5590,
    fgetline=0x55ad449eb804 <get_func_line>, cookie=0x55ad46451ec0) at ex_docmd.c:2570
#4  0x000055ad4481156c in do_cmdline (cmdline=0x0, fgetline=0x55ad449eb804 <get_func_line>, cookie=0x55ad46451ec0, flags=7)
    at ex_docmd.c:992
#5  0x000055ad449e4f1d in call_user_func (fp=0x55ad46408b10, argcount=0, argvars=0x7ffeb89e6430, rettv=0x7ffeb89e6de0,
    funcexe=0x7ffeb89e6610, selfdict=0x0) at userfunc.c:2900
#6  0x000055ad449e5551 in call_user_func_check (fp=0x55ad46408b10, argcount=0, argvars=0x7ffeb89e6430, rettv=0x7ffeb89e6de0,
    funcexe=0x7ffeb89e6610, selfdict=0x0) at userfunc.c:3057
#7  0x000055ad449e660b in call_func (funcname=0x55ad464cd440 "markbar#helpers#GetOpenBuffers())", len=30, rettv=0x7ffeb89e6de0,
    argcount_in=0, argvars_in=0x7ffeb89e6430, funcexe=0x7ffeb89e6610) at userfunc.c:3613
#8  0x000055ad449e28a7 in get_func_tv (name=0x55ad464cd440 "markbar#helpers#GetOpenBuffers())", len=30, rettv=0x7ffeb89e6de0,
    arg=0x7ffeb89e6dd8, evalarg=0x7ffeb89e7040, funcexe=0x7ffeb89e6610) at userfunc.c:1833
#9  0x000055ad447dc98b in eval_func (arg=0x7ffeb89e6dd8, evalarg=0x7ffeb89e7040,
    name=0x55ad46471483 "markbar#helpers#GetOpenBuffers())", name_len=30, rettv=0x7ffeb89e6de0, flags=1, basetv=0x0) at eval.c:2113
#10 0x000055ad447e088f in eval9 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040, want_string=0) at eval.c:4027
#11 0x000055ad447dfb61 in eval8 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040, want_string=0) at eval.c:3596
#12 0x000055ad447df595 in eval7 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040, want_string=0) at eval.c:3388
#13 0x000055ad447deccd in eval6 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:3151
#14 0x000055ad447de976 in eval5 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:3040
#15 0x000055ad447de441 in eval4 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:2891
#16 0x000055ad447ddf50 in eval3 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:2752
#17 0x000055ad447dda78 in eval2 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:2626
#18 0x000055ad447dd323 in eval1 (arg=0x7ffeb89e6dd8, rettv=0x7ffeb89e6de0, evalarg=0x7ffeb89e7040) at eval.c:2472
#19 0x000055ad449e25dd in get_func_tv (name=0x55ad464cd3c0 "markbar#MarkbarModel#pushNewBuffer", len=-1, rettv=0x7ffeb89e6fc0,
    arg=0x7ffeb89e6f88, evalarg=0x7ffeb89e7040, funcexe=0x7ffeb89e6ff0) at userfunc.c:1779
#20 0x000055ad449eb2eb in ex_call (eap=0x7ffeb89e7190) at userfunc.c:5594
#21 0x000055ad4481465a in do_one_cmd (cmdlinep=0x7ffeb89e73c0, flags=7, cstack=0x7ffeb89e74a0, fgetline=0x55ad4478a5e4 <getnextac>,
    cookie=0x7ffeb89e7bf0) at ex_docmd.c:2570
#22 0x000055ad4481156c in do_cmdline (cmdline=0x0, fgetline=0x55ad4478a5e4 <getnextac>, cookie=0x7ffeb89e7bf0, flags=7)
    at ex_docmd.c:992
#23 0x000055ad44789f39 in apply_autocmds_group (event=EVENT_VIMENTER,
    fname=0x55ad464a24b0 "/home/yiliny/plugin/vim-markbar/test/[Vader]", fname_io=0x0, force=0, group=-3, buf=0x55ad4648df40,
    eap=0x0) at autocmd.c:2218
#24 0x000055ad4478948a in apply_autocmds (event=EVENT_VIMENTER, fname=0x0, fname_io=0x0, force=0, buf=0x55ad4648df40)
    at autocmd.c:1701
#25 0x000055ad44a6a093 in vim_main2 () at main.c:812
#26 0x000055ad44a69976 in main (argc=7, argv=0x7ffeb89e7e68) at main.c:432

From the stackframe for ex_redir(), exarg_T *eap is set to:

(gdb) p *eap
$4 = {arg = 0x55ad46472a6a "=> l:buffers_str", nextcmd = 0x0, cmd = 0x55ad46472a64 "redir => l:buffers_str",
  cmdlinep = 0x7ffeb89e54b0, cmdline_tofree = 0x0, cmdidx = CMD_redir, argt = 17301774, skip = 0, forceit = 0, addr_count = 0,
  line1 = 1, line2 = 1, addr_type = ADDR_NONE, flags = 0, do_ecmd_cmd = 0x0, do_ecmd_lnum = 0, append = 0, usefilter = 0,
  amount = 0, regname = 0, force_bin = 0, read_edit = 0, force_ff = 0, force_enc = 0, bad_char = 0, useridx = 0, errmsg = 0x0,
  getline = 0x55ad449eb804 <get_func_line>, cookie = 0x55ad46451ec0, cstack = 0x7ffeb89e5590}

vim throws:

"10lines.txt" line 9 of 10 --90%-- col 1
Error detected while processing VimEnter Autocommands for "*"..function markbar#helpers#GetOpenBuffers:
line    2:
E121: Undefined variable: l:to_return
Press ENTER or type command to continue

It looks like close_redir() was never called for the redirect statements in GetLocalMarks/GetGlobalMarks, maybe(?) because autocommands for VimEnter fired before that close_redir() call corresponding to redir end could be executed.

EDIT: In #38 (comment), the E121 is thrown after the user tries opening the markbar, not after an autocommand fires. This probably isn't an issue with autocommands specifically.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant