1

I'm trying to create C code that creates an Python xmlrpc client and calls methods on the xmlrpc server (I'm thinking of using this as IPC for a hook DLL).

Here's the code ... I'm not going to layer in reference counting until it works.

#include <Python.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

static PyObject *xmlrpc_server_proxy = NULL;
static PyObject *set_server_proxy(void);
static void say_hi(void);

int main()
{
    xmlrpc_server_proxy = set_server_proxy();
    say_hi();
    return 0;
}

static PyObject *
set_server_proxy()
{
        PyObject *xmlrpc_client_mod, *xmlrpc_server_proxy_class, *location, *args;
        PyObject *result;
        Py_Initialize();
        xmlrpc_client_mod = PyImport_ImportModule("xmlrpc.client");
        xmlrpc_server_proxy_class = PyObject_GetAttrString(xmlrpc_client_mod, "ServerProxy");
        location = PyUnicode_FromString("http://127.0.0.1:8000/");
        args = Py_BuildValue("(O)", location);
        result = PyObject_CallObject(xmlrpc_server_proxy_class, args);
        Py_Finalize();
        return result;
}

static void say_hi()
{
    PyObject_CallMethod(xmlrpc_server_proxy, "say_hi", "()");
}

I've confirmed that my Python xmlrpc server works fine when called from another Python server proxy. When I try to run the above executable, it crashes on the PyObject_CallMethod(). Why?

1
  • My initial instinct is that PyObject_CallObject() or one of the Py* functions in set_server_proxy() is calling is returning NULL. You should check the return of each of the Py* functions to see what is returning NULL as it might give an insight into calling a function incorrectly. Commented Mar 30, 2011 at 22:57

1 Answer 1

2

Near the end of set_server_proxy() you are calling Py_Finalize() which destroys the interpreter, and subsequently you are calling say_hi() which assumes the interpreter still exists. When the Python interprer code attempts to raise an error, the PyErr_Occurred() function gets a pointer to the current thread state, which is NULL; it dereferences it and this generates the segfault.

Move your interpreter initialization calls inside the main() function:

int main()
{
    Py_Initialize();
    xmlrpc_server_proxy = set_server_proxy();
    say_hi();
    Py_Finalize();
    return 0;
}

Secondarily, if you are trying to use Python's standard xmlrpclib.ServerProxy you may need to change your import to:

xmlrpc_client_mod = PyImport_ImportModule("xmlrpclib");
Sign up to request clarification or add additional context in comments.

3 Comments

Is there another way to use the interpreter to create a Python object that sticks around after the interpreter is gone? Given that this will be implemented in a hook DLL, I'm not sure I can move Py_Initialize out of the called function (unless it can go in Dllmain, which I'm not sure it can).
I don't think that's possible in the vast majority of cases (maybe in some edge cases). PyObject_CallMethod internally makes calls to other functions which depend directly on the interpreter state. Perhaps you can link the interpreter's lifespan to the DllMain DLL_PROCESS_ATTACH / DLL_PROCESS_DETACH events?
Moving both Py_Initialize and set_server_proxy() into DLL_PROCESS_ATTACH and Py_Finalize into DLL_PROCESS_DETACH seemed to work ... now using xmlrpc to monitor Vista Windows API calls without having to deal with any UAC. Thanks for the help.

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.