Skip to content

Commit 8d1359f

Browse files
committed
gh-148252: Fix stack depth calculation in binary reader on 32-bit platforms
Compute ``final_depth`` in ``decode_stack_pop_push()`` and ``decode_stack_suffix()`` using ``uint64_t`` before validating it. On 32-bit builds, using ``size_t`` arithmetic for ``keep + push`` can wrap for large input values, causing the later bounds check to validate the wrong final depth. Using a widened type keeps the validation aligned with the actual result.
1 parent acf5229 commit 8d1359f

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed stack depth calculation in :mod:`!_remote_debugging` when decoding
2+
certain ``.pyb`` inputs on 32-bit builds. Issue originally identified and
3+
diagnosed by Tristan (@TristanInSec on GitHub).

Modules/_remote_debugging/binary_io_reader.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,20 @@ reader_get_or_create_thread_state(BinaryReader *reader, uint64_t thread_id,
601601
* STACK DECODING HELPERS
602602
* ============================================================================ */
603603

604+
/* Validate that final_depth fits in the stack buffer.
605+
* Uses uint64_t to prevent overflow on 32-bit platforms. */
606+
static inline int
607+
validate_stack_depth(ReaderThreadState *ts, uint64_t final_depth)
608+
{
609+
if (final_depth > ts->current_stack_capacity) {
610+
PyErr_Format(PyExc_ValueError,
611+
"Final stack depth %llu exceeds capacity %zu",
612+
(unsigned long long)final_depth, ts->current_stack_capacity);
613+
return -1;
614+
}
615+
return 0;
616+
}
617+
604618
/* Decode a full stack from sample data.
605619
* Updates ts->current_stack and ts->current_stack_depth.
606620
* Returns 0 on success, -1 on error (bounds violation). */
@@ -658,12 +672,9 @@ decode_stack_suffix(ReaderThreadState *ts, const uint8_t *data,
658672
return -1;
659673
}
660674

661-
/* Validate final depth doesn't exceed capacity */
662-
size_t final_depth = (size_t)shared + new_count;
663-
if (final_depth > ts->current_stack_capacity) {
664-
PyErr_Format(PyExc_ValueError,
665-
"Final stack depth %zu exceeds capacity %zu",
666-
final_depth, ts->current_stack_capacity);
675+
/* Use uint64_t to prevent overflow on 32-bit platforms */
676+
uint64_t final_depth = (uint64_t)shared + new_count;
677+
if (validate_stack_depth(ts, final_depth) < 0) {
667678
return -1;
668679
}
669680

@@ -713,12 +724,9 @@ decode_stack_pop_push(ReaderThreadState *ts, const uint8_t *data,
713724
}
714725
size_t keep = (ts->current_stack_depth > pop) ? ts->current_stack_depth - pop : 0;
715726

716-
/* Validate final depth doesn't exceed capacity */
717-
size_t final_depth = keep + push;
718-
if (final_depth > ts->current_stack_capacity) {
719-
PyErr_Format(PyExc_ValueError,
720-
"Final stack depth %zu exceeds capacity %zu",
721-
final_depth, ts->current_stack_capacity);
727+
/* Use uint64_t to prevent overflow on 32-bit platforms */
728+
uint64_t final_depth = (uint64_t)keep + push;
729+
if (validate_stack_depth(ts, final_depth) < 0) {
722730
return -1;
723731
}
724732

0 commit comments

Comments
 (0)