https://sourceware.org/bugzilla/show_bug.cgi?id=19904
Bug ID: 19904 Summary: SIGPROF keeps a large task from ever completing a fork() Product: binutils Version: unspecified Status: NEW Severity: normal Priority: P2 Component: gprof Assignee: unassigned at sourceware dot org Reporter: paulo.cesar.pereira.de.andrade at gmail dot com Target Milestone: --- A program can be built to cause a -pg built binary to enter an infinite loop in fork call, due to not finishing the syscall before the signal is sent again, entering an infinite loop restarting the syscall. Testing user provided test case: """ # cat test.cpp #include <stdlib.h> #include <stdio.h> #include <unistd.h> int main(int argc, char ** argv) { int a1l, a2l, i, j, pid; double ** p; double * q; a1l = atoi(argv[1]); a2l = atoi(argv[2]); p = (double**)malloc(a1l * sizeof(double*)); for (i = 0; i < a1l; i++) { q = (double*)malloc(a2l * sizeof(double)); for (j = 0; j < a2l; j++) q[j] = (double) j; p[i] = q; } printf("Forking!\n"); fflush(stdout); pid = fork(); printf("Fork returns...\n"); switch (pid) { case -1: printf("Parent: fork failed\n"); perror("fork"); break; case 0: printf("Son: fork succeeded, pid = %d\n", getpid()); break; default: printf("Parent: fork succeeded, pid = %d\n", pid); } return 0; } # g++ -o ./test -g -pg -Wunused -Wall test.cpp # ./bin/test 1000 200000 """ Previously RHEL5 had a patch to workaround it, to the correct gprof issue in kernel: """ commit 122c17ac54c9b3f53e80bc6f0786cc5f2a8dc486 Author: Stefan Ring <s...@visotech.at> Date: Fri May 8 13:19:55 2015 +0200 the patch (v2.6.18) diff --git a/include/linux/sched.h b/include/linux/sched.h index 34ed0d9..808f79d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1478,6 +1478,7 @@ static inline int lock_need_resched(spinlock_t *lock) extern FASTCALL(void recalc_sigpending_tsk(struct task_struct *t)); extern void recalc_sigpending(void); +extern int fork_recalc_sigpending(void); extern void signal_wake_up(struct task_struct *t, int resume_stopped); diff --git a/kernel/fork.c b/kernel/fork.c index f9b014e..21f9a0d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1193,8 +1193,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, * A fatal signal pending means that current will exit, so the new * thread can't slip out of an OOM kill (or normal SIGKILL). */ - recalc_sigpending(); - if (signal_pending(current)) { + if (fork_recalc_sigpending()) { spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -ERESTARTNOINTR; diff --git a/kernel/signal.c b/kernel/signal.c index bfdb568..bd7e794 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -227,6 +227,31 @@ void recalc_sigpending(void) recalc_sigpending_tsk(current); } +int fork_recalc_sigpending(void) +{ + struct task_struct *tsk = current; + int pending; + + recalc_sigpending(); + if (likely(!signal_pending(tsk))) + return 0; + + pending = 1; + /* + * HACK. If SIGPROF is the sole reason for TIF_SIGPENDING + * we assume it was sent by ITIMER_PROF and return false, + * otherwise fork() can never succeed if it takes more than + * it_prof_incr. bz645528. + */ + if (!sigismember(&tsk->blocked, SIGPROF)) { + sigaddset(&tsk->blocked, SIGPROF); + pending = recalc_sigpending_tsk(tsk); + sigdelset(&tsk->blocked, SIGPROF); + } + + return pending; +} + /* Given the mask, find the first available signal that should be serviced. */ static int """ This patch/hack is not in upstream neither in newer RHEL. Users were suggested to switch to perf, but gprof should be still an useful tool, e.g. for non x86 architectures. It was suggested to block SIGPROF during the clone syscall in glibc, but that would become overkill as well. The proper solution should be to applications built with -pg to somehow block it, and likely, have an option of which syscalls to block, in case syscalls other than clone could cause the infinite loop. -- You are receiving this mail because: You are on the CC list for the bug. _______________________________________________ bug-binutils mailing list bug-binutils@gnu.org https://lists.gnu.org/mailman/listinfo/bug-binutils