Skip to content

fix: cancel pending futures on SIGINT to prevent traceback on exit (Python 3.13+)#2847

Open
juliosuas wants to merge 12 commits intosherlock-project:masterfrom
juliosuas:fix/ctrl-c-graceful-shutdown
Open

fix: cancel pending futures on SIGINT to prevent traceback on exit (Python 3.13+)#2847
juliosuas wants to merge 12 commits intosherlock-project:masterfrom
juliosuas:fix/ctrl-c-graceful-shutdown

Conversation

@juliosuas
Copy link
Copy Markdown

Description

Fixes #2756Control + C generates a noisy traceback instead of exiting cleanly.

Root Cause

When the user presses Ctrl-C, the handler() function calls sys.exit(0). However, there are still worker threads running inside the ThreadPoolExecutor (created by SherlockFuturesSession). In Python 3.13+, the interpreter's threading shutdown is stricter and tries to join these threads, which then raise SystemExit from inside a worker — resulting in the exception trace seen in the issue.

Fix

  1. Added a module-level _active_session variable that stores a reference to the active SherlockFuturesSession immediately after it is created inside sherlock().
  2. Updated handler() to call executor.shutdown(wait=False, cancel_futures=True) before sys.exit(0), so all pending futures are cancelled and the thread pool drains cleanly.
  3. Wrapped in a broad except to ensure we never raise inside a signal handler.

Before

^C^CException ignored on threading shutdown:
Traceback (most recent call last):
  File ".../threading.py", line 1536, in _shutdown
  ...
  File ".../sherlock.py", line 535, in handler
    sys.exit(0)
SystemExit: 0

After

Ctrl-C exits immediately and cleanly with no traceback.

Checklist

  • Code is syntactically valid
  • Existing test suite passes (pre-existing failures in test_ux.py unrelated)
  • Manually verified clean exit

GNOME VCS (sherlock-project#2804): Switch from response_url to API-based detection
using /api/v4/users?username={} endpoint (same approach as GitLab).
The previous response_url method failed because non-existent users
get 302-redirected to /users/sign_in instead of staying at the
profile URL.

Patched (sherlock-project#2805): Update domain from patched.sh to patched.to.
The site migrated domains, causing all lookups to fail with the
old URL.

Verified both fixes: GNOME VCS API returns user data for existing
users and [] for non-existent ones. Patched.to returns the expected
error message for invalid users on the new domain.

Fixes sherlock-project#2804
Fixes sherlock-project#2805
Patched.sh now redirects to patched.to, which returns HTTP 403
for all requests (both existing and non-existing users) due to
Cloudflare WAF. This causes guaranteed false positives.

GNOME VCS fix (API-based detection) is retained and passes F+/F-
validation locally.
When the user presses Ctrl-C while Sherlock is scanning, Python's
ThreadPoolExecutor (particularly strict in Python 3.13+) prints a noisy
traceback during interpreter shutdown because worker threads are still
running when sys.exit(0) is called from the signal handler.

Fix by:
1. Storing the active SherlockFuturesSession in a module-level variable
   (_active_session) immediately after it is created inside sherlock().
2. Calling executor.shutdown(wait=False, cancel_futures=True) from the
   SIGINT handler before sys.exit(0), so all pending futures are
   cancelled and the thread pool drains cleanly.

The shutdown call is wrapped in a broad except to ensure we never raise
inside a signal handler, and the global is set to None initially so the
handler is safe to call even before any scan starts.

Fixes sherlock-project#2756
@github-actions
Copy link
Copy Markdown
Contributor

Automatic validation of changes

Target F+ Check F- Check
Root-Me ✔️   Pass ✔️   Pass

@juliosuas
Copy link
Copy Markdown
Author

Thanks for the automated validation — Root-Me checks pass on both + and - sides, which confirms the fix doesn't affect detection behavior.

To summarize what this PR does: when the user hits Ctrl-C during a scan, Python 3.13+'s ThreadPoolExecutor shutdown is stricter and tries to join worker threads that call sys.exit(0) internally, producing the traceback in #2756. The fix stores a reference to the SherlockFuturesSession and calls executor.shutdown(wait=False, cancel_futures=True) before exiting, which cleanly drains the thread pool.

Happy to add a test or adjust anything based on your review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Control + C Fails to cleanly stop sherlock

1 participant