bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug gprof/19904] New: SIGPROF keeps a large task from ever completing a


From: paulo.cesar.pereira.de.andrade at gmail dot com
Subject: [Bug gprof/19904] New: SIGPROF keeps a large task from ever completing a fork()
Date: Mon, 04 Apr 2016 13:03:05 +0000

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 <address@hidden>
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(&current->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.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]