无法在地址函数参数传递问题上访问内存

标签 c linux gcc gdb shared-libraries

在我的 main() 函数中,我有一个局部变量:

datastruct pdw_frame;

我用数据填充它并将它传递给 main() 中相邻行的两个函数,例如

datastruct_to_pdw(&pdw_frame, 0, &pdw); /* ok */
hash_streams = get_streams(&pdw_frame, &result_frame); /* not ok */

在使用 gdb 进入 datastruct_to_pdw() 时,我可以毫无问题地查看第一个函数参数,例如

(gdb) p *pdw_frame

返回结构的描述

然而,当进入第二个函数并尝试做同样的事情时,我得到:

Cannot access memory at address 0xcccccccd

我不明白为什么我可以从第一个函数参数而不是第二个参数取消引用指针

point 中的函数包含在我从 main() 调用的共享库中。这些函数定义在不同的文件中,它们的原型(prototype)在不同的头文件中。我检查了我的 Makefile 以确保它们都已构建。检查共享库可确认这两个函数都存在,例如

nm mylib.so

000251a1 T datastruct_to_pdw
00027348 T get_streams

为什么一个函数调用起作用而另一个不起作用?

函数原型(prototype)是:

void datastruct_to_pdw(const datastruct *const pulse_data, size_t i, Pdw *pdw);
stream_t* get_streams(datastruct *pdw_frame, resultstruct *result_frame);

我的共享库的调试版本设置了以下编译器标志:

DEBUG_CFLAGS := -fPIC -g -Wall -DDEBUG=1

使用这些设置,从 Makefile 构建时我不会收到任何警告

单步执行代码,边检查 pdw_frame 的值边给出:

在调用 datastruct_to_pdw() 之前的 main() 中:

(gdb) p pdw_frame
$2 = {ptoa = 0x8051e98, prf = 0x804e008, ppw = 0x804ff50, pamp = 0x8053de0, pbr = 0x8055d28, n = 1000, truth = 0x8057c70}

(gdb) p &pdw_frame
$5 = (datastruct *) 0xbfffe9e0

进入 datastruct_to_pdw():

(gdb) p pulse_data
$4 = (const datastruct * const) 0xbfffe9e0

(gdb) p *pulse_data
$3 = {ptoa = 0x8051e98, prf = 0x804e008, ppw = 0x804ff50, pamp = 0x8053de0, pbr = 0x8055d28, n = 1000, truth = 0x8057c70}

从 datastruct_to_pdw() 返回到 main() 中:

(gdb) p pdw_frame
$9 = {ptoa = 0x8051e98, prf = 0x804e008, ppw = 0x804ff50, pamp = 0x8053de0, pbr = 0x8055d28, n = 1000, truth = 0x8057c70}

(gdb) p &pdw_frame
$8 = (datastruct *) 0xbfffe9e0

进入 get_streams():

(gdb) p pdw_frame
$10 = (datastruct *) 0x40c24f80 (why is this different to &pdw_frame in main()?)

(gdb) p *pdw_frame
Cannot access memory at address 0x40c24f80 (why??)

在 main() 中从 get_streams() 返回:

(gdb) p pdw_frame
$13 = {ptoa = 0x8051e98, prf = 0x804e008, ppw = 0x804ff50, pamp = 0x8053de0, pbr = 0x8055d28, n = 1000, truth = 0x8057c70}

(gdb) p &pdw_frame
$14 = (datastruct *) 0xbfffe9e0

请注意,我认为也许我在 main() 中为局部变量 pdw_frame(类型为 datastruct)使用了相同的名称get_streams() 函数(datastruct* 类型)中的参数名称可能会导致问题,因此我尝试重命名 get_streams 的第一个参数() 完全不同的东西,但这对错误没有影响

通过 valgrind 运行程序似乎没有任何问题(我认为),例如:

valgrind --tool=memcheck --leak-check=full --show-reachable=yes <my_program>

==12371== 
==12371== HEAP SUMMARY:
==12371==     in use at exit: 1,880 bytes in 1 blocks
==12371==   total heap usage: 35,810 allocs, 35,809 frees, 102,124,128 bytes allocated
==12371== 
==12371== 1,880 bytes in 1 blocks are still reachable in loss record 1 of 1
==12371==    at 0x402A2FB: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==12371==    by 0x41D048B: monstartup (gmon.c:134)
==12371==    by 0x8049F60: __gmon_start__ (in /home/ben/projects/glamdring/RESTRICTED/core_harness/build/linux/release/GlamdringHarness_rel)
==12371==    by 0x40D45A9: ??? (in /lib/i386-linux-gnu/librt-2.17.so)
==12371== 
==12371== LEAK SUMMARY:
==12371==    definitely lost: 0 bytes in 0 blocks
==12371==    indirectly lost: 0 bytes in 0 blocks
==12371==      possibly lost: 0 bytes in 0 blocks
==12371==    still reachable: 1,880 bytes in 1 blocks
==12371==         suppressed: 0 bytes in 0 blocks
==12371== 
==12371== For counts of detected and suppressed errors, rerun with: -v
==12371== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Profiling timer expired

我还应该补充一点,当我运行编译并链接到单个可执行文件而不是通过共享库访问函数的单元测试套件时,我没有遇到任何此类问题。

刚刚添加了一个新功能:

void dummy_utility(int n)
{
    printf("Hello World!");
    return;
}

像这样从 main() 调用它:

dummy_utility(42);    

使用 gdb 进入它并得到:

(gdb) p n
$4 = 1086476160

它一定是选择了一个旧库,但是当我搜索共享库时,例如

$ locate libProgram_dbg.so(_dbg版本有调试符号,没有优化)

我在 build/linux/debug 目录中得到一个文件,正如我所料,当我在那里查看共享库的时间戳时,它显示它刚刚被重建!我真的很困惑..

这是在 gdb 中运行信息寄存器的输出:

就在调用 dummy_utility() 之前:

(gdb) info registers
eax            0xc  12
ecx            0x0  0
edx            0xbfffe454   -1073748908
ebx            0x11 17
esp            0xbfffe8c0   0xbfffe8c0
ebp            0xbfffec78   0xbfffec78
esi            0x8053dd0    134561232
edi            0x1f38   7992
eip            0x8049d82    0x8049d82 <main+3884>
eflags         0x286    [ PF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

关于进入dummy_utility():

(gdb) info registers
eax            0xbfffea98   -1073747304
ecx            0x0  0
edx            0x2a 42
ebx            0xb7fd9000   -1208119296
esp            0xbfffe8b8   0xbfffe8b8
ebp            0xbfffe8d0   0xbfffe8d0
esi            0x8053dd0    134561232
edi            0x1f38   7992
eip            0xb7fc22cc   0xb7fc22cc <dummy_utility+18>
eflags         0x296    [ PF AF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

单步执行 dummy_utility() 以尝试从 main() 返回,gdb 告诉我:

Cannot find bounds of current function

运行 ldd ProgramHarness_dbg 得到:

linux-gate.so.1 =>  (0xb76e7000)
libGlamdring_dbg.so => /home/ben/projects/core/build/linux/debug/libProgram_dbg.so (0xb76a4000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7646000)
librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb763c000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7489000)
/lib/ld-linux.so.2 (0xb76e8000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb746e000)

共享库的位置符合预期..

最佳答案

对于在 emacs/linux 下运行 gdb 时遇到奇怪行为的任何人

如果您最近升级到 emacs 24,请了解 gdb 已损坏,您现在需要使用 gud-gdb

详情如下:

Emacs gdb not running

gud-gdb emacs 24 not working

关于无法在地址函数参数传递问题上访问内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20633968/

相关文章:

c - SDL 访问冲突

c - 使用结构字段作为循环计数器?

c - 用char数组存储单词C语言

linux - 在一台机器上编译gcc4.4.6,如何让另一台机器使用?

c - 带返回值的 Switch 语句——代码正确性

linux - 如何在Linux(fedora,ubuntu)中自动运行jar文件,例如Windows上的服务

python 打印循环中的第一行

c++ - 使用内联汇编程序从 GCC 中的共享库调用函数

c++ - gcc -I 和 -L 选项似乎不起作用

c++ - "Undefined"C++类成员引用