[COMMITTED,08/31] ada: Disable signals when calling pthread_create on QNX

Message ID 20250911091904.1505690-8-poulhies@adacore.com
State Committed
Commit 7cbf4b85b2c98b503a7fdff507fa39fca3a09b6e
Headers
Series [COMMITTED,01/31] ada: Disable new warning for composite equality ops that can raise Program_Error |

Commit Message

Marc Poulhiès Sept. 11, 2025, 9:18 a.m. UTC
  From: Johannes Kliemann <kliemann@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(-)
  

Patch

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;