Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Completion segmentation fault

Was going through the backlog and noticed that this one was overlooked.

On 6 Nov 2017, at 06:48, Leah Neukirchen <leah@xxxxxxxx> wrote:
>gdb tells infinite recursion between _source, _dispatch, and _normal,
>then stack overflow.  (Entry point is from _cmdstring.)

The problem seems related to the fact that set_comp_sep() (which is called via
`compset -q` in _cmdstring) removes semi-colons and other meta-characters from
compwords (the user-land words array), but doesn't decrement compcurrent (the
user-land CURRENT integer) accordingly. Here are the results of calling
`compset -q` on command lines with and without a semicolon in the string:

  command line         | ${(qq)words} | $CURRENT
  sh -c 'source <TAB>  | 'source' ''  | 2
  sh -c 'source; <TAB> | 'source' ''  | 3

The fact that compcurrent is now greater than the length of compwords confuses
do_comp_vars() (which is called via `compset -n` in _source), such that it
doesn't think it needs to shrink compwords, and so _source loops for ever.

I was able to fix the mismatch by adding a limit on the new value of compcurrent
(see below). This prevents the crash, and puts compcurrent in the right place if
your cursor is already at the last word, which is certainly an improvement. I
can't figure out how to calculate the right position if your cursor was in the
middle of a string like this, however:

  sh -c 'a; b; ;; ;; ;; ;; <TAB> c; d;

The position here (after stripping the semi-colons) should be 3, but i'm not
sure the existing code offers me a way to see *where* the semi-colons have been
removed, just the fact that they have been. I bet someone more knowledgeable
than me could add a check or counter in the loop above, if they're inclined;
otherwise, this is at least better than before.

Some related problems that this does NOT address:

* the fact that the words array may not be accurate following a call to
  `compset -q`

* the fact that completing in the middle of a string, as in these examples...

    sh -c 'a b <TAB> c d
    GREP_OPTIONS='-A1 <TAB> -B1 -C1

  ... destroys everything following the cursor (not sure what causes this? is it
  the same code? it seems to depend on the prefix and some other things)

* the fact that `source; <TAB>` should not actually complete an argument to
  source (i don't think it was ever meant to be that smart)


diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 52b0c173f..c3b971e0d 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1901,7 +1901,8 @@ set_comp_sep(void)
 	    p = compwords[i] = (char *) getdata(n);
-	compcurrent = cur + 1;
+	/* The current position shouldn't exceed the new word count */
+	compcurrent = cur + 1 > i ? i : cur + 1;
 	compwords[i] = NULL;
     instring = ois;

Messages sorted by: Reverse Date, Date, Thread, Author