0

我一直在从事一个在专用 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 没有显示这是发生分段错误的代码行,而是说它是函数调用?

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

谢谢。

4

2 回答 2

0

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

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

提供了一个行号:src/seam_processor.c:47那里有什么有趣的吗?GDB 抱怨的各种内存地址是堆栈上的各种内存地址,它们都是连续的,而且几乎所有这些地址本身看起来都是指针(因为它们都是 8 字节宽)。

(这是我可以根据手头的信息给出的最佳答案;请随时提出修改建议或提供更多信息。)

于 2012-08-15T20:07:41.863 回答
0

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

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

  1. 为所有局部函数变量分配存储量,
  2. 开始执行函数中的语句

这样,当你从 fucntion1 调用另一个 say function2 时,function1 的局部变量不会被来自 function2 的局部变量的数据干扰。

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

于 2013-07-25T09:51:16.640 回答