[issue45061] [C API] Detect refcount bugs on True/False in C extensions

STINNER Victor report at bugs.python.org
Wed Sep 1 10:27:00 EDT 2021


STINNER Victor <vstinner at python.org> added the comment:

Christian Tismer: "What about an even more flexible solution? A debug option could memorize always the last object deallocated and give full info (the object's repr) before the crash would happen."

Bugs in object_dealloc() are rare. Apart None, True and False, do you know other objects which must not be deleted?

Calling repr(obj) can crash during late Python finalization for many reasons.

It is slow and can consume significant memory. Not all object types detect loops (a container storing indirectly itself) and so it can fail with a MemoryError: repr() is not "safe".

Using gdb, it is easy to dump the object currently being deleted: go the object_dealloc() frame and use "print self" command.

Example using attached os_uname_refcount_bug.patch:
------------
$ gdb ./python
(...)
(gdb) run
>>> import os; os.uname()
>>> exit()

Debug memory block at address p=0x886e60: API ''
    0 bytes originally requested
    The 7 pad bytes at p-7 are not all FORBIDDENBYTE (0xfd):
        at p-7: 0x00 *** OUCH
        at p-6: 0x00 *** OUCH
        at p-5: 0x00 *** OUCH
        at p-4: 0x00 *** OUCH
        at p-3: 0x00 *** OUCH
        at p-2: 0x00 *** OUCH
        at p-1: 0x00 *** OUCH
    Because memory is corrupted at the start, the count of bytes requested
       may be bogus, and checking the trailing pad bytes may segfault.
    The 8 pad bytes at tail=0x886e60 are not all FORBIDDENBYTE (0xfd):
        at tail+0: 0x00 *** OUCH
        at tail+1: 0x00 *** OUCH
        at tail+2: 0x00 *** OUCH
        at tail+3: 0x00 *** OUCH
        at tail+4: 0x00 *** OUCH
        at tail+5: 0x00 *** OUCH
        at tail+6: 0x00 *** OUCH
        at tail+7: 0x00 *** OUCH

Enable tracemalloc to get the memory block allocation traceback

Fatal Python error: _PyMem_DebugRawFree: bad ID: Allocated using API '', verified using API 'o'
Python runtime state: finalizing (tstate=0x00000000008e1a80)

Current thread 0x00007ffff7c24740 (most recent call first):
  Garbage-collecting
  <no Python frame>

Program received signal SIGABRT, Aborted.
0x00007ffff7c662a2 in raise () from /lib64/libc.so.6

(...)

(gdb) frame 9
#9  0x0000000000499dd7 in object_dealloc (self=True)
    at Objects/typeobject.c:4497
4497	    Py_TYPE(self)->tp_free(self);

(gdb) print self
$2 = True
------------

----------

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue45061>
_______________________________________


More information about the Python-bugs-list mailing list