← index #17710Issue #18167
Related · high · value 2.251
QUERY · ISSUE

uctypes: Element assignment through PTR silently fails

openby jepleropened 2025-07-18updated 2025-07-18
bug

Port, board and/or hardware

unix port, longlong build

MicroPython version

MicroPython v1.26.0-preview.391.gba3f9cacf0.dirty

Reproduction

import uctypes

# Find the size corresponding to a pointer
ptr_size = uctypes.sizeof((uctypes.PTR, uctypes.INT8))
assert ptr_size in (4, 8)
UINTPTR = uctypes.UINT64 if ptr_size == 8 else uctypes.UINT32

# This descriptor lets us store an address via val then dereference it via ptr
descr = {
    'ptr': (uctypes.PTR | 0, uctypes.INT8),
    'val': UINTPTR | 0
}

# Build the data. `x.ptr` points at b2.
b1 = bytearray(uctypes.sizeof(descr))
b2 = bytearray(8)
x = uctypes.struct(uctypes.addressof(b1), descr)
x.val = uctypes.addressof(b2)

# Optimization: avoid rebuilding the `x.ptr` struct object
# (this has no influence over the bug)
ptr = x.ptr

# Access the data...
print("Setting via uctypes ptr, reading via bytearray")
for i in range(8):
    ptr[i] = i
for i in range(8):
    print(b2[i], end=" ")
    #assert ptr[i] == i ## Assertion fails!
print()

print("Setting via bytearray, reading via ptr")
for i in range(8):
    b2[i] = 10 + i
for i in range(8):
    print(ptr[i], end=" ")
    assert ptr[i] == 10 + i
print()

Expected behaviour

The first line printed should say 0 1 2 3 4 5 6 7 (the values assigned by ptr[i] = i)

Observed behaviour

Instead, it says 0 0 0 0 0 0 0 , because the element assignment is silently ignored.

Additional Information

over in m68k-micropython I'm using this change:

         } else if (agg_type == PTR) {
             byte *p = *(void **)self->addr;
             if (mp_obj_is_small_int(t->items[1])) {
                 uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS);
-                return get_aligned(val_type, p, index);
+                if (value == MP_OBJ_SENTINEL) {
+                    return get_aligned(val_type, p, index);
+                } else {
+                    set_aligned(val_type, p, index, value);
+                    return value; // just !MP_OBJ_NULL
+                }

I can submit this as a PR, but I wanted to make sure the functionality wasn't intentionally missing for some reason I wasn't aware of.

Code of Conduct

Yes, I agree

CANDIDATE · ISSUE

uctypes.bytes_at() accepts out-of-range (non-canonical) address and segfaults

openby MaksimFengopened 2025-09-29updated 2025-09-30
bug

Port, board and/or hardware

Unix port

MicroPython version

MicroPython v1.27.0-preview.107.gd1607598f on 2025-09-09; linux [GCC 14.2.0] version

Reproduction

A Python-level exception when the address is obviously invalid, e.g.:

  • ValueError/OverflowError for negative/out-of-range addresses, or
  • OSError if the runtime chooses to probe and detect unreadable memory on the unix port.

At minimum, reject negative addresses and detect addr + size overflow to avoid trivial VM crashes.

Expected behaviour


import uctypes
ptr = 1 << 48         
arr = uctypes.bytes_at(ptr, 8)
print('READ', arr)     

Observed behaviour

Program received signal SIGSEGV, Segmentation fault.
#0  qstr_compute_hash(data=0x1000000000000, len=0x8)
#1  mp_obj_new_str_copy(type=mp_type_bytes, data=0x1000000000000, len=0x8)
#2  mp_obj_new_bytes(...)
#3  uctypes_struct_bytes_at(ptr=0x1000000000000, size=0x8)
#4  fun_builtin_2_call(...)
#5  mp_call_function_n_kw(...)
#6  mp_execute_bytecode(...)
...


Additional Information

No, I've provided everything above.

Code of Conduct

Yes, I agree

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied