diff --git a/Lib/test/test_external_inspection.py b/Lib/test/test_external_inspection.py index 9fff8e8bff91f7a..a61c1616fa82f0b 100644 --- a/Lib/test/test_external_inspection.py +++ b/Lib/test/test_external_inspection.py @@ -3544,6 +3544,30 @@ def gen(): skip_non_matching_threads=True, ) + @requires_gil_enabled("Free threaded builds don't have an 'active thread'") + def test_filtered_active_thread_is_not_replaced(self): + samples = [] + + def sample(): + for kwargs in ({"all_threads": True}, {"only_active_thread": True}): + unwinder = RemoteUnwinder( + os.getpid(), mode=PROFILING_MODE_EXCEPTION, **kwargs + ) + samples.append( + self._get_thread_statuses(unwinder.get_stack_trace()) + ) + + thread = threading.Thread(target=sample) + try: + raise ValueError + except ValueError: + thread.start() + thread.join() + + all_threads, active_thread = samples + self.assertEqual(list(all_threads), [threading.get_native_id()]) + self.assertEqual(active_thread, {}) + @requires_remote_subprocess_debugging() class TestFrameCaching(RemoteInspectionTestBase): diff --git a/Misc/NEWS.d/next/Library/2026-10-10-18-56-26.gh-issue-159130.3AIHqh.rst b/Misc/NEWS.d/next/Library/2026-10-10-18-56-26.gh-issue-159130.3AIHqh.rst new file mode 100644 index 000000000000000..f4ff555a25e7010 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-10-18-56-26.gh-issue-159130.3AIHqh.rst @@ -0,0 +1,2 @@ +Fix :mod:`!_remote_debugging` returning a different thread when the selected +thread does not match the profiling mode with ``only_active_thread=True``. diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index 6fa277d1065ed91..2a782715298f933 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -823,6 +823,9 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self goto exit; } // Thread was skipped due to mode filtering, continue to next thread + if (self->tstate_addr || self->only_active_thread) { + break; + } continue; } // This was an actual error