Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed string table and sample record bounds checks in :mod:`!_remote_debugging`
when decoding certain ``.pyb`` inputs on 32-bit builds. Patch by Maurycy
Pawłowski-Wieroński.
7 changes: 4 additions & 3 deletions Modules/_remote_debugging/binary_io_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

/* File structure sizes */
#define FILE_FOOTER_SIZE 32
#define SAMPLE_RECORD_HEADER_SIZE (sizeof(uint64_t) + sizeof(uint32_t) + 1)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense indeed 👍 Can you do the change in this PR?

Copy link
Copy Markdown
Contributor Author

@maurycy maurycy Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pablogsal

Voilà: f14741f

Truth to be told, I think there's a massive room for improvement with consts here:

https://github.com/maurycy/cpython/blob/remote-debugging-int-bounds/Modules/_remote_debugging/binary_io_reader.c#L26
https://github.com/maurycy/cpython/blob/remote-debugging-int-bounds/Modules/_remote_debugging/binary_io_reader.c#L26

#define MAX_DECOMPRESS_SIZE (1ULL << 30)

#define MAX_DECOMPRESS_SIZE (1ULL << 30)

or magic offsets:

uint64_t file_size = (uint64_t)footer_offset + 32;
uint8_t footer[32] = {0};
/* Cast size_t to uint32_t before memcpy to ensure correct bytes are copied
* on both little-endian and big-endian systems (size_t is 8 bytes on 64-bit) */
uint32_t string_count_u32 = (uint32_t)writer->string_count;
uint32_t frame_count_u32 = (uint32_t)writer->frame_count;
memcpy(footer + 0, &string_count_u32, 4);
memcpy(footer + 4, &frame_count_u32, 4);
memcpy(footer + 8, &file_size, 8);

(perhaps just FILE_FOOTER_SIZE here etc.)

https://github.com/maurycy/cpython/blob/f14741f422d0983f9a3c6a7bdd9c47b931e3fb1e/Modules/_remote_debugging/binary_io_reader.c#L985-L1003
https://github.com/maurycy/cpython/blob/f14741f422d0983f9a3c6a7bdd9c47b931e3fb1e/Modules/_remote_debugging/binary_io_writer.c#L651-L662
https://github.com/maurycy/cpython/blob/f14741f422d0983f9a3c6a7bdd9c47b931e3fb1e/Modules/_remote_debugging/binary_io_writer.c#L590-L595

(perhaps just SAMPLE_OFF warranted here as well)

etc., etc.

If interest in cleaning up these – I can create a PR.

#define MIN_DECOMPRESS_BUFFER_SIZE (64 * 1024) /* Minimum decompression buffer */

/* Progress callback frequency */
Expand Down Expand Up @@ -258,7 +259,7 @@ reader_parse_string_table(BinaryReader *reader, const uint8_t *data, size_t file
PyErr_SetString(PyExc_ValueError, "Malformed varint in string table");
return -1;
}
if (offset + str_len > file_size) {
if (offset > file_size || str_len > file_size - offset) {
PyErr_SetString(PyExc_ValueError, "String table overflow");
return -1;
}
Expand Down Expand Up @@ -976,8 +977,8 @@ binary_reader_replay(BinaryReader *reader, PyObject *collector, PyObject *progre
}

while (offset < reader->sample_data_size) {
/* Read thread_id (8 bytes) + interpreter_id (4 bytes) */
if (offset + 13 > reader->sample_data_size) {
/* Read thread_id (8 bytes) + interpreter_id (4 bytes) + encoding byte */
if (reader->sample_data_size - offset < SAMPLE_RECORD_HEADER_SIZE) {
break; /* End of data */
}

Expand Down
Loading