Skip to content

Fix #1063: non-ASCII --profile-only no longer crashes with SIGSEGV - #1064

Merged
emeryberger merged 3 commits into
masterfrom
fix-issue-1063-non-ascii-profile-only
Jun 26, 2026
Merged

Fix #1063: non-ASCII --profile-only no longer crashes with SIGSEGV#1064
emeryberger merged 3 commits into
masterfrom
fix-issue-1063-non-ascii-profile-only

Conversation

@emeryberger

Copy link
Copy Markdown
Member

Fixes #1063.

Problem

Running Scalene with a non-ASCII value for --profile-only crashes the profiler with a segmentation fault:

python -m scalene run --profile-only é noop_target.py
# Scalene error: received signal SIGSEGV  (returncode 245)

Root cause

In src/include/traceconfig.hpp, the TraceConfig constructor converted each pattern with PyUnicode_AsASCIIString(item) and fed the result straight into PyBytes_AsString(...) without a NULL check. For non-ASCII input like é, the ASCII conversion fails and returns NULL, so PyBytes_AsString(NULL) dereferences a null pointer and crashes the process.

The same code also stored raw char* pointers into transient conversion objects (and had a latent use-after-free of the base_path conversion temporary).

Fix

  • Decode each pattern (and base_path) with PyUnicode_AsUTF8AndSize, which accepts UTF-8 / non-ASCII input.
  • On decode failure (NULL), call PyErr_Clear() and skip the item instead of dereferencing NULL.
  • Store owned std::string copies — items is now std::vector<std::string> and scalene_base_path is now std::string — so the data outlives any transient Python object. This also fixes the latent use-after-free.
  • Updated all use sites (should_trace, print) accordingly.

Verification

  • Native extension rebuilds cleanly (python setup.py build_ext --inplace).
  • The exact issue reproduction now runs to completion (target ran, rc=0) instead of segfaulting.
  • Added regression test tests/test_issue1063_non_ascii_profile_only.py (non-ASCII case + ASCII control); all related tests pass.

Note

The fix accepts/skips non-ASCII patterns rather than raising a Python error. A valid UTF-8 é is now matched correctly; truly non-decodable items are silently skipped, which is appropriate since --profile-only is a best-effort substring filter.

TraceConfig converted each --profile-only pattern with
PyUnicode_AsASCIIString and passed the result straight to
PyBytes_AsString without a NULL check. For non-ASCII input like "é"
the ASCII conversion returns NULL, so PyBytes_AsString(NULL)
dereferenced it and crashed the process with SIGSEGV.

Decode patterns (and base_path) with PyUnicode_AsUTF8AndSize, which
accepts UTF-8/non-ASCII input, and skip items that fail to decode
instead of dereferencing NULL. Store owned std::string copies (items
is now vector<string>, scalene_base_path is now string) so the data
outlives any transient conversion object, which also fixes a latent
use-after-free of the base_path conversion temporary.

Adds tests/test_issue1063_non_ascii_profile_only.py.
The subprocess-based test ran a full memory-mode "scalene run" and
asserted on its exit code / stdout, which was fragile under CI sampling
and process timing (both the non-ASCII case and the ASCII control
failed on CI while passing locally).

Rewrite it to drive the fixed TraceConfig constructor directly via
pywhere.setup_trace_config (the CPU-only registration path, which
needs no libscalene preload). A regression dereferences NULL inside the
extension and crashes the interpreter, so the test still captures the
exact SIGSEGV failure mode — now without subprocess/sampling flakiness.
@emeryberger
emeryberger merged commit 52aec24 into master Jun 26, 2026
64 of 77 checks passed
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.

Non-ASCII --profile-only value causes SIGSEGV in default profiling mode

1 participant