3

I have a C++ library which uses Python callbacks. The callback, i.e. PyObject*, is stored in an object of class UnaryFunction, and the constructor Py_INCREFs it. The destuctor Py_XDECREFs it. That's the problem. The interpreter segfaults on that DECREF.

My solution is to just not DECREF it, but that seems wrong. What is the proper way to INC/DEC the reference count of a function, and more importantly, why does the interpreter try to GC a function body when there are other live references to it?

Edit: On Linux instead of a segfault I get an assertion fail that says:

python: Objects/funcobject.c:442: func_dealloc: Assertion 'g->gc.gc_refs != (-2)' failed.

3
  • This seems like a question for the mailing list. Google "Python mailing list". On there you can find people who know Python very well, sometimes even the creators/devs of Python themselves. Commented Sep 8, 2011 at 2:06
  • related: stackoverflow.com/questions/7326762/… Commented Sep 8, 2011 at 3:21
  • @J.F.Sebastian, good guess but the method does not go out of scope. The problem is exhibited in a simple flat script with a simple `def myfunc(x):". If I comment out the parts that use the callback then I can call myfunc() through the end of the script. Commented Sep 8, 2011 at 20:45

2 Answers 2

1

A crash does not necessary mean that it is trying to GC an used object. It can also mean that you are calling python code without the interpretor lock.

Calling Py_XDECREF in a destructor leads me to think you have something like this:

void MyCallback(myfunc, myarg)
{
    ...
    PyGILState_STATE gilstate = PyGILState_Ensure();
    try {
            myfunc(myarg);
    } catch (...) {
        ...
    }
    PyGILState_Release(gilstate);

    // myfunc goes out of scope here --> CRASH because we no longer own the GIL
}

with the simple solution:

...
try {
    scopefunc = myfunc;
    myfunc = emptyfunc();
    scopefunc(myarg);
} ...
Sign up to request clarification or add additional context in comments.

2 Comments

Actually, I do not touch the GIL at all. From what I understand the GIL does not get released unless it's explicitly released. My C++ code simply uses PyEval_CallObject() to call the function. I say it's collected because the segfault is: Objects/funcobject.c:442: func_dealloc: Assertion 'g->gc.gc_refs != (-2)' failed. and that's talking about a dealloc and GC references.
If you have just one thread then things should be simpler. You have to find the mismatched incref/decref, and calling sys.getrefcount before and after each step that involves the function could give you some clues
0

It appears the Py_INCREF simply doesn't actually increment the refcount.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.