Visitar URL original
GH-93964: Harden overflow checks before _PyBytes_Resize in compile.c by sweeneyde · Pull Request #94044 · python/cpython · GitHub
Skip to content
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Another test, more comments
  • Loading branch information
sweeneyde committed Jun 21, 2022
commit e0054bfc2f2e604356a206e9fe8b34891233451d
27 changes: 17 additions & 10 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7500,14 +7500,22 @@ assemble_emit_exception_table_item(struct assembler *a, int value, int msb)
write_except_byte(a, (value&0x3f) | msb);
}

/* Make room for at least logical_length+to_add bytes in the bytes object.
Use exponential growth for O(1) amortized runtime. */
/* Make room for at least (logical_length+to_add)*unitsize in the
bytes object. Use exponential growth for O(1) amortized runtime. */
static int
bytes_make_room(PyObject **bytes, Py_ssize_t logical_length,
Py_ssize_t to_add)
bytes_make_room(PyObject **bytes, int logical_length,
int to_add, Py_ssize_t unitsize)
{
// Make sure we can successfully do the addition.
if (logical_length > INT_MAX - to_add) {
PyErr_NoMemory();
return 0;
}
// The existing logical buffer should always fit in a Py_ssize_t
assert(logical_length <= PY_SSIZE_T_MAX / unitsize);
Py_ssize_t b_len = PyBytes_GET_SIZE(*bytes);
if (logical_length >= b_len - to_add) {
if (unitsize * logical_length >= b_len - to_add * unitsize) {
// There's not enough room. Double it.
if (b_len > PY_SSIZE_T_MAX / 2) {

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.

This has the same issue as the backport.
We want to be able to index all code object structures with an int, so you'll need INT_MAX instead of PY_SSIZE_T_MAX and it should be an overflow error, not a memory error.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

To clarify, we want a_bytecode to be able to have INT_MAX code units, not just INT_MAX bytes, right?

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.

We probably want the smaller amount to avoid risk of overflow. So the length in bytes should be less than INT_MAX.

PyErr_NoMemory();
return 0;
Expand All @@ -7526,7 +7534,7 @@ static int
assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler)
{
if (!bytes_make_room(&a->a_except_table, a->a_except_table_off,
MAX_SIZE_OF_ENTRY)) {
MAX_SIZE_OF_ENTRY, 1)) {
return 0;
}
int size = end-start;
Expand Down Expand Up @@ -7669,7 +7677,7 @@ static int
write_location_info_entry(struct assembler* a, struct instr* i, int isize)
{
if (!bytes_make_room(&a->a_linetable, a->a_location_off,
THEORETICAL_MAX_ENTRY_SIZE)) {
THEORETICAL_MAX_ENTRY_SIZE, 1)) {
return 0;
}
if (i->i_loc.lineno < 0) {
Expand Down Expand Up @@ -7728,9 +7736,8 @@ assemble_emit(struct assembler *a, struct instr *i)
Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
_Py_CODEUNIT *code;
int size = instr_size(i);
assert(a->a_offset <= PY_SSIZE_T_MAX / 2);
if (!bytes_make_room(&a->a_bytecode, a->a_offset * (Py_ssize_t)2,
sizeof(_Py_CODEUNIT) * (Py_ssize_t)size)) {
if (!bytes_make_room(&a->a_bytecode, a->a_offset,
size, sizeof(_Py_CODEUNIT))) {
return 0;
}
code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
Expand Down