I'm trying to figure out why I can't simply get and set the python path through its C API. I am using Python3.6, on Ubuntu 17.10 with gcc version 7.2.0. Compiling with:
gcc pytest.c `python3-config --libs` `python3-config --includes`
#include <Python.h> int main() { Py_Initialize(); // removes error if put after Py_SetPath printf("setting path\n"); // prints Py_SetPath(L"/usr/lib/python3.6"); // Error in `./a.out': free(): invalid size: 0x00007fd5a8365030 *** printf("success\n"); // doesn't print return 0; } Setting the path works fine, unless I also try to get the path prior to doing so. If I get the path at all, even just to print without modifying the returned value or anything, I get a "double free or corruption" error.
Very confused. Am I doing something wrong or is this a bug? Anyone know a workaround if so?
Edit: Also errors after calling Py_Initialize();. Updated code. Now errors even if I don't call Py_GetPath() first.
2 Answers
[the below answer refers to this version of the question.]
From the docs:
void Py_Initialize()Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions; with the exception of
Py_SetProgramName(),Py_SetPythonHome()andPy_SetPath().
But the code you show does call Py_GetPath() before it calls Py_Initialize();, which it per the above paragraph implicitly should not.
From alk it seems related to this bug:
Here is the workaround I am using. Since you can't call Py_GetPath() before Py_Initialize(), and also seemingly you can't call Py_SetPath() after Py_Initialize(), you can add to or get the path like this after calling Py_Initialize():
#include <Python.h> int main() { Py_Initialize(); // get handle to python sys.path object PyObject *sys = PyImport_ImportModule("sys"); PyObject *path = PyObject_GetAttrString(sys, "path"); // make a list of paths to add to sys.path PyObject *newPaths = PyUnicode_Split(PyUnicode_FromWideChar(L"a:b:c", -1), PyUnicode_FromWideChar(L":", 1), -1); // iterate through list and add all paths for(int i=0; i<PyList_Size(newPaths); i++) { PyList_Append(path, PyList_GetItem(newPaths, i)); } // print out sys.path after appends PyObject *newlist = PyUnicode_Join(PyUnicode_FromWideChar(L":", -1), path); printf("newlist = %ls\n", PyUnicode_AsWideCharString(newlist, NULL)); return 0; }