2

최근에 저속 Python 코드를 C 확장자로 변환했습니다. 이것은 return 문에서 162 번째 호출에서 segfault를 생성한다는 점을 제외하면 아름답게 작동합니다.Python C 확장 : return PyFloat_FromDouble (double) segfault

다음은 작동 방식입니다. 일단, I는 연산 할 함수의 모든 호출에 앞서, I는 (부모 오브젝트 INCREF하는 기억) 메모리로 데이터를로드

static PyObject *grm_loadDosage(PyObject *self, PyObject *args) { 
/*** 
Load the dosage matrix into global memory 
Global variables: DOSAGES_PYMAT - will be a pointer to the PyArrayObject of the dosage array (must incref this) 
        DOSAGES - will be a pointer to the double array underlying DOSAGES_PYMAT 
***/ 
PyArrayObject *dosageMatrixArr; 
if (! PyArg_ParseTuple(args,"O",&DOSAGES_PYMAT_OBJ)) return NULL; 
if (NULL == DOSAGES_PYMAT_OBJ) return NULL; 

Py_INCREF(DOSAGES_PYMAT_OBJ); 

/* from PyObject to Python Array */ 
dosageMatrixArr = pymatrix(DOSAGES_PYMAT_OBJ); 
/* get the row and col sizes */ 
N_VARIANTS = dosageMatrixArr->dimensions[0]; 
N_SAMPLES = dosageMatrixArr->dimensions[1]; 
DOSAGES = pymatrix_to_Carray(dosageMatrixArr); 
Py_RETURN_TRUE; 
} 

합니다 (C 배열 방법 http://www.scipy.org/Cookbook/C_Extensions/NumPy_arrays 참조). 그때 내가 파이썬에서 호출 할 함수에서로드를 두 번 [] [], 복용량을 참조 :

디버그 문의 톤으로
static PyObject *grm_calcdistance(PyObject *self, PyObject *args) { 
/** Given column indeces (samples) of DOSAGES, and an array of row indeces (the variants missing for one or both), 
    calculate the distance **/ 
int samI,samJ,nMissing, *missing; 
PyObject *missingObj; 
PyArrayObject *missingArr; 
printf("debug1\n"); 
if (! PyArg_ParseTuple(args,"iiOi",&samI,&samJ,&missingObj,&nMissing)) return NULL; 
if (NULL == missingObj) return NULL; 
missingArr = pyvector(missingObj); 
missing = pyvector_to_Carray(missingArr); 
double replaced1[nMissing]; 
double replaced2[nMissing]; 
printf("debug2\n"); 

int missingVectorIdx; 
int missingVariantIdx; 
// for each sample, store the dosage at the missing site (as it could be missing 
// in the OTHER sample), and replace it with 0.0 in the dosage matrix 
for (missingVectorIdx = 0; missingVectorIdx < nMissing; missingVectorIdx++) { 
    printf("debugA: %d < %d\n",missingVectorIdx,nMissing); 
    missingVariantIdx = missing[missingVectorIdx]; 
    replaced1[missingVariantIdx] = DOSAGES[missingVariantIdx][samI]; 
    replaced2[missingVariantIdx] = DOSAGES[missingVariantIdx][samJ]; 
    printf("debugB\n"); 
    DOSAGES[missingVariantIdx][samI]=0.0; 
    DOSAGES[missingVariantIdx][samJ]=0.0; 
} 

// calculate the distance (this uses DOSAGES which we just modified) 
double distance = _calcDistance(samI,samJ); 

printf("debug3\n"); 
// put the values that we replaced with 0.0 back into the matrix 
for (missingVectorIdx = 0; missingVectorIdx < nMissing; missingVectorIdx++) { 
    missingVariantIdx = missing[missingVectorIdx]; 
    DOSAGES[missingVariantIdx][samI] = replaced1[missingVariantIdx]; 
    DOSAGES[missingVariantIdx][samJ] = replaced2[missingVariantIdx]; 
} 
printf("debug4: %f\n",distance); 
// grab the python object wrapper and return it 
PyObject * distPy = PyFloat_FromDouble((double)distance); 
printf("debug5\n"); 
if (NULL == distPy) 
    printf("and is NULL\n"); 
return distPy; 

} 

은 (당신이 보는 것을) 나는 return 문에 세그먼트 폴트를 지역화했습니다. 즉, python float 객체의 인스턴스를 만든 후, C에서 return을 호출하는 것과 python의 다음 실행 된 라인을 호출 한 것 사이에 있습니다 (즉, 당신은 print ("debugReturned")라고 추측합니다.) stdout에서 볼 수있는 것은 :

debug4: -0.025160 
debug5 
Segmentation fault 

그래서 배는 NULL이 아니다, 파이썬 개체가 제대로 생성 이상한 값이 아니라 몇 가지 오류가 C에서 반환하고, 파이썬에서 계속 사이에있다. 소스 온라인 이것은 INCREF 될 수 있음을 시사/DECREF 문제뿐만 아니라 PyFloat_FromDouble()과 Py_BuildValue ("f", double)가 새로운 참조를 생성하므로 INCREF 될 필요가 없습니다. 두 옵션 모두 동일한 결과를 생성합니다. 내 grm_loadDosage 함수 중에 내 행렬을 유지하는 PyObject를 INCREF해야합니다. INCREF를 사용하거나 사용하지 않고 시도했습니다. 같은 행동으로

아이디어가 있습니까?

감사 또한

하는 스택 트레이스 :

#0 0x0000000000000000 in ??() 
#1 0x000000000045aa5c in PyEval_EvalFrameEx (f=0x2aaae1ae3f60, throwflag=<value optimized out>) at Python/ceval.c:2515 
#2 0x000000000045ecb4 in call_function (f=0x3fb7494970227c55, throwflag=<value optimized out>) at Python/ceval.c:4009 
#3 PyEval_EvalFrameEx (f=0x3fb7494970227c55, throwflag=<value optimized out>) at Python/ceval.c:2692 
#4 0x000000000045ecb4 in call_function (f=0x95c880, throwflag=<value optimized out>) at Python/ceval.c:4009 
#5 PyEval_EvalFrameEx (f=0x95c880, throwflag=<value optimized out>) at Python/ceval.c:2692 
#6 0x000000000045f626 in PyEval_EvalCodeEx (_co=0x98abe0, globals=<value optimized out>, locals=<value optimized out>, args=0x0, argcount=0, kws=0x0, kwcount=0, defs=0x0, defcount=0, kwdefs=0x0, 
    closure=0x0) at Python/ceval.c:3350 
#7 0x000000000045f74b in PyEval_EvalCode (co=0x146b098, globals=0x71, locals=0xc7) at Python/ceval.c:767 
#8 0x0000000000482fab in run_mod (fp=0x881b80, filename=0x2aaaae257de0 "/humgen/gsa-hphome1/chartl/projects/t2d/gcta/resources/bin/cGRM/calculateGRM.py", start=<value optimized out>, 
    globals=0x81e340, locals=0x81e340, closeit=1, flags=0x7fffffffbfd0) at Python/pythonrun.c:1783 
#9 PyRun_FileExFlags (fp=0x881b80, filename=0x2aaaae257de0 "/humgen/gsa-hphome1/chartl/projects/t2d/gcta/resources/bin/cGRM/calculateGRM.py", start=<value optimized out>, globals=0x81e340, 
    locals=0x81e340, closeit=1, flags=0x7fffffffbfd0) at Python/pythonrun.c:1740 
#10 0x0000000000483268 in PyRun_SimpleFileExFlags (fp=<value optimized out>, filename=0x2aaaae257de0 "/humgen/gsa-hphome1/chartl/projects/t2d/gcta/resources/bin/cGRM/calculateGRM.py", closeit=1, 
    flags=0x7fffffffbfd0) at Python/pythonrun.c:1265 
#11 0x00000000004964d7 in run_file (argc=<value optimized out>, argv=0x7df010) at Modules/main.c:297 
#12 Py_Main (argc=<value optimized out>, argv=0x7df010) at Modules/main.c:692 
#13 0x000000000041563e in main (argc=11, argv=0x7fffffffc148) at ./Modules/python.c:59 
+1

분명히 잘못된 것은 없습니다. 전체 C 소스와 Python 예제를 게시하여 문제를 로컬에서 재현하는 것을 도와야합니다. –

답변

1

내가 시도하고 코드에 Valgrind의 실행하는 것이 좋습니다 파이썬으로, 나는 방법을 잘 받았음을 수행하는 방법에 대한 How can I use valgrind with Python C++ extensions? 을 볼 것이다 exeoption list는 python 3에 유용합니다. 어쨌든, 파일의 일부가없는 부품의 모든 출력을 무시하십시오. Windows를 사용하는 경우

나는이 Is there a good Valgrind substitute for Windows?

오류가 함수가 반환 한 후 발생 하더군요했던 디버깅 중 하나를 추천 할 것입니다. 왜 return 문 자체가 문제가되는지 나는 알 수 없다. stacktrace에 따른 오류의 원인은 python-3 자체의 일부 코드에 있습니다. 나는 python-3 자체에 버그가 없다고 가정합니다. 이것을 더 이상 배제하기 위해 python-3의 다른 버전을 설치하려고 할 수 있습니다. 그래서 저는 여러분이 스택이나 힙 (heap)을 손질했다고 가정합니다. 이것은 valgrind가 유용하게 사용하는 것입니다.