Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SystemExit raised in signal handler not propagated to running threads, killing them instead #107170

Open
sandrinr opened this issue Jul 24, 2023 · 2 comments
Labels
3.10 only security fixes 3.11 only security fixes 3.12 bugs and security fixes type-bug An unexpected behavior, bug, or error

Comments

@sandrinr
Copy link

Bug report

It seems to me that threads running when sys.exit() is called during signal handling are killed immediately. It further seems that the try ... finally contract is adhered to on the main thread but broken in other threads.

Consider the following pice of Python code:

import signal
import sys
import time
from threading import Thread


def termination_signal_handler(_, __):
    print("termination_signal_handler")
    sys.exit()


def f():
    try:
        print("Begin f")
        time.sleep(1000)
    except SystemExit:
        print("Got SystemExit in f")
        raise
    finally:
        print("End f")


signal.signal(signal.Signals.SIGINT, termination_signal_handler)
signal.signal(signal.Signals.SIGTERM, termination_signal_handler)

try:
    t = Thread(target=f, daemon=False)
    t.start()
    t.join()
except SystemExit:
    print("Got SystemExit in main")
    raise
finally:
    print("End main")

When running this code and hitting CTRL-C after a short while I get the following output:

$ python testthread.py 
Begin f
^Ctermination_signal_handler
Got SystemExit in main
End main

The output indicates that the thread t was killed right away, leaving the finally (and the except SystemExit clause in f) unexecuted.

My expectation would have been that either (XOR)

  • (a) SystemExit would be propagated to all threads
  • (b) SystemExit raised on the main thread and the other threads are left running
  • (c) Nothing happens

According to the Python doc, non daemonic threads should not be killed when the main thread exits. Also, according to several SO posts, the expected behavior would more be in the area of (b).

Note: The same code without the signal handling is behaving in a similar way. The only difference there is that the KeyboardInterupt trace is also logged to the console.

Am I missing something?

Your environment

  • CPython versions tested on: 3.11.4
  • Operating system and architecture: macOS-13.4.1-arm64-arm-64bit
@sandrinr sandrinr added the type-bug An unexpected behavior, bug, or error label Jul 24, 2023
@gpshead gpshead added 3.11 only security fixes 3.12 bugs and security fixes labels Sep 26, 2024
@gpshead
Copy link
Member

gpshead commented Sep 26, 2024

I can reproduce this using the latest 3.12 branch as well as a build of 3.10. But 3.13.0rc2 and main already appear to do what you would expect and the thread is still running keeping the process alive.

@gpshead gpshead added the 3.10 only security fixes label Sep 26, 2024
@gpshead
Copy link
Member

gpshead commented Sep 26, 2024

I added the labels for the older versions I tested, but 3.11 and 3.10 are in security fix only mode; there's a chance someone might work on this for 3.12 but at least our soon to be latest version is already fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.10 only security fixes 3.11 only security fixes 3.12 bugs and security fixes type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants