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

Weird completion bug in Src/Zle/compmatch.c#bld_line

Hi zsh-workers,

TL;DR Using openlog(...) (from syslog.h) at the beginning and closelog() at the end of Src/Zle/compmatch.c#bld_line(...) solves a weird completion bug.


I feel a little bit like Alice — although this message is not sent to Bob.

As you can read from the threads [1,2], I was looking for the White Rabbit, and Bart Schaefer helped me track him down to Src/Zle/compmatch.c. And the rabbit hole runs deep: 2900 lines! So I was gazing through the looking glass of Zsh C routines, and I was wondering how to log stuff from over there.

Unfortunately, no one can believe what the fix is: you have to see it for yourself. Jun kindly suggested I should use a file descriptor to another TTY, and Bart mentioned dputs. But I first tried with syslog(3), and I started tumbling down the rabbit hole.

syslog(3) actually solved the bug. No kidding. You take the red pill, we stay in Wonderland, and I will show you.


Since it initially got posted on zsh-users, let me summarize the bug for you. It originates from that case-insensitive substring-matching completion style I heard about from the Cheshire cat:

zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'l:|=* r:|=*'

The bug occurs when a completion leads to multiple completion choices, under the following conditions:
* completion choices are all the same length;
* completion choices share a common suffix;
* that suffix is at least half of the length but not the full length;
* in each choice, the first and the n-th character of the suffix are both letters, where n is the length of the prefix;
* in each choice, the character just before the common suffix is a digit (or some other non-letter character, like an underscore, or the Queen of Hearts), and that character is different for each choice.

The Hatter told me that the above list of conditions looked like "quantum mechanics". I myself agree with the Duchess: "he only does it to annoy / because he knows it teases".

Under the above conditions, the bug happens when completing after a substring prefixing the common suffix (i.e. completing after "a" or "al" or ... or "alice", when the common suffix is "alice").

Expected behavior: the suffix gets completed. The Duchess and her baby sneeze.

Actual behavior: the suffix gets completed, but a letter is inserted before the suffix. This letter is the n-th character of the suffix, in inverted case. The baby changes into a pig.

Example 1: in a directory containing two files "1abc" and "2abc", completing after ": a" will expand it to "abc" and then add an extra "A", so the command line will look like ": Aabc".

Example 2: on a table with a cake saying "__eat_me_please" and a bottle saying "drink%me_please", completing after ": me_p" will expand it to "me_please" and then add an extra "E", so the command line will look like ": Eme_please".


Now that you know the bug, on to what I have tried so far. I have been working on version 5.0.2, where the bld_line function is in Src/Zle/compmatch.c at lines 1669-1920. By the way, debugging a 350-line-long function fells like swimming in a pool made of my own tears.

So first, I started by #include-ing <syslog.h> and logging parameters in the first lines of the bld_line function, like so:

syslog(LOG_WARNING,"lpat: %s",lpat->u.str);

Compiles fine, logs fine. Great. But then I think "hey, in a minute I am gonna want to log stuff all over the place, let me close the log at the end of the function instead".

So I move the "closelog();" call to the end of the function, and I duplicate it because the bld_line function actually has four return statements. And, like that: poof... he's gone! — I mean that the bug disappeared just because I closed the log at the end of the function!!!

Moreover, the "syslog(...);" call is irrelevant! Simply calling "openlog" at the beginning of the routine, and "closelog" before each return statement, fixes the bug. WAT? So I included a patch, you can show it to you friends and have a good laugh.

Attachment: zsh-5.0.2-compmatch.patch
Description: Binary data

Either my gcc is making fun of me, or... it finally happened, happened, I'm slightly maaaaaaad. What is going on? I thought I did not drink any of his special tea... his specialty... Why is a raven like a writing desk?


Sorry about the Carroll-esque tone, I could not help it — maybe I am indeed slightly mad. If you know why syslog(3) fixes the bug, or if you have any insight about what is happening here, I will be happy to hear from you.

Cheers guys.

Nicolas Canceill

[1] http://www.zsh.org/mla/users/2014/threads.html#0061
[2] http://www.zsh.org/mla/workers/2014/threads.html#00534

Le 8 juin 2014 à 17:47, Jun T. <takimoto-j@xxxxxxxxxxxxxxxxx> a écrit :

> 2014/06/08 19:25, nicolas.canceill <nicolas.canceill@xxxxxxxxxxx> wrote:
>>  ... so I prefer to log a bunch of stuff from within the C functions.
> How about writing to the tty of another window?
> Open a terminal window, and use the 'tty' command to show the device name
> of the tty of this window:
> $ tty
> /dev/ttys002
> Then open another terminal window, edit the source code to add lines like
>    FILE *mylog = fopen("/dev/ttys002", "w");
>    ...
>    fprintf(mylog, "log/debug info....\n");
> and build/run the program.

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