diff mbox series

Fix deadlock from calling exit() in signal handler

Message ID 20211112201054.3493178-1-JPEWhacker@gmail.com
State Accepted
Headers show
Series Fix deadlock from calling exit() in signal handler | expand

Commit Message

Joshua Watt Nov. 12, 2021, 8:10 p.m. UTC
exit() cannot be called from a signal handler in swupdate because the
atexit() handlers are not thread-safe and can deadlock. Instead, signal
the main process to exit with SIGTERM when a child process dies.

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
---
 core/pctl.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

Comments

Stefano Babic Nov. 13, 2021, 2:26 p.m. UTC | #1
Hi Joshua,

On 12.11.21 21:10, Joshua Watt wrote:
> exit() cannot be called from a signal handler in swupdate because the
> atexit() handlers are not thread-safe and can deadlock.

Right.

> Instead, signal
> the main process to exit with SIGTERM when a child process dies.
> 
> Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
> ---
>   core/pctl.c | 11 ++++++-----
>   1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/core/pctl.c b/core/pctl.c
> index 9c2d534..c31575a 100644
> --- a/core/pctl.c
> +++ b/core/pctl.c
> @@ -404,7 +404,6 @@ int run_system_cmd(const char *cmd)
>   void sigchld_handler (int __attribute__ ((__unused__)) signum)
>   {
>   	int childpid, status, serrno;
> -	int exitstatus;
>   	int hasdied = 0;
>   	int i;
>   
> @@ -427,11 +426,9 @@ void sigchld_handler (int __attribute__ ((__unused__)) signum)
>   			hasdied = 0;
>   			if (WIFEXITED(status)) {
>   				hasdied = 1;
> -				exitstatus = WEXITSTATUS(status);
> -				printf("exited, status=%d\n", exitstatus);
> +				printf("exited, status=%d\n", WIFEXITED(status));
>   			} else if (WIFSIGNALED(status)) {
>   				hasdied = 1;
> -				exitstatus = WTERMSIG(status);
>   				printf("killed by signal %d\n", WTERMSIG(status));
>   			} else if (WIFSTOPPED(status)) {
>   				printf("stopped by signal %d\n", WSTOPSIG(status));
> @@ -454,7 +451,11 @@ void sigchld_handler (int __attribute__ ((__unused__)) signum)
>   			}
>   		}
>   
> -		exit(exitstatus);
> +		/*
> +		 * exit() it not safe to call from a signal handler because of atexit()
> +		 * handlers, so send SIGTERM to ourself instead
> +		 */
> +		kill(getpid(), SIGTERM);
>   	}
>   
>   	errno = serrno;
> 


Thanks for fixing, applied to -master.

Best regards,
Stefano Babic
diff mbox series

Patch

diff --git a/core/pctl.c b/core/pctl.c
index 9c2d534..c31575a 100644
--- a/core/pctl.c
+++ b/core/pctl.c
@@ -404,7 +404,6 @@  int run_system_cmd(const char *cmd)
 void sigchld_handler (int __attribute__ ((__unused__)) signum)
 {
 	int childpid, status, serrno;
-	int exitstatus;
 	int hasdied = 0;
 	int i;
 
@@ -427,11 +426,9 @@  void sigchld_handler (int __attribute__ ((__unused__)) signum)
 			hasdied = 0;
 			if (WIFEXITED(status)) {
 				hasdied = 1;
-				exitstatus = WEXITSTATUS(status);
-				printf("exited, status=%d\n", exitstatus);
+				printf("exited, status=%d\n", WIFEXITED(status));
 			} else if (WIFSIGNALED(status)) {
 				hasdied = 1;
-				exitstatus = WTERMSIG(status);
 				printf("killed by signal %d\n", WTERMSIG(status));
 			} else if (WIFSTOPPED(status)) {
 				printf("stopped by signal %d\n", WSTOPSIG(status));
@@ -454,7 +451,11 @@  void sigchld_handler (int __attribute__ ((__unused__)) signum)
 			}
 		}
 
-		exit(exitstatus);
+		/*
+		 * exit() it not safe to call from a signal handler because of atexit()
+		 * handlers, so send SIGTERM to ourself instead
+		 */
+		kill(getpid(), SIGTERM);
 	}
 
 	errno = serrno;