Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

python 3.x - Calling Cython function from C code raises segmentation fault

I'm trying to call cython (cdef) function in C program. When the cdef function contains python statements, e.g. print(0.5), or python (def) functions, calling the (cdef) function raises a segmentation fault.

The .pyx file:

# cython: language_level=3

cdef public double PI = 3.1415926

cdef public double get_e():
    print("calling get_e()")
    return 2.718281828

The .c file:

#include "Python.h"
#include "transcendentals.h"
#include <math.h>
#include <stdio.h>

int main(int argc, char **argv) {
  Py_Initialize();
  PyInit_transcendentals();
  printf("pi**e: %f
", pow(PI, get_e()));
  Py_Finalize();
  return 0;
}

The compiling commands:

cython transcendentals.pyx

gcc -I. -I/usr/include/python3.5m -I/usr/include/python3.5m 
-Wno-unused-result -Wsign-compare 
-g -fstack-protector-strong -Wformat 
-Werror=format-security -DNDEBUG -g 
-fwrapv -O3 -Wall -Wstrict-prototypes 
-L/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu 
-L/usr/lib transcendentals.c main.c 
-lpython3.5m -lpthread -ldl -lutil -lm -Xlinker 
-export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

When I remove the print statement of get_e function, no segmentation fault would be raised. But the value of PI will be 0.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I guess you are using Cython 0.29. Since 0.29, PEP-489 multi-phase module initialisation has been enabled for Python versions >=3.5. This means, using PyInit_XXX is no longer sufficient, as you are experiencing.

Cython's documentation suggest to use inittab mechanism, i.e. your main-function should look something like:

#include "Python.h"
#include "transcendentals.h"
#include <math.h>
#include <stdio.h>

int main(int argc, char **argv) {
  int status=PyImport_AppendInittab("transcendentals", PyInit_transcendentals);
  if(status==-1){
    return -1;//error
  } 
  Py_Initialize();
  PyObject *module = PyImport_ImportModule("transcendentals");

  if(module==NULL){
     Py_Finalize();
     return -1;//error
  }

  printf("pi**e: %f
", pow(PI, get_e()));
  Py_Finalize();
  return 0;
}

Another possibility to restore the old behavior would be to define macro CYTHON_PEP489_MULTI_PHASE_INIT=0 and thus overriding the default by e.g. passing -DCYTHON_PEP489_MULTI_PHASE_INIT=0 to gcc on the command line.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...