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

Re: Bug report: zsh crashes when expanding long command from history.



On Tue, Oct 20, 2015 at 10:30 AM, Bart Schaefer
<schaefer@xxxxxxxxxxxxxxxx> wrote:
> On Oct 20, 12:47pm, Dorian Haglund wrote:
> } The command is attached (it is 41111 characters long so I won't copy
> } paste it here).
>
> The history mechanism is using a short integer to track the position of
> each word in the command line, so any command line longer than the
> maximum value of a signed short is going to cause problems.

The following seems to be the most straightforward way to fix the
crash.  If we really want to be able to handle 32k+ command lines
we'll need a more invasive patch.

I suppose this might still break on a single word more than 64k
characters long, but it'll break by returning the substring of the
command line rather than by crashing.

(This diff might get garbled, I'm not using my regular email client.)

diff --git a/Src/hist.c b/Src/hist.c
index 9c42d85..50a2104 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -2254,7 +2254,7 @@ static char *
 getargs(Histent elist, int arg1, int arg2)
 {
     short *words = elist->words;
-    int pos1, nwords = elist->nwords;
+    int pos1, pos2, nwords = elist->nwords;

     if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) {
     /* remember, argN is indexed from 0, nwords is total no. of words */
@@ -2263,8 +2263,22 @@ getargs(Histent elist, int arg1, int arg2)
     return NULL;
     }

+    /* optimization for accessing entire history event */
+    if (arg1 == 0 && arg2 == nwords - 1)
+    return dupstring(elist->node.nam);
+
     pos1 = words[2*arg1];
-    return dupstrpfx(elist->node.nam + pos1, words[2*arg2+1] - pos1);
+    pos2 = words[2*arg2+1];
+
+    /* a word has to be at least one character long, so if the position
+     * of a word is less than its index, we've overflowed our signed
+     * short integer word range and the recorded position is garbage. */
+    if (pos1 < 0 || pos1 < arg1 || pos2 < 0 || pos2 < arg2) {
+    herrflush();
+    zerr("history event too long, can't index requested words");
+    return NULL;
+    }
+    return dupstrpfx(elist->node.nam + pos1, pos2 - pos1);
 }

 /**/



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