Skip to content

Commit c266f0c

Browse files
authored
gh-149009: Validate thread_count in profiling.sampling binary reader (#149147)
1 parent 04ce318 commit c266f0c

3 files changed

Lines changed: 41 additions & 0 deletions

File tree

Lib/test/test_profiling/test_sampling_profiler/test_binary_format.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import os
55
import random
6+
import struct
67
import tempfile
78
import unittest
89
from collections import defaultdict
@@ -941,6 +942,35 @@ def test_writer_total_samples_after_close_returns_zero(self):
941942
self.assertEqual(w.total_samples, 0)
942943

943944

945+
class TestBinaryFormatValidation(BinaryFormatTestBase):
946+
"""Tests for malformed binary files."""
947+
948+
HDR_OFF_THREADS = 32
949+
950+
def test_replay_rejects_more_threads_than_declared(self):
951+
"""Replay rejects files with more unique threads than the header declares."""
952+
threads = [
953+
make_thread(1, [make_frame("t1.py", 10, "t1")]),
954+
make_thread(2, [make_frame("t2.py", 20, "t2")]),
955+
]
956+
samples = [[make_interpreter(0, threads)]]
957+
filename = self.create_binary_file(samples, compression="none")
958+
959+
with open(filename, "r+b") as raw:
960+
raw.seek(self.HDR_OFF_THREADS)
961+
raw.write(struct.pack("=I", 1))
962+
963+
with BinaryReader(filename) as reader:
964+
self.assertEqual(reader.get_info()["thread_count"], 1)
965+
with self.assertRaises(ValueError) as cm:
966+
reader.replay_samples(RawCollector())
967+
self.assertEqual(
968+
str(cm.exception),
969+
"Invalid thread count: sample data contains more unique "
970+
"threads than declared in header (declared 1, found at least 2)",
971+
)
972+
973+
944974
class TestBinaryEncodings(BinaryFormatTestBase):
945975
"""Tests specifically targeting different stack encodings."""
946976

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Validate that :mod:`profiling.sampling` binary profiles do not contain more
2+
unique (thread, interpreter) pairs than declared in the header. Patch by
3+
Maurycy Pawłowski-Wieroński.

Modules/_remote_debugging/binary_io_reader.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,14 @@ reader_get_or_create_thread_state(BinaryReader *reader, uint64_t thread_id,
559559
}
560560
}
561561

562+
if (reader->thread_state_count >= reader->thread_count) {
563+
PyErr_Format(PyExc_ValueError,
564+
"Invalid thread count: sample data contains more unique threads than declared in header "
565+
"(declared %u, found at least %zu)",
566+
reader->thread_count, reader->thread_state_count + 1);
567+
return NULL;
568+
}
569+
562570
if (!reader->thread_states) {
563571
reader->thread_state_capacity = 16;
564572
reader->thread_states = PyMem_Calloc(reader->thread_state_capacity, sizeof(ReaderThreadState));

0 commit comments

Comments
 (0)