在虚拟机中使用GDB来调试Python ctypes段错误

时间:2012-08-15 18:18:10

标签: python gdb virtual-machine ctypes

我一直致力于一个在专用的Linux CentOS系统上运行良好的项目。

一般的想法是,有一个Python工作流管理器,而不是使用ctypes调用用C编写的共享库。它工作正常。

但是,我需要有一个用于开发目的的项目的本地实例。我在Windows 7下使用VMWare设置了一个Linux Mint虚拟机。在大多数情况下,一切正常。

问题是一个模块在调用其中一个共享库中的函数时崩溃并出现分段错误。通常这没关系,在专用的Linux机器上,使用类似“gdb python corename”的东西让我看到它崩溃的确切位置并解决问题。

但是,使用本地设置我遇到了问题。我最常注意到的是GDB没有报告正确的内存地址。这是一个巨大的项目,所以我不能发布所有代码,但我会给出一个纲要:

Python模块创建一个“file_path”变量,一个字符串。它首先将此传递给某个共享库以加载该文件。如果我在python中执行命令

hex(id(file_path))

它将返回类似'46cb4ec'的内容。在第一个共享库(C)中,我用

开始
printf("file_pathaddress = %x\n", &file_path[0]);

并输出'file_path address = 46cb4ec',这与我通过Python的'id()'函数相同。我想这是预期的......?

无论如何..我将这个相同的变量发送到另一个共享库,但它在此调用中立即崩溃。如果我分析核心文件,它会显示它在函数调用本身崩溃,而不是函数内的一行。但奇怪的是,它输出的内容如下:

Program terminated with signal 11, Segmentation fault.
#0  0x00007f124448c9fc in seam_processor (irm_filename=<error reading variable: Cannot access memory at address 0x7fff5fab51b8>, 
seam_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51b0>, 
    full_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51a8>, ranges=<error reading variable: Cannot access memory at address 0x7fff5fab51a0>, 
    job_id=<error reading variable: Cannot access memory at address 0x7fff5fab519c>, job_owner=<error reading variable: Cannot access memory at address 0x7fff5fab5198>, 
    y_tile_in=1, x_tile_in=1, fc_int=10650000000, atmos_props=..., surf_props=..., extra_props=<error reading variable: Cannot access memory at address 0x7fff5fab5190>, 
    gascalc_ftype=513, len_gas_sectrum=16, vect_spec_fq=<error reading variable: Cannot access memory at address 0x7fff5fab5188>, surfscat_theta_inc_vector_size=6, 
    surfscat_theta_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5180>, surfscat_phi_inc_vector_size=6, 
    surfscat_phi_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5178>, surfscat_theta_scat_vector_size=6, 
    surfscat_theta_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5170>, surfscat_phi_scat_vector_size=6, 
    surfscat_phi_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5168>) at src/seam_processor.c:47

所以,我无法弄清楚为什么GDB会报告这些内存地址。在这种情况下,'irm_filename'变量是Python传入的'file_path'变量,因此它的地址应该是其他库和id()函数报告的内容,0x46CB4EC。它为什么不同?然而,奇怪的是,有些变量很好,比如'y_tile_in'。如果我在gdb中执行:

(gdb) print &y_tile_in
$1 = (int *) 0x7fff60543f80

因此,尽管它可以读取此内存地址,但这与Python的id()报告的内容不同,或者地址的类似C printf()在不崩溃的库中报告的内容。此外,这些内存地址实际上是一个很大的数字,大于我迄今为止的内存量......它们的真正含义是什么?

那么,我的问题是这里到底发生了什么?事实上这是在虚拟机中运行吗?是否有一些映射?如果在虚拟机中使用gdb,我无法在网上找到任何我不得不做的事情,所以我很茫然...

任何人都知道发生了什么事?

感谢。

修改

所以,这个问题变得更加陌生。基本上,我注释掉了库中执行任何操作的所有代码,并使函数调用保持不变。当我这样做并在带有断点的gdb中运行它时,它在函数调用中打印的所有内存地址都是正常的,匹配Python id()函数并匹配地址上的printf()。

我开始取消注释掉代码以查看问题所在。问题在于声明:

double nrcs_h_d[MAX_NINC_S*MAX_SCAT_S];
double nrcs_v_d[MAX_NINC_S*MAX_SCAT_S];

如果我注释掉这两行,就没有崩溃。如果我只注释掉第二行,就没有崩溃。但是,如果没有注释掉任何行,它就会崩溃。

奇怪的是,MAX_NINC_S和MAX_SCAT_S都等于500.因此,这些数组的大小只有几兆字节......在数百兆字节的代码数组中的其他地方分配得很好。

另外,如果我用以下代码替换上面的行:

double *nrcs_h_d, *nrcs_v_d;
nrcs_h_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double));
nrcs_v_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double));

似乎工作正常......显然问题与尝试在堆栈上分配太多有关。

所以,问题变成了:

为什么gdb没有显示这是发生分段错误的代码行,而是说它是函数调用?

如果进行分配,为什么核心转储文件的内存地址似乎搞砸了?

感谢。

2 个答案:

答案 0 :(得分:0)

回想一下,堆栈空间向下增长,而堆空间向上增长;靠近虚拟内存空间顶部的地址(例如0x7fff5fab51b0)是堆栈分配的变量,而靠近底部的地址(例如0x46cb4ec)是堆分配的变量。请注意,虚拟内存空间通常远远大于物理内存;看起来您的操作系统和架构最多支持128 GiB的虚拟内存。

由于Python在很大程度上依赖于动态内存分配,因此它最终会将其对象放在堆上,这就是id()倾向于返回低端地址的原因。如果C代码将任何值复制到堆栈分配的变量并随后尝试使用这些本地副本调用函数,那么您将再次看到偏高的地址。

提供了一个代码:src/seam_processor.c:47那里有什么有意思吗? GDB抱怨的各种内存地址是堆栈上的各种内存地址 ,所有内存地址都是顺序的,几乎所有这些都是自己出现的成为指针(因为它们都是8字节宽)。

(这是我可以用手头的信息给出的最佳答案;随时建议修改或提供其他信息。)

答案 1 :(得分:0)

一种可能的解释是函数中局部变量的数据分配发生在执行特定函数中的任何代码之前。

编译器计算出所需的堆栈空间量,并在获取函数中的语句之前分配它。所以你的函数的实际执行有点像这样:

  1. 为所有本地函数变量分配存储量
  2. 开始执行函数
  3. 中的语句

    这样,当你从fucntion1调用另一个说function2时,function1的局部变量不会受到function2中局部变量数据的干扰。

    因此,在您的情况下,本地数据变量所需的空间大于堆栈可用空间,并且在函数代码开始执行之前的某个时间点引发异常。