Closed
Description
Crash report
What happened?
Version
Python 3.13.0a3+ (heads/v3.13.0a2:e2c4038924, Feb 10 2024, 12:05:47) [GCC 11.4.0]
bisect from commit 32ea165
Root cause
the deque_index_impl
function retrieves an element from the deque using b→data
. However, the reference count of the item may decrease due to PyObject_RichCompareBool
, leading to a use-after-free
static PyObject * deque_index_impl(dequeobject *deque, PyObject *v, Py_ssize_t start, Py_ssize_t stop){ ... while (n--) { CHECK_NOT_END(b); item = b->data[index]; // <--- don't raise reference count using Py_NewRef cmp = PyObject_RichCompareBool(item, v, Py_EQ); // <--- arbitrary call to __eq__ if (cmp > 0) return PyLong_FromSsize_t(stop - (n + 1)); else if (cmp < 0) return NULL; if (start_state != deque->state) { PyErr_SetString(PyExc_RuntimeError, "deque mutated during iteration"); return NULL; } }
POC
import collections class evil_pre1(object): def __eq__(self,o): deq.clear() return NotImplemented deq = collections.deque([evil_pre1()]) deq.index(3)
ASAN
asan
================================================================= ==246599==ERROR: AddressSanitizer: heap-use-after-free on address 0xffffb086b3c8 at pc 0xaaaabb857308 bp 0xffffc5757c40 sp 0xffffc5757c50 READ of size 8 at 0xffffb086b3c8 thread T0 #0 0xaaaabb857304 in Py_TYPE Include/object.h:333 #1 0xaaaabb857304 in long_richcompare Objects/longobject.c:3265 #2 0xaaaabb8c1158 in do_richcompare Objects/object.c:922 #3 0xaaaabb8c1438 in PyObject_RichCompare Objects/object.c:965 #4 0xaaaabb8c1578 in PyObject_RichCompareBool Objects/object.c:987 #5 0xaaaabbcc1a5c in deque_index_impl Modules/_collectionsmodule.c:1222 #6 0xaaaabbcc1c94 in deque_index Modules/clinic/_collectionsmodule.c.h:248 #7 0xaaaabb7f4ee4 in method_vectorcall_FASTCALL Objects/descrobject.c:401 #8 0xaaaabb7ccb84 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168 #9 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327 #10 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815 #11 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115 #12 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788 #13 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592 #14 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294 #15 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379 #16 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215 #17 0xaaaabbc08c3c in _PyRun_SimpleFileObject Python/pythonrun.c:464 #18 0xaaaabbc08ff4 in _PyRun_AnyFileObject Python/pythonrun.c:77 #19 0xaaaabbc66e68 in pymain_run_file_obj Modules/main.c:357 #20 0xaaaabbc693d8 in pymain_run_file Modules/main.c:376 #21 0xaaaabbc69de0 in pymain_run_python Modules/main.c:628 #22 0xaaaabbc6a084 in Py_RunMain Modules/main.c:707 #23 0xaaaabbc6a274 in pymain_main Modules/main.c:737 #24 0xaaaabbc6a5b0 in Py_BytesMain Modules/main.c:761 #25 0xaaaabb63145c in main Programs/python.c:15 #26 0xffffb93d73f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #27 0xffffb93d74c8 in __libc_start_main_impl ../csu/libc-start.c:392 #28 0xaaaabb63136c in _start (/home/kk/projects/cpython/python+0x27136c) 0xffffb086b3c8 is located 56 bytes inside of 72-byte region [0xffffb086b390,0xffffb086b3d8) freed by thread T0 here: #0 0xffffb96a9fe8 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127 #1 0xaaaabb8c9744 in _PyMem_RawFree Objects/obmalloc.c:84 #2 0xaaaabb8cc580 in _PyMem_DebugRawFree Objects/obmalloc.c:2398 #3 0xaaaabb8ccd74 in _PyMem_DebugFree Objects/obmalloc.c:2531 #4 0xaaaabb8f0f78 in PyObject_Free Objects/obmalloc.c:995 #5 0xaaaabbb7087c in PyObject_GC_Del Python/gc.c:1903 #6 0xaaaabb914e1c in object_dealloc Objects/typeobject.c:5569 #7 0xaaaabb938da8 in subtype_dealloc Objects/typeobject.c:2092 #8 0xaaaabb8bf0b8 in _Py_Dealloc Objects/object.c:2889 #9 0xaaaabbb69bc4 in Py_DECREF Include/object.h:922 #10 0xaaaabbb69bc4 in Py_XDECREF Include/object.h:1030 #11 0xaaaabbb69bc4 in _PyFrame_ClearExceptCode Python/frame.c:140 #12 0xaaaabbaa276c in clear_thread_frame Python/ceval.c:1652 #13 0xaaaabbaab750 in _PyEval_FrameClearAndPop Python/ceval.c:1679 #14 0xaaaabbadc91c in _PyEval_EvalFrameDefault Python/generated_cases.c.h:4914 #15 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115 #16 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788 #17 0xaaaabb7cc2fc in _PyFunction_Vectorcall Objects/call.c:413 #18 0xaaaabb94bfe0 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168 #19 0xaaaabb94bfe0 in vectorcall_unbound Objects/typeobject.c:2271 #20 0xaaaabb94bfe0 in slot_tp_richcompare Objects/typeobject.c:8983 #21 0xaaaabb8c1058 in do_richcompare Objects/object.c:916 #22 0xaaaabb8c1438 in PyObject_RichCompare Objects/object.c:965 #23 0xaaaabb8c1578 in PyObject_RichCompareBool Objects/object.c:987 #24 0xaaaabbcc1a5c in deque_index_impl Modules/_collectionsmodule.c:1222 #25 0xaaaabbcc1c94 in deque_index Modules/clinic/_collectionsmodule.c.h:248 #26 0xaaaabb7f4ee4 in method_vectorcall_FASTCALL Objects/descrobject.c:401 #27 0xaaaabb7ccb84 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168 #28 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327 #29 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815 #30 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115 #31 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788 #32 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592 #33 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294 #34 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379 #35 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215 previously allocated by thread T0 here: #0 0xffffb96aa2f4 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 #1 0xaaaabb8cb160 in _PyMem_RawMalloc Objects/obmalloc.c:56 #2 0xaaaabb8c9028 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2331 #3 0xaaaabb8c9084 in _PyMem_DebugRawMalloc Objects/obmalloc.c:2364 #4 0xaaaabb8ccdc0 in _PyMem_DebugMalloc Objects/obmalloc.c:2516 #5 0xaaaabb8f0df0 in PyObject_Malloc Objects/obmalloc.c:966 #6 0xaaaabb92e22c in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46 #7 0xaaaabb92e22c in _PyType_AllocNoTrack Objects/typeobject.c:1739 #8 0xaaaabb92e538 in PyType_GenericAlloc Objects/typeobject.c:1763 #9 0xaaaabb92830c in object_new Objects/typeobject.c:5555 #10 0xaaaabb92ec48 in type_call Objects/typeobject.c:1682 #11 0xaaaabb7cc64c in _PyObject_MakeTpCall Objects/call.c:242 #12 0xaaaabb7ccc90 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:166 #13 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327 #14 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815 #15 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115 #16 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788 #17 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592 #18 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294 #19 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379 #20 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215 #21 0xaaaabbc08c3c in _PyRun_SimpleFileObject Python/pythonrun.c:464 #22 0xaaaabbc08ff4 in _PyRun_AnyFileObject Python/pythonrun.c:77 #23 0xaaaabbc66e68 in pymain_run_file_obj Modules/main.c:357 #24 0xaaaabbc693d8 in pymain_run_file Modules/main.c:376 #25 0xaaaabbc69de0 in pymain_run_python Modules/main.c:628 #26 0xaaaabbc6a084 in Py_RunMain Modules/main.c:707 #27 0xaaaabbc6a274 in pymain_main Modules/main.c:737 #28 0xaaaabbc6a5b0 in Py_BytesMain Modules/main.c:761 #29 0xaaaabb63145c in main Programs/python.c:15 #30 0xffffb93d73f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 #31 0xffffb93d74c8 in __libc_start_main_impl ../csu/libc-start.c:392 SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:333 in Py_TYPE Shadow bytes around the buggy address: 0x200ff610d620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x200ff610d630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x200ff610d640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x200ff610d650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x200ff610d660: fa fa fa fa fd fd fd fd fd fd fd fd fd fa fa fa =>0x200ff610d670: fa fa fd fd fd fd fd fd fd[fd]fd fa fa fa fa fa 0x200ff610d680: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd 0x200ff610d690: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd 0x200ff610d6a0: fd fd fd fd fd fd fa fa fa fa 00 00 00 00 00 00 0x200ff610d6b0: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00 0x200ff610d6c0: 00 00 fa fa fa fa 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==246599==ABORTING
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Output from running 'python -VV' on the command line:
Python 3.13.0a3+ (heads/v3.13.0a2:e2c4038924, Feb 10 2024, 12:05:47) [GCC 11.4.0]