Skip to content

Commit 18406c9

Browse files
committed
py/objarray: Fix use-after-free if extending a slice from itself.
Closes #13283 Reproducing this bug and confirming the fix requires running under valgrind with GC-aware extensions. Note in default configurations with GIL this bug exists but has no impact (the free buffer won't be reused while the function is still executing, and is no longer referenced after it returns). Signed-off-by: Angus Gratton <angus@redyak.com.au>
1 parent 90e5178 commit 18406c9

File tree

2 files changed

+23
-11
lines changed

2 files changed

+23
-11
lines changed

py/objarray.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,8 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
456456
#if MICROPY_PY_ARRAY_SLICE_ASSIGN
457457
// Assign
458458
size_t src_len;
459-
void *src_items;
459+
uint8_t *src_items;
460+
size_t src_offs = 0;
460461
size_t item_sz = mp_binary_get_size('@', o->typecode & TYPECODE_MASK, NULL);
461462
if (mp_obj_is_obj(value) && MP_OBJ_TYPE_GET_SLOT_OR_NULL(((mp_obj_base_t *)MP_OBJ_TO_PTR(value))->type, subscr) == array_subscr) {
462463
// value is array, bytearray or memoryview
@@ -469,7 +470,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
469470
src_items = src_slice->items;
470471
#if MICROPY_PY_BUILTINS_MEMORYVIEW
471472
if (mp_obj_is_type(value, &mp_type_memoryview)) {
472-
src_items = (uint8_t *)src_items + (src_slice->memview_offset * item_sz);
473+
src_offs = src_slice->memview_offset * item_sz;
473474
}
474475
#endif
475476
} else if (mp_obj_is_type(value, &mp_type_bytes)) {
@@ -504,13 +505,18 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value
504505
// TODO: alloc policy; at the moment we go conservative
505506
o->items = m_renew(byte, o->items, (o->len + o->free) * item_sz, (o->len + len_adj) * item_sz);
506507
o->free = len_adj;
507-
dest_items = o->items;
508+
if (o->items != dest_items) { // m_renew moved o->items
509+
if (src_items == dest_items) {
510+
src_items = o->items;
511+
}
512+
dest_items = o->items;
513+
}
508514
}
509515
mp_seq_replace_slice_grow_inplace(dest_items, o->len,
510-
slice.start, slice.stop, src_items, src_len, len_adj, item_sz);
516+
slice.start, slice.stop, src_items + src_offs, src_len, len_adj, item_sz);
511517
} else {
512518
mp_seq_replace_slice_no_grow(dest_items, o->len,
513-
slice.start, slice.stop, src_items, src_len, item_sz);
519+
slice.start, slice.stop, src_items + src_offs, src_len, item_sz);
514520
// Clear "freed" elements at the end of list
515521
// TODO: This is actually only needed for typecode=='O'
516522
mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz);

tests/basics/bytearray_slice_assign.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
l[1:3] = bytearray()
1919
print(l)
2020
l = bytearray(x)
21-
#del l[1:3]
21+
# del l[1:3]
2222
print(l)
2323

2424
l = bytearray(x)
@@ -28,7 +28,7 @@
2828
l[:3] = bytearray()
2929
print(l)
3030
l = bytearray(x)
31-
#del l[:3]
31+
# del l[:3]
3232
print(l)
3333

3434
l = bytearray(x)
@@ -38,7 +38,7 @@
3838
l[:-3] = bytearray()
3939
print(l)
4040
l = bytearray(x)
41-
#del l[:-3]
41+
# del l[:-3]
4242
print(l)
4343

4444
# slice assignment that extends the array
@@ -61,8 +61,14 @@
6161
print(b)
6262

6363
# Growth of bytearray via slice extension
64-
b = bytearray(b'12345678')
65-
b.append(57) # expand and add a bit of unused space at end of the bytearray
64+
b = bytearray(b"12345678")
65+
b.append(57) # expand and add a bit of unused space at end of the bytearray
6666
for i in range(400):
67-
b[-1:] = b'ab' # grow slowly into the unused space
67+
b[-1:] = b"ab" # grow slowly into the unused space
68+
print(len(b), b)
69+
70+
# Growth of bytearray via slice extension from itself
71+
b = bytearray(b"1234567")
72+
for i in range(3):
73+
b[-1:] = b
6874
print(len(b), b)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy