diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py index ff944b3163ec3e..92cf8c01351f03 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py @@ -952,6 +952,26 @@ def test_writer_handles_mixed_empty_and_real_first_sample(self): self.assertIn((0, 1), reader_collector.by_thread) self.assertEqual(len(reader_collector.by_thread[(0, 1)]), 2) + def test_writer_failed_sample_does_not_advance_timestamp(self): + """A rejected frame must not shift later timestamps.""" + with tempfile.NamedTemporaryFile(suffix=".bin", delete=False) as f: + filename = f.name + self.temp_files.append(filename) + + good = [make_interpreter(0, [make_thread(1, [make_frame("a.py", 1, "f")])])] + bad = [make_interpreter(0, [make_thread(1, [make_frame(42, 1, "f")])])] + + with _remote_debugging.BinaryWriter(filename, 1000, 0) as writer: + writer.write_sample(good, 1000) + with self.assertRaises(TypeError): + writer.write_sample(bad, 5000) + writer.write_sample(good, 6000) + + collector = TimestampCollector() + with BinaryReader(filename) as reader: + reader.replay_samples(collector) + self.assertEqual(collector.all_timestamps, [1000, 6000]) + def test_writer_total_samples_after_finalize_matches_reader(self): """BinaryWriter.total_samples after finalize() matches the reader's count.""" # Five IDENTICAL samples force every sample beyond the first into the diff --git a/Misc/NEWS.d/next/Library/2026-10-01-09-17-11.gh-issue-158550.cRIHW-.rst b/Misc/NEWS.d/next/Library/2026-10-01-09-17-11.gh-issue-158550.cRIHW-.rst new file mode 100644 index 00000000000000..d84eb292bb5b3d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-01-09-17-11.gh-issue-158550.cRIHW-.rst @@ -0,0 +1,2 @@ +Fix incorrect timestamps in Tachyon binary profiles after a sample fails to be +written. Patch by Maurycy Pawłowski-Wieronski. diff --git a/Modules/_remote_debugging/binary_io_writer.c b/Modules/_remote_debugging/binary_io_writer.c index 6af81515e7131d..bd9175701dcbde 100644 --- a/Modules/_remote_debugging/binary_io_writer.c +++ b/Modules/_remote_debugging/binary_io_writer.c @@ -950,7 +950,6 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, /* Calculate timestamp delta */ uint64_t delta = timestamp_us - entry->prev_timestamp; - entry->prev_timestamp = timestamp_us; /* Process frames and build current stack */ uint32_t curr_stack[MAX_STACK_DEPTH]; @@ -1006,6 +1005,7 @@ process_thread_sample(BinaryWriter *writer, PyObject *thread_info, entry->prev_stack_depth = curr_depth; } + entry->prev_timestamp = timestamp_us; writer->total_samples++; return 0; }