Repository navigation
_PyList_AsTupleAndClear does not reset allocated to 0. #145681
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorextension-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
on Mar 9, 2026 - removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errortype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
on Mar 9, 2026 _PyList_AsTupleAndClearis only used internally in CPython, so it's OK for it to only do enough to convincelist_deallocdo the right thing.That said, a bit of defensive programming shouldn't hurt.
I don't think we need to add an adjustment forself->allocated, though. We can instead skip freeing the memory & settingself->ob_itemto NULL, and leave deallocation tolist_dealloc.I don't think we need to add an adjustment for self->allocated, though. We can instead skip freeing the memory & setting self->ob_item to NULL, and leave deallocation to list_dealloc.
Ah, yeah, that makes sense to me as well.
EDIT: Now that I think about it, won't that be a problem (when we deallocate the list) since the items in the list will still "be" in
ob_itembut now belong to the resulting tuple?The bits of the pointers will “be” in
ob_item, but they'll be treated as uninitialized memory, reserved so that the next fewappends don't need to reallocate the array.
The deallocator should not look at them, much less DECREF them.Ah, I think I get it now. Sorry for the confusion -- what you mean is to remove setting
ob_itemto NULL, removeallocated = 0but keep thePy_SET_SIZEso that the list deallocator considers everything insideob_itemas uninitialised memory / not something it needs to clear. Correct? (Sorry for the back and forth.)I updated #145680 to do what you suggested.
- added a commit that references this issue
on Mar 12, 2026 Thank you!
Description
While working on our C extension, I noticed what I believe is a bug/crash in the list implementation when using
_PyList_AsTupleAndClear(which creates a list from a tuple then clears the list), sort of livestd::move-ing a Python list into a tuple.Long story short, the function sets
self->ob_item = NULLandPy_SET_SIZE(self, 0)("clear the list and disown the memory") but does NOT resetself->allocatedto 0.After this, the list "believes" it has some memory allocated but it actually has none.
If code then tries to append something to the list (through
PyList_Append),it fails because it directly writes to
self->ob_item[len]-- which is null.Currently, it seems like there's only one caller to
_PyList_AsTupleAndClear, and it discards the list right after gettings its tuple, so the bug has been flying under the radar I believe...Testing
Reproducer
To build the reproducer (from a subdir):
And to trigger it:
../python.exe -c "import ext; ext.test()"gives (I have a TSan build but it does give me what I expect...)
Next steps
I have a branch/PR ready with a fix for that: #145680.
Linked PRs
_PyList_AsTupleAndClear#145680