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