0

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.

Logan
  • 1
  • 1
  • how about printing the address of `out.ctypes.data` too. Also, you do know that you're supposed to set the argument and return types, though the default promotions for *these* arguments should be fine. – Antti Haapala -- Слава Україні May 10 '20 at 07:54
  • Add `print(sizeof(c_void_p))` as 1st line of *callTestFunction* and update the question with the outputs (in both cases). – CristiFati May 10 '20 at 09:54
  • Thanks! sizeof(c_void_p) was the same for both, but for some reason I need to explicitly cast out.ctypes.data for it to work in apache. – Logan May 10 '20 at 17:53
  • That's not it. It only works by coincidence. Check [\[SO\]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer)](https://stackoverflow.com/questions/58610333/c-function-called-from-python-via-ctypes-returns-incorrect-value/58611011#58611011). This seems very much like a duplicate. – CristiFati May 10 '20 at 18:13

0 Answers0