C代码行在完全不相关的代码行上导致分段错误

时间:2012-04-05 22:13:08

标签: c segmentation-fault llvm exc-bad-access opencl

根据Xcode中的堆栈跟踪,我的程序在这里断开并给出了EXC_BAD_ACCESS:

int main (int argc, const char * argv[]) {
    float usd,btc,bid,ask,order_price,possible_price;
    DateData * prices = load_prices(); <---

DateData * load_prices(){
    FILE * file = fopen("price.dat", "rb"); <---

我确定这与该行代码无关,而是后来的代码。在直到稍后才调用的函数中,有一行代码似乎破坏了程序。当它在执行行之前从函数返回时,程序没有这个问题,但如果它应该从行后的函数返回,则会出现这个问题。

代码行是对OpenCL的调用。它是否以某种方式破坏了该计划?

err = clEnqueueReadBuffer(ocl_data->commands, ocl_data->output, CL_TRUE, 0, sizeof(CombinationResult) * PPO_COMBINATIONS, (*PPO_results)[x] + PPO_COMBINATIONS*(p + 5), 0, NULL, NULL); 

PPO_COMBINATIONS定义为整数宏,PPO_results的类型为CombinationResult(*)[3] [PPO_COMBINATIONS * 11]。 ocl_data-&gt;命令的类型为cl_command_queue,ocl_data-&gt;输出的类型为cl_mem。错误,p和x的类型为int。

我正在使用Xcode和“Apple LLVM Compiler 3.0”。 “LLVM GCC 4.2”编译器出于某种原因给出了“架构i386的格式错误的元数据记录”。

这是使用命令行编译并使用gdb运行时的结果:

Matthew-Mitchell:Parrallel BitCoin Trading Algorithm matt$ gcc -g cmain.c -o test -lcurl -framework OpenCL -std=c99 -arch i386
Matthew-Mitchell:Parrallel BitCoin Trading Algorithm matt$ gdb testGNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Mon Aug 15 16:03:10 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries .... done

(gdb) run
Starting program: /Users/matt/Programming/Bit Coin algorithm/Parrallel BitCoin Trading Algorithm/test 
Reading symbols for shared libraries .+++.................................................................. done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0xbea7d7cc
0x00003e9a in main (argc=0, argv=0x1000) at cmain.c:572
572 int main (int argc, const char * argv[]) {

直接在命令行中运行时,程序立即退出。

4 个答案:

答案 0 :(得分:8)

感谢MrGomez做了一个很好的猜测,但实际答案一直盯着我。答案是这个网站的名称。问题是主函数中的自动变量太大而导致堆栈溢出。解决方案是使用malloc分配数据。

对于任何从谷歌看到此内容的人来说,最好检查声明变量的大小。您可能希望在运行时分配内存。

答案 1 :(得分:2)

当你试图通过clEnqueueReadBuffer中的(*PPO_results)[x] + PPO_COMBINATIONS*(p + 5)缓冲区指针写入void*时,我会猜测你有堆栈损坏。我很容易相信你的整数宏PPO_COMBINATIONSPPO_results的指针操作的组合结合起来指向堆栈,导致你意外地写入应用程序的可执行区域

如果它在你的FILE * file = fopen("price.dat", "rb");通话区域周围损坏你的筹码,这将重现你所看到的问题。作为奖励,这将阻止某些工具(如gdb)正确展开堆栈帧(从而禁止完整堆栈跟踪),因为此时堆栈处于腐败且平坦的不可恢复状态。

最简单的检查是通过在调试器中逐步执行写操作或在应用程序上运行bounds checker来验证您的写入。在这个OSX空间中也存在Valgrind has a patch containing this functionality和一些other tools

祝你的申请顺利。使用缓冲区安全播放,您的程序将继续开心。 :)

修改:关闭,但是nope

答案 2 :(得分:0)

当代码中某个奇怪的地方出现故障时,就像一个甚至没有被调用的函数一样,可能是由于间接跳过了损坏的代码指针。这不一定是在程序中作为值可见的函数指针。它可能是堆栈上的损坏返回地址。

机器可能会使用之前在前一个函数调用链中使用的返回地址来欺骗自己(其中堆栈中仍然存在碎片)。

实施例。您的load_prices调用fopen,因此它将返回地址放入堆栈。然后整个业务返回,程序正在调用其他一些函数激活链,这样就不会覆盖返回地址。 (有时函数会分配局部变量但不会完全初始化它们。或者编译器会安排临时区域,例如寄存器保存区域,但并不总是使用它们。)

无论如何,堆栈被搞砸后会出现问题,然后执行不正确的函数返回,以便重新使用给予fopen的旧返回地址。 Blam,你回到load_prices里面,好像第二次从fopen回来一样(类似于setjmp / longjmp)。

答案 3 :(得分:0)

将这行代码分成不同的行并分配给变量:

err = clEnqueueReadBuffer(ocl_data->commands, ocl_data->output, CL_TRUE, 0, sizeof(CombinationResult) * PPO_COMBINATIONS, (*PPO_results)[x] + PPO_COMBINATIONS*(p + 5), 0, NULL, NULL);

这里有太多的东西可以安全地保存为一行代码。您还需要更多错误检查:

if (ocl_data!=null) {
  //Making Assumtions here, don't expect to compile
  int crCalc=sizeof(CombinationResult)*PPO_COMBINATIONS;
  int ppoResult=0; 
  int ppoCFive=PPO_COMBINATIONS*(p + 5);

  //Check size of PPO_results before assigning
  if (x<sizeof((*PPO_results))
    ppoResult=(*PPO_results)[x];

  err = clEnqueueReadBuffer(ocl_data->commands, ocl_data->output, CL_TRUE, 0, crCalc, ppoResult + ppoCFive, 0, NULL, NULL);
} else (
  //Error message
}