1

I've got an access violation error in a C code calling Python.

I am trying to call a sympy function from Python and handle the result in C.

#include <Python.h>

int main(int argc, char *argv[])
{
    PyObject *pmod, *pdict, *pValue;
    Py_Initialize();
    pmod  = PyImport_ImportModule("sympy");
    PyErr_Print();
    pdict = PyModule_GetDict(pmod);

    pValue = PyRun_String("x = symbols('x'); diff(cos(x), x)", Py_single_input, pdict, pdict);
    PyErr_Print();
    if (pValue != NULL) {
        //PyObject* pu = PyUnicode_AsEncodedString(pValue, "utf-8", "~E~");
        //printf("Result of call: %s\n", PyBytes_AS_STRING(pu));
        //Py_DECREF(pu);
        Py_DECREF(pValue);
        Py_DECREF(pmod);
        Py_DECREF(pdict);
    }
    else {
        PyErr_Print();
        return 1;
    }
    Py_FinalizeEx();
    return 0;
}

I would like to know the reason for this access violation and how to solve it. I would also like to know why the commented printf to show the result is not working.

My compilation line is:

gcc probe.c `python3-config --cflags` `python3-config --ldflags` -fpic

My Python version is 3.6.7.

Thanks in advance.

Ry-
  • 218,210
  • 55
  • 464
  • 476
franpena
  • 151
  • 11
  • Are you sure your access violation is in `PyRun_String`? When I run the code, it crashes in `Py_Finalize`. (I had to replace `Py_FinalizeEx` with `Py_Finalize` due to having only Python 3.5.2.) – rtoijala Jun 10 '19 at 13:05
  • @rtoijala may be you are right. I made a test with python 2.7 and PyFinalize and then the error I've got is: "Fatal Python error: deletion of interned string failed". I really don't care whether to user python 2 or 3. What I need is to get rid of the error. – franpena Jun 10 '19 at 13:16

1 Answers1

2

The problem is that you are destroying the sympy module's dictionary when you should not be. According to the documentation for PyModule_GetDict, the returned dictionary reference is borrowed, not new. Therefore you must not call Py_DECREF on it. Removing the line with Py_DECREF(pdict); fixes the issue.

More about ownership and borrowing from the Python documentation:

Ownership can also be transferred, meaning that the code that receives ownership of the reference then becomes responsible for eventually decref’ing it by calling Py_DECREF() or Py_XDECREF() when it’s no longer needed—or passing on this responsibility (usually to its caller). When a function passes ownership of a reference on to its caller, the caller is said to receive a new reference. When no ownership is transferred, the caller is said to borrow the reference. Nothing needs to be done for a borrowed reference.

rtoijala
  • 1,200
  • 10
  • 20