crash in btree module
Port, board and/or hardware
unix coverage build
MicroPython version
MicroPython v1.26.0-preview.387.g67acac257f.dirty on 2025-07-19; linux [GCC 12.2.0] version
Reproduction
Run the following script on the unix coverage build:
import btree, io
N = 62
db = btree.open(io.BytesIO(), pagesize=512)
e = b"a" * 78
for i in range(N):
db[b"thekey{}".format(i)] = e + str(i)
for i in range(N):
db[b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + str(i)] = e + str(i)
The script is a hand-minimized version of a longer version found by automated fuzzing. Small changes to the final long key string can cause the test to succeed or to fail instead with a MemoryError.
Expected behaviour
The script completes. It produces no useful output.
Observed behaviour
The script crashes.
With added instrumentation, I was able to trace the problem back to the use of an undefined value in __bt_split:
188 case P_BLEAF:
189 bl = GETBLEAF(rchild, 0);
190 VALGRIND_CHECK_VALUE_IS_DEFINED(bl->ksize);
191 nbytes = NBINTERNAL(bl->ksize);
192 if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
==2795256== Uninitialised byte(s) found during client check request
==2795256== at 0x6424C1: __bt_split (bt_split.c:191)
==2795256== by 0x635343: __bt_put (bt_put.c:202)
==2795256== by 0x471C19: btree_subscr (modbtree.c:328)
==2795256== by 0x3BB297: mp_obj_subscr (obj.c:575)
==2795256== by 0x446E75: mp_execute_bytecode (vm.c:503)
==2795256== by 0x3DA130: fun_bc_call (objfun.c:295)
==2795256== by 0x39F14F: mp_call_function_n_kw (runtime.c:727)
==2795256== by 0x3A41DB: mp_call_function_0 (runtime.c:701)
==2795256== by 0x658253: execute_from_lexer (main.c:162)
==2795256== by 0x658346: do_file (main.c:311)
==2795256== by 0x65A865: main_ (main.c:741)
==2795256== by 0x65ADE9: main (main.c:494)
==2795256== Address 0x55d164f is 463 bytes inside a block of size 560 alloc'd
==2795256== at 0x48417B4: malloc (vg_replace_malloc.c:381)
==2795256== by 0x649EAF: mpool_bkt (mpool.c:335)
==2795256== by 0x64B846: mpool_new (mpool.c:124)
==2795256== by 0x632B96: __bt_new (bt_page.c:96)
==2795256== by 0x63F954: bt_page (bt_split.c:371)
==2795256== by 0x640BC6: __bt_split (bt_split.c:110)
==2795256== by 0x635343: __bt_put (bt_put.c:202)
==2795256== by 0x471C19: btree_subscr (modbtree.c:328)
==2795256== by 0x3BB297: mp_obj_subscr (obj.c:575)
==2795256== by 0x446E75: mp_execute_bytecode (vm.c:503)
==2795256== by 0x3DA130: fun_bc_call (objfun.c:295)
==2795256== by 0x39F14F: mp_call_function_n_kw (runtime.c:727)
==2795256== Uninitialised value was created by a heap allocation
==2795256== at 0x48417B4: malloc (vg_replace_malloc.c:381)
==2795256== by 0x649EAF: mpool_bkt (mpool.c:335)
==2795256== by 0x64B846: mpool_new (mpool.c:124)
==2795256== by 0x62E481: nroot (bt_open.c:360)
==2795256== by 0x63094B: __bt_open (bt_open.c:306)
==2795256== by 0x47179E: mod_btree_open (modbtree.c:416)
==2795256== by 0x3DB1BF: fun_builtin_var_call (objfun.c:118)
==2795256== by 0x39F14F: mp_call_function_n_kw (runtime.c:727)
==2795256== by 0x39FC01: mp_call_method_n_kw (runtime.c:743)
==2795256== by 0x43EDFB: mp_execute_bytecode (vm.c:1068)
==2795256== by 0x3DA130: fun_bc_call (objfun.c:295)
==2795256== by 0x39F14F: mp_call_function_n_kw (runtime.c:727)
Additional Information
The cause for the bug is almost certainly in the btree submodule but as I'm not 100% sure, I chose to file the issue here.
Code of Conduct
Yes, I agree
crash in io.BufferedWriter due to missing argument validation
Port, board and/or hardware
unix coverage port
MicroPython version
MicroPython v1.26.0-preview.387.ge4e97f5aa7.dirty on 2025-07-20; linux [GCC 12.2.0] version
Reproduction
Run the following script:
import io
io.BufferedWriter(None, 1).write(b"foo")
Expected behaviour
Some kind of exception like a TypeError
Observed behaviour
Segmentation fault:
Program received signal SIGSEGV, Segmentation fault.
mp_stream_rw (stream=0x6, buf_=buf_@entry=0x7ffff7c30ba0, size=1,
errcode=errcode@entry=0x7fffffffd83c, flags=flags@entry=2 '\002')
at ../../py/stream.c:50
50 const mp_stream_p_t *stream_p = mp_get_stream(stream);
(gdb) p stream
$3 = (mp_obj_t) 0x6
Additional Information
Minimal validation of the suitablity of the stream object is missing.
This crash was found via automated fuzzing. I minimized the test case the fuzzer found.
Code of Conduct
Yes, I agree