Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Python crash while returning a C string?

Tags:

python

c

ctypes

Here's my C code, I made a shared lib out of it. When I load the shared lib in Python and execute the Python code below, I crash. Why?

extern "C" { 
PyObject* foo2(char* b) 
{
  return Py_BuildValue("s", b);
}

}

And here's what I am doing in Python:

   from ctypes import *
   d = cdll.LoadLibrary('./foo.so')
   d.foo2.restype = c_char_p
   v  = d.foo2('hello world')
   print pythonapi.PyString_Size(v)

If it helps, I am at Python2.6.

like image 221
Fanatic23 Avatar asked May 21 '15 18:05

Fanatic23


2 Answers

Your problem is that you're lying about the return type:

d.foo2.restype = c_char_p

The actual return type is PyObject *. But ctypes is going to see that c_char_p, cast the PyObject * to a char *, and then try to convert that char * to a string with PyString_FromString, which is going to read who knows what arbitrary bytes until it hits a NUL character.

The way to specify a PyObject * is with py_object.

Also, you probably want to set the argtypes. And this time, it really is a c_char_p:

d = cdll.LoadLibrary('./foo.so')
d.foo2.argtypes = [c_char_p]
d.foo2.restype = py_object

But, as interjay points out in a comment, it's a bit silly to be building a C library that uses the Python C API and then calling it via ctypes. This is occasionally useful, but normally, the solution is to just finish building a C extension module instead of doing 80% of the work for none of the benefit…

like image 194
abarnert Avatar answered Nov 06 '22 14:11

abarnert


You are telling cdll that the function returns a char* but in actual fact it returns a PyObject*. The two need to be in agreement.

like image 44
NPE Avatar answered Nov 06 '22 12:11

NPE