I have a python function that uses ctypes to call some c code
The python code looks like:
import numpy as np
from ctypes import *
dll=cdll.LoadLibrary("./test.so")
def callTestFunction():
out=np.zeros(shape=(10),dtype=np.float32)
dll.testFunction(out.ctypes.data,10)
return out
And the c code looks like
void testFunction(float values[], int l){
for(int i=0;i<l;i++){
values[i]=1;
}
}
This code works fine if I run python and call the function.
But when I import the same code and call the function inside of mod_wsgi, I get a segmentation fault.
I have already set WSGIApplicationGroup %{GLOBAL}
and if I capture the segfault in httpd using gdb, it says
#0 0x00007fffc9fa9bad in testFunction (values=0x563e93b0, l=10) at test.c:63
63 values[i]=1;
(gdb) print *values@10
Cannot access memory at address 0x563e93b0
My guess is Apache is enforcing some kind of memory boundary between my python code and my c library? Does anyone have a solution for this, or know of a better way to return an array from c to python inside of mod_wsgi?
Update:
I added print statements to python and c to print out sizeof(c_void_p), out.ctypes.data, and values.
in ipython
out.ctypes.data 0x23dde40
sizeof(c_void_p) 8
values (in c): 23dde40
in apache
[Sun May 10 17:37:01.647440 2020] [wsgi:error] [pid 7101] [client 127.0.0.1:60346] out.ctypes.data 0x55555645f7c0
[Sun May 10 17:37:01.647592 2020] [wsgi:error] [pid 7101] [client 127.0.0.1:60346] sizeof(c_void_p) 8
...
(gdb) p values
$1 = (float *) 0x5645f7c0
So there is a difference in Apache! 0x55555645f7c0 vs 0x5645f7c0
If I look at the correct memory location in GDB, it looks promising!
(gdb) p *0x55555645f7c0@40
$2 = {0 <repeats 40 times>}
Turns out I need to cast out.ctypes.data as c_void_p!
Corrected python code:
import numpy as np
from ctypes import *
dll=cdll.LoadLibrary("./test.so")
def callTestFunction():
out=np.zeros(shape=(10),dtype=np.float32)
dll.testFunction(c_void_p(out.ctypes.data),c_int(10))
return out
I still have no idea why this works in ipython, but not Apache.