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

Re: Segfault with zsh 5.2



On Mon, 7 Dec 2015 14:01:57 +0100
Christian Neukirchen <chneukirchen@xxxxxxxxx> wrote:
>   zle-line-init() {
>     BUFFER="$ICMD"
>     zle accept-line
>     zle -D zle-line-init
>   }

I couldn't get your crash to happen easily, and the crash
actually happened in a normal alloc high up in the execution tree so
doesn't give us much direct help apart from pointing at memory
management.  (The call was protected by signal queueing, by the way.)

However, there's definitely something very dodgy in memory management
for the code above.  It's always been this way, so I think the fact it's
just shown up is an accident.  I couldn't get valgrind to show it up,
for some reason, but the evidence from gdb is incontrovertible.

Does the following help?  Unless I've screwed up it needs committing
anyway.

(I hope the widget flags aren't so heavily overloaded now as to make
this unsafe.)

pws

diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 2d672de..e9b1428 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -213,6 +213,8 @@ struct widget {
 #define ZLE_KEEPSUFFIX	(1<<9)	/* DON'T remove added suffix */
 #define ZLE_NOTCOMMAND  (1<<10)	/* widget should not alter lastcmd */
 #define ZLE_ISCOMP      (1<<11)	/* usable for new style completion */
+#define WIDGET_INUSE    (1<<12) /* widget is in use */
+#define WIDGET_FREE     (1<<13) /* request to free when no longer in use */
 
 /* thingies */
 
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 38427e8..1f0c07d 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1344,6 +1344,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
 	    eofsent = 1;
 	    ret = 1;
 	} else {
+	    int inuse = wflags & WIDGET_INUSE;
+	    w->flags |= WIDGET_INUSE;
 	    if(!(wflags & ZLE_KEEPSUFFIX))
 		removesuffix();
 	    if(!(wflags & ZLE_MENUCMP)) {
@@ -1367,6 +1369,12 @@ execzlefunc(Thingy func, char **args, int set_bindk)
 		ret = w->u.fn(args);
 		unqueue_signals();
 	    }
+	    if (!inuse) {
+		if (w->flags & WIDGET_FREE)
+		    freewidget(w);
+		else
+		    w->flags &= ~WIDGET_INUSE;
+	    }
 	    if (!(wflags & ZLE_NOTCOMMAND))
 		lastcmd = wflags;
 	}
@@ -1387,6 +1395,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
 	    int osc = sfcontext, osi = movefd(0);
 	    int oxt = isset(XTRACE);
 	    LinkList largs = NULL;
+	    int inuse = w->flags & WIDGET_INUSE;
+	    w->flags |= WIDGET_INUSE;
 
 	    if (*args) {
 		largs = newlinklist();
@@ -1402,8 +1412,15 @@ execzlefunc(Thingy func, char **args, int set_bindk)
 	    opts[XTRACE] = oxt;
 	    sfcontext = osc;
 	    endparamscope();
-	    lastcmd = w->flags;
-	    w->flags = 0;
+	    lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE);
+	    if (inuse) {
+		w->flags &= WIDGET_INUSE|WIDGET_FREE;
+	    } else {
+		if (w->flags & WIDGET_FREE)
+		    freewidget(w);
+		else
+		    w->flags = 0;
+	    }
 	    r = 1;
 	    redup(osi, 0);
 	}
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 271fd8e..21495b6 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -253,9 +253,14 @@ unbindwidget(Thingy t, int override)
 /* Free a widget. */
 
 /**/
-static void
+void
 freewidget(Widget w)
 {
+    if (w->flags & WIDGET_INUSE) {
+	w->flags |= WIDGET_FREE;
+	return;
+    }
+
     if (w->flags & WIDGET_NCOMP) {
 	zsfree(w->u.comp.wid);
 	zsfree(w->u.comp.func);




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