问题描述
我正在尝试调用 fileUtilcopyRecurse
为其提供您可以在下面看到的参数。当我进入函数时,参数 2-4 被替换为无意义(参数 1 没问题)。
(下面继续……)
Breakpoint 1,createTestDir (T=0x5555555cabc0 <Staticmem>,MakeTargetNewer=0 '\000') at ../backuper/backuperTest.c:64
64 fileUtilcopyRecurse(T,DirInBoth1,DirInBoth2,false);
(gdb) p DirInBoth1
$1 = (utf8 *) 0x5555555aac68 "../backuper/testdir/1/dir-in-both/"
(gdb) p DirInBoth2
$2 = (utf8 *) 0x5555555aac90 "../backuper/testdir/2/dir-in-both/"
(gdb) s
fileUtilcopyRecurse (T=0x5555555cabc0 <Staticmem>,P=0x5555556bef88 <nonstd_creat_f> "\360\n\354\367\377\177",To=0x5555555a929e "creat",Recurse=1 '\001') at ../fileUtil/fileUtil.c:271
271 fct void fileUtilcopyRecurse(void* T,pathC* P,pathC* To,bool Recurse) { // if dir and Recurse set then recursively copies it
(gdb) p P
$3 = (pathC *) 0x5555556bef88 <nonstd_creat_f> "\360\n\354\367\377\177"
一开始我以为调用者.o-File和被调用者.o-File在签名上不一致。 typedef 是不同的,因为它们是代码库的两个不同部分,调用者使用 utf8,即 typedef char,被调用者使用 pathC,即 typedef const char。所以我们给一个 const char* 一个 char* ,这很好。
为了确保一致性,我检查了 .c 文件是否包含相同的 .h 文件(指定 fileUtilcopyRecurse
)并重新编译所有内容。然后我确定 fileUtilcopyRecurse
由于某种原因不是宏。
这发生在 64 位 Linux 上的 GCC 9.3.0。我启用了很多警告并且禁用了优化(-O0)。我将代码带到另一台装有 GCC 7.5.0(也是 64 位 Linux)的计算机上,并且运行正常。
所以我想我在某处有未定义的行为,我向您询问要寻找什么的提示。
对拆解感兴趣的朋友:
(gdb) x/6i $pc
=> 0x5555555a7ca8 <createTestDir+245>: mov -0x28(%rbp),%rdx
0x5555555a7cac <createTestDir+249>: mov -0x30(%rbp),%rsi
0x5555555a7cb0 <createTestDir+253>: mov -0x38(%rbp),%rax
0x5555555a7cb4 <createTestDir+257>: mov $0x0,%ecx
0x5555555a7cb9 <createTestDir+262>: mov %rax,%rdi
0x5555555a7cbc <createTestDir+265>: callq 0x55555559a9de <fileUtilcopyRecurse>
(gdb) si
0x00005555555a7cac 64 fileUtilcopyRecurse(T,false);
1: x/i $pc
=> 0x5555555a7cac <createTestDir+249>: mov -0x30(%rbp),%rsi
(gdb)
0x00005555555a7cb0 64 fileUtilcopyRecurse(T,false);
1: x/i $pc
=> 0x5555555a7cb0 <createTestDir+253>: mov -0x38(%rbp),%rax
(gdb)
0x00005555555a7cb4 64 fileUtilcopyRecurse(T,false);
1: x/i $pc
=> 0x5555555a7cb4 <createTestDir+257>: mov $0x0,%ecx
(gdb)
0x00005555555a7cb9 64 fileUtilcopyRecurse(T,false);
1: x/i $pc
=> 0x5555555a7cb9 <createTestDir+262>: mov %rax,%rdi
(gdb)
0x00005555555a7cbc 64 fileUtilcopyRecurse(T,false);
1: x/i $pc
=> 0x5555555a7cbc <createTestDir+265>: callq 0x55555559a9de <fileUtilcopyRecurse>
(gdb) info reg
rax 0x5555555cabc0 93824992717760
rbx 0x5555555a8670 93824992577136
rcx 0x0 0
rdx 0x5555555aac90 93824992586896
rsi 0x5555555aac68 93824992586856
rdi 0x5555555cabc0 93824992717760
rbp 0x7fffffffdc90 0x7fffffffdc90
rsp 0x7fffffffdc50 0x7fffffffdc50
r8 0x0 0
r9 0x7fffffffd830 140737488345136
r10 0x7ffff7db407c 140737351729276
r11 0x246 582
r12 0x5555555610d0 93824992284880
r13 0x7fffffffdf80 140737488347008
r14 0x0 0
r15 0x0 0
rip 0x5555555a7cbc 0x5555555a7cbc <createTestDir+265>
eflags 0x207 [ CF PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
解决方法
如果在函数序言中执行已停止,则调试器中显示的参数值可以是影子空间(在寄存器中传递的参数存储在堆栈中的堆栈空间)的未初始化值。继续执行另一个语句应该允许序言将允许填充这些影子变量并让调试器显示参数的正确值。
检查是否是这种情况的一种方法是查看反汇编视图以查看执行已停止的确切位置。