[Python-Dev] Problem with _PyTrash_destroy_chain ? (original) (raw)

"Martin v. Löwis" martin at v.loewis.de
Fri Aug 31 00:21:54 CEST 2012


Am 30.08.12 22:22, schrieb Manu:

That's right, sorry. The reason why I think this is a double free is that the op seems to point to an object that has been deallocated by python.

(gdb) select-frame 0 (gdb) print *op $6 = {obnext = 0x0, obprev = 0x0, obrefcnt = 0, obtype = 0x2364020}

Doesn't look like that to me. If it was deallocated, the debug malloc would fill it with DEADBYTE (0xDB). So the memory has not been deallocated (yet?). The object was just unlinked from the all-objects list (or the pointers were overwritten with NULL by some buggy code of yours).

If the object had properly been unlinked before, its refcount would have been set to 0. In turn, the DECREF call that caused the second deallocation would have complained "UNREF negative refcnt" just above the line where it crashed.

So it's rather unlikely that an earlier ForgetReference had happened, unless someone has INCREFed the object again in-between. This is actually plausible: the trashcan defers deallocation, allowing for a double drop-refcount-to-zero operation. Without the trashcan, the object gets deallocated, the refcount overwritten with DEADBYTE, the bogus INCREF and the second DECREF happen, the refcount isn't 0 then, so there is no second deallocation.

Since there apparently is still a reference from a frame, the first forgetreference was actually bogus; the object shouldn't have been released yet. So you are missing an INCREF somewhere.

It would then be interesting to find out what object used to be there. Unfortunately, there is no easy way to find out (unless the crash always involves 0x4dc7bc0).

Not sure why you know this address by heart ;) but the op pointer points exactly there in the stacktrace I posted in the bug report. I'd bet it's like this every time. What does it mean ?

It means that it's a deterministic failure, which is a good thing from a debugging point of view. You can set a watchpoint on the refcount, and watch it go 0, then 1, then 0 again. If you are unfamiliar with watchpoints, here is the rough guide:

  1. Find the address of ob_refcnt, i.e. &op->ob_refcnt. I think it should be (int*)0x4dc7bc8, but please double-check.
  2. watch (int)0x4dc7bc8
  3. run, continue, continue, ...

In this form, this typically doesn't work, since the address has typically no memory associated initially. So you need to set a break point on a function that is called closely before the object gets allocated, and set the watchpoint only then.

Good luck, Martin



More information about the Python-Dev mailing list