Fix an invalid free() in command handlers.
authorAndre Noll <maan@systemlinux.org>
Sun, 26 Apr 2009 16:08:13 +0000 (18:08 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 26 Apr 2009 16:08:13 +0000 (18:08 +0200)
The chunk table and the info_string are pointers located in the mmd
struct that point to dynamically allocated memory that must be freed
by the parent and the child. However, as the mmd struct is in a shared
memory area, there's no guarantee that after the fork these pointers
are still valid in child context. As these two pointers are not used
in the child anyway, we save them to local variables and free the
memory via that copy in the child.

This gets rid of

*** glibc detected *** para_server (serving 127.0.0.1#53650): double free or corruption (!prev): 0x08086fe0 ***

command.c
server.c

index d08a718..698e275 100644 (file)
--- a/command.c
+++ b/command.c
@@ -792,8 +792,6 @@ __noreturn void handle_connect(int fd, const char *peername)
        ret = cmd->handler(fd, argc, argv);
        mutex_lock(mmd_mutex);
        mmd->num_commands++;
-       free(mmd->afd.afhi.info_string);
-       free(mmd->afd.afhi.chunk_table);
        mutex_unlock(mmd_mutex);
        if (ret >= 0)
                goto out;
index 1e4caf0..a4115eb 100644 (file)
--- a/server.c
+++ b/server.c
@@ -352,6 +352,8 @@ static void command_post_select(struct sched *s, struct task *t)
        int new_fd, ret, i;
        char *peer_name;
        pid_t child_pid;
+       uint32_t *chunk_table;
+       char *info_string;
 
        if (!FD_ISSET(sct->listen_fd, &s->rfds))
                return;
@@ -364,6 +366,16 @@ static void command_post_select(struct sched *s, struct task *t)
        mmd->num_connects++;
        mmd->active_connections++;
        random();
+       /* The chunk table and the info_string are pointers located in the
+        * mmd struct that point to dynamically allocated memory that must be
+        * freed by the parent and the child. However, as the mmd struct is in
+        * a shared memory area, there's no guarantee that after the fork these
+        * pointers are still valid in child context. As these two pointers are
+        * not used in the child anyway, we save them to local variables and
+        * free the memory via that copy in the child.
+        */
+       info_string = mmd->afd.afhi.info_string;
+       chunk_table = mmd->afd.afhi.chunk_table;
        child_pid = fork();
        if (child_pid < 0) {
                ret = -ERRNO_TO_PARA_ERROR(errno);
@@ -374,6 +386,9 @@ static void command_post_select(struct sched *s, struct task *t)
                /* parent keeps accepting connections */
                return;
        }
+       /* mmd might already have changed at this point */
+       free(info_string);
+       free(chunk_table);
        alarm(ALARM_TIMEOUT);
        close_listed_fds();
        para_signal_shutdown();