[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1458824294-29733-2-git-send-email-jslaby@suse.cz>
Date: Thu, 24 Mar 2016 13:58:14 +0100
From: Jiri Slaby <jslaby@...e.cz>
To: akpm@...ux-foundation.org
Cc: linux-kernel@...r.kernel.org, Jiri Slaby <jslaby@...e.cz>
Subject: [PATCH 4/4] fork: free thread in copy_process on failure
When using this program (as root):
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/types.h>
#include <sys/wait.h>
#define ITER 1000
#define FORKERS 15
#define THREADS (6000/FORKERS) // 1850 is proc max
static void fork_100_wait()
{
unsigned a, to_wait = 0;
printf("\t%d forking %d\n", THREADS, getpid());
for (a = 0; a < THREADS; a++) {
switch (fork()) {
case 0:
usleep(1000);
exit(0);
break;
case -1:
break;
default:
to_wait++;
break;
}
}
printf("\t%d forked from %d, waiting for %d\n", THREADS, getpid(),
to_wait);
for (a = 0; a < to_wait; a++)
wait(NULL);
printf("\t%d waited from %d\n", THREADS, getpid());
}
static void run_forkers()
{
pid_t forkers[FORKERS];
unsigned a;
for (a = 0; a < FORKERS; a++) {
switch ((forkers[a] = fork())) {
case 0:
fork_100_wait();
exit(0);
break;
case -1:
err(1, "DIE fork of %d'th forker", a);
break;
default:
break;
}
}
for (a = 0; a < FORKERS; a++)
waitpid(forkers[a], NULL, 0);
}
int main()
{
unsigned a;
int ret;
ret = ioperm(10, 20, 0);
if (ret < 0)
err(1, "ioperm");
for (a = 0; a < ITER; a++)
run_forkers();
return 0;
}
kmemleak reports many occurences of this leak:
unreferenced object 0xffff8805917c8000 (size 8192):
comm "fork-leak", pid 2932, jiffies 4295354292 (age 1871.028s)
hex dump (first 32 bytes):
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
backtrace:
[<ffffffff814cfbf5>] kmemdup+0x25/0x50
[<ffffffff8103ab43>] copy_thread_tls+0x6c3/0x9a0
[<ffffffff81150174>] copy_process+0x1a84/0x5790
[<ffffffff811dc375>] wake_up_new_task+0x2d5/0x6f0
[<ffffffff8115411d>] _do_fork+0x12d/0x820
...
Make sure the memory is freed when fork fails later in copy_process.
This is done by calling exit_thread with the thread to kill.
Signed-off-by: Jiri Slaby <jslaby@...e.cz>
---
kernel/fork.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index d277e83ed3e0..0ac98c9ea15e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1470,7 +1470,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
pid = alloc_pid(p->nsproxy->pid_ns_for_children);
if (IS_ERR(pid)) {
retval = PTR_ERR(pid);
- goto bad_fork_cleanup_io;
+ goto bad_fork_cleanup_thread;
}
}
@@ -1632,6 +1632,8 @@ bad_fork_cancel_cgroup:
bad_fork_free_pid:
if (pid != &init_struct_pid)
free_pid(pid);
+bad_fork_cleanup_thread:
+ exit_thread(p);
bad_fork_cleanup_io:
if (p->io_context)
exit_io_context(p);
--
2.7.4
Powered by blists - more mailing lists