The free callback could end up being fired before the done callback
authornicm <nicm@openbsd.org>
Tue, 21 Apr 2015 21:31:02 +0000 (21:31 +0000)
committernicm <nicm@openbsd.org>
Tue, 21 Apr 2015 21:31:02 +0000 (21:31 +0000)
(happens on Cygwin), so use a reference count instead of a single
flag. SF bug 188 reported by "iceboy".

usr.bin/tmux/cmd-if-shell.c

index 857d862..3456449 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-if-shell.c,v 1.30 2015/04/21 15:18:06 nicm Exp $ */
+/* $OpenBSD: cmd-if-shell.c,v 1.31 2015/04/21 21:31:02 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -51,7 +51,7 @@ struct cmd_if_shell_data {
        struct mouse_event       mouse;
 
        int                      bflag;
-       int                      started;
+       int                      references;
 };
 
 enum cmd_retval
@@ -113,11 +113,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
 
        cdata->bflag = args_has(args, 'b');
 
-       cdata->started = 0;
        cdata->cmdq = cmdq;
        memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
        cmdq->references++;
 
+       cdata->references = 1;
        job_run(shellcmd, s, cmd_if_shell_callback, cmd_if_shell_free, cdata);
        free(shellcmd);
 
@@ -152,12 +152,11 @@ cmd_if_shell_callback(struct job *job)
                return;
        }
 
-       cdata->started = 1;
-
        cmdq1 = cmdq_new(cmdq->client);
        cmdq1->emptyfn = cmd_if_shell_done;
        cmdq1->data = cdata;
 
+       cdata->references++;
        cmdq_run(cmdq1, cmdlist, &cdata->mouse);
        cmd_list_free(cmdlist);
 }
@@ -170,12 +169,14 @@ cmd_if_shell_done(struct cmd_q *cmdq1)
 
        if (cmdq1->client_exit >= 0)
                cmdq->client_exit = cmdq1->client_exit;
+       cmdq_free(cmdq1);
+
+       if (--cdata->references != 0)
+               return;
 
        if (!cmdq_free(cmdq) && !cdata->bflag)
                cmdq_continue(cmdq);
 
-       cmdq_free(cmdq1);
-
        free(cdata->cmd_else);
        free(cdata->cmd_if);
        free(cdata);
@@ -187,7 +188,7 @@ cmd_if_shell_free(void *data)
        struct cmd_if_shell_data        *cdata = data;
        struct cmd_q                    *cmdq = cdata->cmdq;
 
-       if (cdata->started)
+       if (--cdata->references != 0)
                return;
 
        if (!cmdq_free(cmdq) && !cdata->bflag)