Two more memory leak fixes, on error paths I didn't spot in r9919.
[u/mdw/putty] / unix / uxproxy.c
index b441b80..f808a67 100644 (file)
@@ -29,6 +29,7 @@ struct Socket_localproxy_tag {
 
     bufchain pending_output_data;
     bufchain pending_input_data;
+    enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;
 
     void *privptr;
 };
@@ -95,12 +96,14 @@ static void sk_localproxy_close (Socket s)
 {
     Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
 
-    del234(localproxy_by_fromfd, ps);
-    del234(localproxy_by_tofd, ps);
+    if (ps->to_cmd >= 0) {
+        del234(localproxy_by_tofd, ps);
+        uxsel_del(ps->to_cmd);
+        close(ps->to_cmd);
+    }
 
-    uxsel_del(ps->to_cmd);
+    del234(localproxy_by_fromfd, ps);
     uxsel_del(ps->from_cmd);
-    close(ps->to_cmd);
     close(ps->from_cmd);
 
     sfree(ps);
@@ -129,6 +132,14 @@ static int localproxy_try_send(Local_Proxy_Socket ps)
        }
     }
 
+    if (ps->outgoingeof == EOF_PENDING) {
+        del234(localproxy_by_tofd, ps);
+        close(ps->to_cmd);
+        uxsel_del(ps->to_cmd);
+        ps->to_cmd = -1;
+        ps->outgoingeof = EOF_SENT;
+    }
+
     if (bufchain_size(&ps->pending_output_data) == 0)
        uxsel_del(ps->to_cmd);
     else
@@ -141,6 +152,8 @@ static int sk_localproxy_write (Socket s, const char *data, int len)
 {
     Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
 
+    assert(ps->outgoingeof == EOF_NO);
+
     bufchain_add(&ps->pending_output_data, data, len);
 
     localproxy_try_send(ps);
@@ -157,6 +170,16 @@ static int sk_localproxy_write_oob (Socket s, const char *data, int len)
     return sk_localproxy_write(s, data, len);
 }
 
+static void sk_localproxy_write_eof (Socket s)
+{
+    Local_Proxy_Socket ps = (Local_Proxy_Socket) s;
+
+    assert(ps->outgoingeof == EOF_NO);
+    ps->outgoingeof = EOF_PENDING;
+
+    localproxy_try_send(ps);
+}
+
 static void sk_localproxy_flush (Socket s)
 {
     /* Local_Proxy_Socket ps = (Local_Proxy_Socket) s; */
@@ -233,6 +256,7 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
        sk_localproxy_close,
        sk_localproxy_write,
        sk_localproxy_write_oob,
+       sk_localproxy_write_eof,
        sk_localproxy_flush,
        sk_localproxy_set_private_ptr,
        sk_localproxy_get_private_ptr,
@@ -252,6 +276,7 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
     ret->fn = &socket_fn_table;
     ret->plug = plug;
     ret->error = NULL;
+    ret->outgoingeof = EOF_NO;
 
     bufchain_init(&ret->pending_input_data);
     bufchain_init(&ret->pending_output_data);
@@ -263,6 +288,7 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
     if (pipe(to_cmd_pipe) < 0 ||
        pipe(from_cmd_pipe) < 0) {
        ret->error = dupprintf("pipe: %s", strerror(errno));
+        sfree(cmd);
        return (Socket)ret;
     }
     cloexec(to_cmd_pipe[1]);
@@ -272,6 +298,7 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
 
     if (pid < 0) {
        ret->error = dupprintf("fork: %s", strerror(errno));
+        sfree(cmd);
        return (Socket)ret;
     } else if (pid == 0) {
        close(0);
@@ -280,8 +307,8 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
        dup2(from_cmd_pipe[1], 1);
        close(to_cmd_pipe[0]);
        close(from_cmd_pipe[1]);
-       fcntl(0, F_SETFD, 0);
-       fcntl(1, F_SETFD, 0);
+       noncloexec(0);
+       noncloexec(1);
        execl("/bin/sh", "sh", "-c", cmd, (void *)NULL);
        _exit(255);
     }