Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm
Precedence: bulk
X-No-Archive: yes
List-Id: Zsh Workers List <zsh-workers.zsh.org>
List-Post: <mailto:zsh-workers@zsh.org>
List-Help: <mailto:zsh-workers-help@zsh.org>
X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au
X-Spam-Level: 
X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_DKIM_INVALID
	autolearn=ham autolearn_force=no version=3.4.1
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=brasslantern-com.20150623.gappssmtp.com; s=20150623;
        h=from:message-id:date:in-reply-to:comments:references:to:subject
         :mime-version;
        bh=sIVDigVARV0WGLet5xPXceMlK2NCrDaA7SnJ+0l3I7Q=;
        b=1nuQRLpmyaXAX29vnRjwDHZWlR9E4ZYpEjevBHGFvlX2EEHquH5Fg4vrJOZwxHgV8e
         JeI7VHeZ2Cs4HQJBwcgMh7Kxn/4JavarErlFJPYLKVykWURbWZM6XCBQIAldQ54X8gSx
         44tWJwW0a3DT5qJioJCV9TGUYkNquefqyu8Pk22Api/wejKUnCoJBB9tzowKlM42gEWt
         ngWOs5z0/ZKtkcb3GMaTw131KbXGzky/zsHHe1cl+fuuz0J4RJ1+LBdyzEbUTA1dNiI/
         u8aH0OjDWqgUz+VVNBy8n7LuMiOeFesiMq9To9A2RPZXs3PNudKjggwG2DRzlIMtoXrB
         U3WQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:from:message-id:date:in-reply-to:comments
         :references:to:subject:mime-version;
        bh=sIVDigVARV0WGLet5xPXceMlK2NCrDaA7SnJ+0l3I7Q=;
        b=H7eDckUVc12HshhqKoPKlPfvOCGsR4DiVUAE6k1q0Y7fS5KKmykktQBhNdJdR0CfBK
         H+s2G8w0a4Ni2z+1Ws5bT+h2eZvEvJc/CM34Tn4mmjW59voibCDeqZ6Myvqqz3Zdk7nO
         B2r/0THgA3RaWg+SsAuJlrXOki8BGGEvjSMdab9fQ8cBeoEY64qekb/ihfIMQ9qj9faB
         jgHc/xggpmAMxyrPhmAJ2URmBBibnqe4fFzTHOW7QOZlKtUz0Z2lkTrNfX95nWnChN8n
         oZ7xTwr1cK4eVTcICO6pEdbaiPDl8yutRyp6sIC7YqqJMbG0VYN86H0oQpMUbR1yrtI/
         ieUQ==
X-Gm-Message-State: AD7BkJJG+JRWwOPQ8ydFn+QEvvdpgLosQJMA5LgPC5r+/8/5TveEawOIDSfv/+b1+1lhRQ==
X-Received: by 10.98.8.74 with SMTP id c71mr39621511pfd.155.1458494322315;
        Sun, 20 Mar 2016 10:18:42 -0700 (PDT)
From: Bart Schaefer <schaefer@brasslantern.com>
Message-Id: <160320101910.ZM8306@torch.brasslantern.com>
Date: Sun, 20 Mar 2016 10:19:10 -0700
In-Reply-To: <CAKzW8okOFzO=ZNdi4HkKuQDnDdqAkQELmXGYJ3XSoho_kvJNzw@mail.gmail.com>
Comments: In reply to comic fans <comicfans44@gmail.com>
        "access already freed memory when resize window" (Mar 20,  9:57pm)
References: <CAKzW8okOFzO=ZNdi4HkKuQDnDdqAkQELmXGYJ3XSoho_kvJNzw@mail.gmail.com>
X-Mailer: OpenZMail Classic (0.9.2 24April2005)
To: zsh-workers@zsh.org
Subject: Re: access already freed memory when resize window
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Seq: zsh-workers 38191

This appears to be happening because the PROMPTSUBST option is set and
one of the prompt variables contains a $(...) command substitution.

When the $(...) is executed during prompt expansion, zsh waits for the
command to exit, which allows a second SIGWINCH to be handled, which
in turn redisplays the prompt again before it has finished expanding.
I can trivially reproduce from zsh -f with:

torch% setopt promptsubst 
torch% PS1='$(<<<$SECONDS) '"$PS1"

and then resize the window.  The reexpandprompt() routine has a guard
against re-entering this way, but that doesn't help because the global
pointer has been freed and even if reexpandprompt() is skipped other
parts of the ZLE redraw may access it.

It doesn't even help to queue signals, because waiting for the command
substitution to finish must temporarily unqueue them.

This is especially nasty because lpromptbuf has to be correctly set in
order for rpromptbuf to be correctly computed, so if the user is wildly
dragging the window border around there is no instant at which we are
guaranteed to be able to leave the two of them in proper sync with both
the window size and each other -- unless we do something unpleasant like
attempting to sleep with SIGWINCH blocked until the user has finished
goofing around.

The following appears to be the next best thing, but I think it could
still leave us one SIGWINCH short of a full paint job.


diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 6e2bfde..104e5d6 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1856,6 +1856,7 @@ void
 reexpandprompt(void)
 {
     static int reexpanding;
+    static int looping;
 
     if (!reexpanding++) {
 	/*
@@ -1866,15 +1867,33 @@ reexpandprompt(void)
 	int local_lastval = lastval;
 	lastval = pre_zle_status;
 
-	free(lpromptbuf);
-	lpromptbuf = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
-				  &pmpt_attr);
-	rpmpt_attr = pmpt_attr;
-	free(rpromptbuf);
-	rpromptbuf = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
-				  &rpmpt_attr);
+	do {
+	    /* A new SIGWINCH may arrive while in promptexpand(), causing
+	     * looping to increment.  This only happens when a command
+	     * substitution is used in a PROMPT_SUBST prompt, but
+	     * nevertheless keep trying until we see no more changes.
+	     */
+	    char *new_lprompt, *new_rprompt;
+	    looping = reexpanding;
+
+	    new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
+				       &pmpt_attr);
+	    free(lpromptbuf);
+	    lpromptbuf = new_lprompt;
+
+	    if (looping != reexpanding)
+		continue;
+
+	    rpmpt_attr = pmpt_attr;
+	    new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
+				       &rpmpt_attr);
+	    free(rpromptbuf);
+	    rpromptbuf = new_rprompt;
+	} while (looping != reexpanding);
+
 	lastval = local_lastval;
-    }
+    } else
+	looping = reexpanding;
     reexpanding--;
 }
 

