2012-12-04 4 views
2

ctypes에서 호출하는 c 함수에서 파이썬 개체를 인스턴스화 할 때 포함 된 파이썬 3.3 프로그램 segfaults.ctypes를 통해 호출 된 c 함수 내에서 파이썬 개체 인스턴스화

인터프리터를 설정 한 후, 나는 성공적 주요 C에서 파이썬 지능 (뿐만 아니라 사용자 정의 C 확장 유형)를 인스턴스화 할 수 있습니다 :

#import <Python/Python.h> 

#define LOGPY(x) \ 
{ fprintf(stderr, "%s: ", #x); PyObject_Print((PyObject*)(x), stderr, 0); fputc('\n', stderr); } 

// c function to be called from python script via ctypes. 
void instantiate() { 
    PyObject* instance = PyObject_CallObject((PyObject*)&PyLong_Type, NULL); 
    LOGPY(instance); 
} 

int main(int argc, char* argv[]) { 
    Py_Initialize(); 
    instantiate(); // works fine 

    // run a script that calls instantiate() via ctypes. 
    FILE* scriptFile = fopen("emb.py", "r"); 
    if (!scriptFile) { 
    fprintf(stderr, "ERROR: cannot open script file\n"); 
    return 1; 
    } 

    PyRun_SimpleFileEx(scriptFile, scriptPath, 1); // close on completion 
    return 0; 
} 

그때 PyRun_SimpleFileEx를 사용하여 파이썬 스크립트를 실행합니다. 잘 실행 표시하지만하는 ctypes, PyObject_CallObject 내부 프로그램 세그먼테이션 폴트 (segfault)를 통해 인스턴스화()를 호출 할 때 :

import ctypes as ct 
dy = ct.CDLL('./emb') 
dy.instantiate() # segfaults 

lldb 출력 :

instance: 0 
Process 52068 stopped 
* thread #1: tid = 0x1c03, 0x000000010000d3f5 Python`PyObject_Call + 69, stop reason = EXC_BAD_ACCESS (code=1, address=0x18) 
    frame #0: 0x000000010000d3f5 Python`PyObject_Call + 69 
Python`PyObject_Call + 69: 
-> 0x10000d3f5: movl 24(%rax), %edx 
    0x10000d3f8: incl %edx 
    0x10000d3fa: movl %edx, 24(%rax) 
    0x10000d3fd: leaq 2069148(%rip), %rax  ; _Py_CheckRecursionLimit 
(lldb) bt 
* thread #1: tid = 0x1c03, 0x000000010000d3f5 Python`PyObject_Call + 69, stop reason = EXC_BAD_ACCESS (code=1, address=0x18) 
    frame #0: 0x000000010000d3f5 Python`PyObject_Call + 69 
    frame #1: 0x00000001000d5197 Python`PyEval_CallObjectWithKeywords + 87 
    frame #2: 0x0000000201100d8e emb`instantiate + 30 at emb.c:9 

왜 전화가 (인스턴스화 않습니다를)에서 실패 ctypes 만? 이 함수는 파이썬 lib를 호출 할 때만 충돌하기 때문에 아마도 일부 인터프리터 상태가 ctypes FFI 호출에 의해 방해 받고있을 것입니다.

+0

dy_test()는 어떻게 인스턴스화됩니까? 인스턴스 메시지를 통해 온다면, 로그 메시지는 PyObject_CallObject가 완료되었음을 보여줍니다. 그렇지 않으면 LOGPY 출력을 볼 수 없습니다. 파이썬에서 PyLongObject 또는 다른 표준 호출 가능 함수를 사용할 수 있습니까? 그게 당신의 타입 설정에 문제가 있는지 말해 줄 것입니다. –

+0

죄송합니다. 질문의 명확성을 위해 dy_test의 이름을 변경했습니다. 결정된. PyLong_Type을 전달하는 것과 같은 방식으로 실패합니다. 나는 그에 따라 복부를 줄일 것이다. – gwk

+2

'CDLL'을'PyDLL'으로 바꾸면 더 잘 작동합니까? –

답변

2

힌트는 Armin Rigo에게 감사드립니다. 문제는 ctypes.CDLL()을 통해로드 된 라이브러리가 원시 코드를 호출 할 때 GIL을 해제하는 함수를 작성한다는 것입니다. 내가 말할 수있는 한, 네이티브 함수가 파이썬 코드를 다시 호출하기 위해서는 파이썬 C API를 사용하여 GIL을 먼저 얻어야합니다.

더 쉬운 대안은 GIL을 해제하지 않는 ctypes.PyDLL()을 사용하는 것입니다 (파이썬 오류 플래그도 검사합니다). 문서는 "따라서 파이썬 C API 함수를 직접 호출하는 것만 유용합니다." 내 코드는 파이썬 코드가 파이썬 C API를 호출하는 내 자신의 C 함수로 호출한다는 점에서 간접적 인 것이지만 문제는 동일합니다.

관련 문제