从 C++ 调用 scipy.stats.anderson_ksamp 时的 EXC_BAD_ACCESS 或 SIGABRT
Posted
技术标签:
【中文标题】从 C++ 调用 scipy.stats.anderson_ksamp 时的 EXC_BAD_ACCESS 或 SIGABRT【英文标题】:EXC_BAD_ACCESS or SIGABRT while calling scipy.stats.anderson_ksamp from C++ 【发布时间】:2017-06-25 12:31:42 【问题描述】:我无法弄清楚我的代码有什么问题。
我正在尝试在我用 C++ 编写的程序中使用 Python 和 numpy 的 C API 来使用来自 scipy.stats
模块的 Python 函数 anderson_ksamp
。问题是我得到了这个错误,我不知道为什么。
我设法重新创建了一小段代码,它给了我错误:
// Test.cpp
#include <Python.h>
#include <numpy/arrayobject.h>
#include <iostream>
#include <vector> // std::vector
int limited_rand(int limit)
int r, d = RAND_MAX / limit;
limit *= d;
do r = rand(); while (r >= limit);
return r / d;
void initialize_c_2d_array(int*& c_array, unsigned long row_length_c_array, std::vector<int> &row1, std::vector<int> &row2)
for (unsigned int i = 0; i < row_length_c_array; i++)
c_array[i] = row1[i];
c_array[row_length_c_array + i] = row2[i];
int main(int argc, const char * argv[])
std::vector<int> left_sample;
std::vector<int> right_sample;
for (int i = 0; i < 250; i++)
if (i < 200)
left_sample.push_back(limited_rand(200));
right_sample.push_back(limited_rand(200));
Py_Initialize();
PyObject* scipy_stats_module = PyImport_ImportModule("scipy.stats"); // importing "scipy.stats" module
if (scipy_stats_module)
import_array();
while (true)
unsigned long k = std::min(left_sample.size(), right_sample.size());
int* both_samples = (int*) (malloc(2 * k));
initialize_c_2d_array(both_samples, k, left_sample, right_sample);
npy_intp dim3[] = 2, (npy_intp) (k);
PyObject* both_samples_nparray = PyArray_SimpleNewFromData(2, dim3, NPY_INT, both_samples);
PyObject* anderson_ksamp = PyObject_GetAttrString(scipy_stats_module, "anderson_ksamp");
if (anderson_ksamp && PyCallable_Check(anderson_ksamp))
// v------- Getting EXC_BAD_ACCESS on this line ---------v
PyObject* anderson_2samp_return_val = PyObject_CallFunctionObjArgs(anderson_ksamp, both_samples_nparray, NULL);
Py_DecRef(both_samples_nparray);
free(both_samples); // <---------- Getting SIGABRT here
Py_DecRef(anderson_ksamp);
if (anderson_2samp_return_val)
double p_value = PyFloat_AsDouble(PyTuple_GetItem(anderson_2samp_return_val, 2));
Py_DecRef(anderson_2samp_return_val);
else
Py_DecRef(anderson_2samp_return_val);
printf("Call to scipy.stats.anderson_ksamp failed.\n");
PyErr_Print();
else
Py_DecRef(both_samples_nparray);
free(both_samples);
Py_XDECREF(anderson_ksamp);
std::cout << "Failed to import function scipy.stats.anderson_ksamp.\n";
PyErr_Print();
else
Py_XDECREF(scipy_stats_module);
printf("Failed to import scipy.stats module.\n");
PyErr_Print();
Py_Finalize();
return 0;
每次执行这段代码我都会得到:
free(both_samples)
上的 SIGABRT
错误并带有以下错误消息:Test(4473,0x1003713c0) malloc: *** error for object 0x10076bbb0: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
或EXC_BAD_ACCESS
PyObject* anderson_2samp_return_val = PyObject_CallFunctionObjArgs(anderson_ksamp, both_samples_nparray, NULL);
。
我认为问题可能出在我对数组 both_samples
的初始化上,因为在我的主脚本中,我还使用了 scipy
函数 ks_2samp
,其代码与这里的代码完全相同,只有ks_2samp
将两个数组作为参数的区别,所以我不需要像在这里那样创建二维数组。
我注意到的另一件奇怪的事情是,在调用 PyObject_GetAttrString(scipy_stats_module, "anderson_ksamp");
之后,anderson_ksamp
的引用计数器直接跳到 3,而不是仅仅上升 1。
我正在使用 Pyhton3.6 和最新版本的 scipy (0.19.0) 和 numpy (1.13.0)。
提前感谢您的任何帮助。
编辑:这是我运行valgrind --leak-check=yes Test
时valgrind给我的输出:
==24810== Memcheck, a memory error detector
==24810== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==24810== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==24810== Command: Test
==24810==
==24810== Syscall param msg->desc.port.name points to uninitialised byte(s)
==24810== at 0x1003AD34A: mach_msg_trap (in /usr/lib/system/libsystem_kernel.dylib)
==24810== by 0x1003AC796: mach_msg (in /usr/lib/system/libsystem_kernel.dylib)
==24810== by 0x1003A6485: task_set_special_port (in /usr/lib/system/libsystem_kernel.dylib)
==24810== by 0x10054210E: _os_trace_create_debug_control_port (in /usr/lib/system/libsystem_trace.dylib)
==24810== by 0x100542458: _libtrace_init (in /usr/lib/system/libsystem_trace.dylib)
==24810== by 0x1000AB9DF: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==24810== by 0x10001BA1A: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==24810== by 0x10001BC1D: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==24810== by 0x1000174A9: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==24810== by 0x100017440: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==24810== by 0x100016523: ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==24810== by 0x1000165B8: ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (in /usr/lib/dyld)
==24810== Address 0x10488ee0c is on thread 1's stack
==24810== in frame #2, created by task_set_special_port (???:)
==24810==
==24810==
==24810== HEAP SUMMARY:
==24810== in use at exit: 17,836 bytes in 157 blocks
==24810== total heap usage: 173 allocs, 16 frees, 23,980 bytes allocated
==24810==
==24810== 72 bytes in 3 blocks are possibly lost in loss record 26 of 41
==24810== at 0x10009A232: calloc (vg_replace_malloc.c:714)
==24810== by 0x1005B6846: map_images_nolock (in /usr/lib/libobjc.A.dylib)
==24810== by 0x1005C9FE8: objc_object::sidetable_retainCount() (in /usr/lib/libobjc.A.dylib)
==24810== by 0x10000B03B: dyld::notifyBatchPartial(dyld_image_states, bool, char const* (*)(dyld_image_states, unsigned int, dyld_image_info const*), bool, bool) (in /usr/lib/dyld)
==24810== by 0x10000B255: dyld::registerObjCNotifiers(void (*)(unsigned int, char const* const*, mach_header const* const*), void (*)(char const*, mach_header const*), void (*)(char const*, mach_header const*)) (in /usr/lib/dyld)
==24810== by 0x10020400A: _dyld_objc_notify_register (in /usr/lib/system/libdyld.dylib)
==24810== by 0x1005B6074: _objc_init (in /usr/lib/libobjc.A.dylib)
==24810== by 0x10019768D: _os_object_init (in /usr/lib/system/libdispatch.dylib)
==24810== by 0x10019763A: libdispatch_init (in /usr/lib/system/libdispatch.dylib)
==24810== by 0x1000AB9D5: libSystem_initializer (in /usr/lib/libSystem.B.dylib)
==24810== by 0x10001BA1A: ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==24810== by 0x10001BC1D: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==24810==
==24810== LEAK SUMMARY:
==24810== definitely lost: 0 bytes in 0 blocks
==24810== indirectly lost: 0 bytes in 0 blocks
==24810== possibly lost: 72 bytes in 3 blocks
==24810== still reachable: 200 bytes in 6 blocks
==24810== suppressed: 17,564 bytes in 148 blocks
==24810== Reachable blocks (those to which a pointer was found) are not shown.
==24810== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==24810==
==24810== For counts of detected and suppressed errors, rerun with: -v
==24810== Use --track-origins=yes to see where uninitialised values come from
==24810== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 12)
【问题讨论】:
您应该使用valgrind
之类的工具来获取更多发生内存损坏的信息。
@πάνταῥεῖ 我会尝试并发布输出。谢谢
【参考方案1】:
好的,这个问题可能已经死了,但我还是会回答的。几天后,我发现了我的错误。当然是非常愚蠢的事情。
调用malloc
时,我根本没有为我的数组分配足够的空间。
我写道:
unsigned long k = std::min(left_sample.size(), right_sample.size());
int* both_samples = (int*) (malloc(2 * k));
但我忘了考虑到我的数组是int
的数组,它也需要内存,因此所需的正确内存量是:2 * k * sizeof(int)
。
正如我所说,非常愚蠢......
我解决了这个问题,现在一切正常。
【讨论】:
以上是关于从 C++ 调用 scipy.stats.anderson_ksamp 时的 EXC_BAD_ACCESS 或 SIGABRT的主要内容,如果未能解决你的问题,请参考以下文章