-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Open
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
What happened?
A custom __index__ can swap the MRO of an array.array subclass mid multiplication, so array_repeat calls find_array_state_by_type on a type without the array module and receives a NULL module state. The subsequent dereference of state->ArrayType then hits freed memory and triggers a null pointer read.
Proof of Concept:
import array
class Good(array.array):
pass
class Hide(type):
def mro(cls):
return (cls, object)
class Bad(Good, metaclass=Hide):
pass
arr = Good('b', b'x')
class Count:
def __index__(self):
arr.__class__ = Bad # Drop array.array from the MRO mid-op
return 2
arr * Count()Affected Versions:
Details
| Python Version | Status | Exit Code |
|---|---|---|
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 27 2025, 21:34:13) |
OK | 0 |
Python 3.10.19+ (heads/3.10:014261980b1, Oct 27 2025, 21:19:00) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 27 2025, 21:20:35) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 27 2025, 21:27:07) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 27 2025, 21:28:49) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.14.0+ (heads/3.14:2e216728038, Oct 27 2025, 21:30:55) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 27 2025, 21:32:37) [Clang 18.1.3 (1ubuntu1)] |
ASAN | 1 |
Related Code Snippet
Details
#define find_array_state_by_type(tp) \
(get_array_state(PyType_GetModuleByDef(tp, &arraymodule))) // requires array.array in the MRO
static array_state *
get_array_state(PyObject *module)
{
return (array_state *)_PyModule_GetState(module); // assumes module is non-NULL
}
static PyObject *
array_repeat(PyObject *op, Py_ssize_t n)
{
arrayobject *a = arrayobject_CAST(op);
array_state *state = find_array_state_by_type(Py_TYPE(a));
if (n < 0)
n = 0;
const Py_ssize_t array_length = Py_SIZE(a);
if ((array_length != 0) && (n > PY_SSIZE_T_MAX / array_length)) {
return PyErr_NoMemory();
}
Py_ssize_t size = array_length * n;
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
if (np == NULL)
return NULL;
if (size == 0)
return (PyObject *)np;
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
const Py_ssize_t newbytes = oldbytes * n;
_PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
return (PyObject *)np;
}
Sanitizer Report
Details
=================================================================
==105120==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x77b5659592d8 bp 0x7ffe28c17cf0 sp 0x7ffe28c17cf0 T0)
==105120==The signal is caused by a READ memory access.
==105120==Hint: address points to the zero page.
#0 0x77b5659592d8 in _Py_TYPE Include/object.h:277
#1 0x77b5659592d8 in Py_IS_TYPE Include/object.h:302
#2 0x77b5659592d8 in PyObject_TypeCheck Include/object.h:432
#3 0x77b565959317 in _PyModule_GetState Include/internal/pycore_moduleobject.h:38
#4 0x77b56595936b in get_array_state Modules/arraymodule.c:75
#5 0x77b56595f09d in array_repeat Modules/arraymodule.c:970
#6 0x584ac280512b in wrap_indexargfunc Objects/typeobject.c:9651
#7 0x584ac270d606 in wrapperdescr_raw_call Objects/descrobject.c:532
#8 0x584ac270df48 in wrapperdescr_call Objects/descrobject.c:570
#9 0x584ac26eec71 in _PyObject_MakeTpCall Objects/call.c:242
#10 0x584ac2801605 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:167
#11 0x584ac2801680 in vectorcall_unbound Objects/typeobject.c:3033
#12 0x584ac281def4 in vectorcall_maybe Objects/typeobject.c:3130
#13 0x584ac2821819 in slot_nb_multiply Objects/typeobject.c:10397
#14 0x584ac26b8613 in binary_op1 Objects/abstract.c:966
#15 0x584ac26bcc64 in PyNumber_Multiply Objects/abstract.c:1170
#16 0x584ac29638f8 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:62
#17 0x584ac29b0e54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
#18 0x584ac29b1148 in _PyEval_Vector Python/ceval.c:2001
#19 0x584ac29b13f8 in PyEval_EvalCode Python/ceval.c:884
#20 0x584ac2aa8507 in run_eval_code_obj Python/pythonrun.c:1365
#21 0x584ac2aa8723 in run_mod Python/pythonrun.c:1459
#22 0x584ac2aa957a in pyrun_file Python/pythonrun.c:1293
#23 0x584ac2aac220 in _PyRun_SimpleFileObject Python/pythonrun.c:521
#24 0x584ac2aac4f6 in _PyRun_AnyFileObject Python/pythonrun.c:81
#25 0x584ac2afd74d in pymain_run_file_obj Modules/main.c:410
#26 0x584ac2afd9b4 in pymain_run_file Modules/main.c:429
#27 0x584ac2aff1b2 in pymain_run_python Modules/main.c:691
#28 0x584ac2aff842 in Py_RunMain Modules/main.c:772
#29 0x584ac2affa2e in pymain_main Modules/main.c:802
#30 0x584ac2affdb3 in Py_BytesMain Modules/main.c:826
#31 0x584ac2583645 in main Programs/python.c:15
#32 0x77b56622a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#33 0x77b56622a28a in __libc_start_main_impl ../csu/libc-start.c:360
#34 0x584ac2583574 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: 202d5dbb945f6d5f5a66ad50e2688d56affd6ecb)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV Include/object.h:277 in _Py_TYPE
==105120==ABORTINGMetadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump