From: Johannes Kliemann <kliem...@adacore.com>

The QNX Certified Products Defect Notification from February 2025
mentions a potential memory leak when pthread_create is interrupted by a
signal. It recommends to disable signals for this function call.

gcc/ada/ChangeLog:

        * adaint.c: Add functions to disable and enable signals on QNX.
        * libgnarl/s-taprop__qnx.adb (Create_Task): Disable
        signals when calling pthread_create.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/adaint.c                   | 63 ++++++++++++++++++++++++++++++
 gcc/ada/libgnarl/s-taprop__qnx.adb | 24 ++++++++++--
 2 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c
index adc39517280a..7b78d91e0e72 100644
--- a/gcc/ada/adaint.c
+++ b/gcc/ada/adaint.c
@@ -107,6 +107,7 @@
 #ifdef __QNX__
 #include <sys/syspage.h>
 #include <sys/time.h>
+#include <signal.h>
 #endif
 
 #ifdef IN_RTS
@@ -3719,6 +3720,68 @@ void __gnat_killprocesstree (int pid, int sig_num)
   */
 }
 
+#if defined (__QNX__)
+
+static __thread sigset_t set;
+static __thread sigset_t oset;
+static __thread int signals_disabled = 0;
+
+int __gnat_disable_signals(void)
+{
+    sigemptyset(&set);
+    sigaddset(&set, SIGHUP);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGQUIT);
+    sigaddset(&set, SIGILL);
+    sigaddset(&set, SIGTRAP);
+    sigaddset(&set, SIGIOT);
+    sigaddset(&set, SIGABRT);
+    sigaddset(&set, SIGEMT);
+    sigaddset(&set, SIGDEADLK);
+    sigaddset(&set, SIGFPE);
+    sigaddset(&set, SIGKILL);
+    sigaddset(&set, SIGBUS);
+    sigaddset(&set, SIGSEGV);
+    sigaddset(&set, SIGSYS);
+    sigaddset(&set, SIGPIPE);
+    sigaddset(&set, SIGALRM);
+    sigaddset(&set, SIGTERM);
+    sigaddset(&set, SIGUSR1);
+    sigaddset(&set, SIGUSR2);
+    sigaddset(&set, SIGCHLD);
+    sigaddset(&set, SIGCLD);
+    sigaddset(&set, SIGPWR);
+    sigaddset(&set, SIGWINCH);
+    sigaddset(&set, SIGURG);
+    sigaddset(&set, SIGPOLL);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGSTOP);
+    sigaddset(&set, SIGTSTP);
+    sigaddset(&set, SIGCONT);
+    sigaddset(&set, SIGTTIN);
+    sigaddset(&set, SIGTTOU);
+    sigaddset(&set, SIGVTALRM);
+    sigaddset(&set, SIGPROF);
+    sigaddset(&set, SIGXCPU);
+    sigaddset(&set, SIGXFSZ);
+    sigaddset(&set, SIGDOOM);
+
+    int ret = sigprocmask(SIG_BLOCK, &set, &oset);
+    signals_disabled = !ret;
+    return ret;
+}
+
+int __gnat_enable_signals(void)
+{
+    if (!signals_disabled) {
+        return 0;
+    }
+    signals_disabled = 0;
+    return sigprocmask(SIG_SETMASK, &oset, 0);
+}
+
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gcc/ada/libgnarl/s-taprop__qnx.adb 
b/gcc/ada/libgnarl/s-taprop__qnx.adb
index e7d245fec7de..b51f2b527082 100644
--- a/gcc/ada/libgnarl/s-taprop__qnx.adb
+++ b/gcc/ada/libgnarl/s-taprop__qnx.adb
@@ -766,6 +766,16 @@ package body System.Task_Primitives.Operations is
       function Thread_Body_Access is new
         Ada.Unchecked_Conversion (System.Address, Thread_Body);
 
+      function Disable_Signals return Interfaces.C.int with
+        Import,
+        Convention    => C,
+        External_Name => "__gnat_disable_signals";
+
+      function Enable_Signals return Interfaces.C.int with
+        Import,
+        Convention    => C,
+        External_Name => "__gnat_enable_signals";
+
    begin
       Adjusted_Stack_Size :=
          Interfaces.C.size_t (Stack_Size + Alternate_Stack_Size);
@@ -840,10 +850,11 @@ package body System.Task_Primitives.Operations is
 
       pragma Assert (Result = 0);
 
-      --  Since the initial signal mask of a thread is inherited from the
-      --  creator, and the Environment task has all its signals masked, we
-      --  do not need to manipulate caller's signal mask at this point.
-      --  All tasks in RTS will have All_Tasks_Mask initially.
+      --  (QMS3263) lists PR 2894086. This defect causes a memory leak when
+      --  pthread_create is interrupted by a signal and later resumed. To avoid
+      --  avoid such a leak the document suggests to disable signals while
+      --  calling pthread_create. The signal mask of the calling thread is
+      --  restored after the call to pthread_create.
 
       --  The write to T.Common.LL.Thread is not racy with regard to the
       --  created thread because the created thread will not access it until
@@ -851,6 +862,8 @@ package body System.Task_Primitives.Operations is
       --  Restricted.Stages is used). One can verify that by inspecting the
       --  Task_Wrapper procedures.
 
+      Result := Disable_Signals;
+      pragma Assert (Result = 0);
       Result := pthread_create
         (T.Common.LL.Thread'Access,
          Attributes'Access,
@@ -860,6 +873,9 @@ package body System.Task_Primitives.Operations is
 
       Succeeded := Result = 0;
 
+      Result := Enable_Signals;
+      pragma Assert (Result = 0);
+
       Result := pthread_attr_destroy (Attributes'Access);
       pragma Assert (Result = 0);
    end Create_Task;
-- 
2.43.0

Reply via email to