如何深入了解明显的腐败
How to Drill Down on Apparent Corruption
我已经使用C和C++相当长的时间了。 我有一个计算机科学辅修专业。 我熟悉这些语言提供的对进程内存的低级访问所固有的陷阱。 我在他们身上度过了几天和几周。
大约十年前,学习使用valgrind
在捕获小访问错误等方面是救命稻草。 目前,我也将ASAN与clion一起使用,此类错误通常会被迅速发现和处理。
然而,我认为没有防弹,最近的一个问题让我完全难倒了。1我有一个对象,其中包含一个名为from
的非公共sockaddr_storage
字段。 这可以通过以下途径访问:
const sockaddr_storage* getSockAddr () {
return &from;
}
但是返回的地址是错误的。 从gdb
中return
行上的断点开始:
Breakpoint 3, socketeering::Socket::getSockAddr (this=0x617000000400) at Socket.hpp:81
81 return &from;
(gdb) p this
$1 = (socketeering::UDPsocket * const) 0x617000000400
(gdb) p &from
$2 = (sockaddr_storage *) 0x617000000600
(gdb) p (const sockaddr_storage*)&from
$3 = (const sockaddr_storage *) 0x617000000600
似乎很明显返回的值必须0x617000000600。 但是没有:
(gdb) fin
Run till exit from #0 socketeering::Socket::getSockAddr (this=0x617000000400) at Socket.hpp:81
0x00000000004290ab in udpHandler::dataReady (this=0x631000014810, iod=0x617000000400, con=0x60e0000249b0) at /opt/cogware/C++/Socketeering2/demo/echo_server.cpp:66
66 auto sa = sock->getSockAddr();
Value returned is $4 = (const sockaddr_storage *) 0x617000000618
^^
(gdb) p sock
$5 = (socketeering::UDPsocket *) 0x617000000400
这不好 - 它是结构内部的18字节。 更糟糕的是,我无法用简单的 SSCCE 重现它:
class foo {
sockaddr_storage ss;
public:
foo () { cout << &ss << "n"; }
const sockaddr_storage* getSockAddr () { return &ss; }
};
这意味着这不是对规则等的误解。 这显然也不是逻辑错误。
一定是腐败吧?
这是一个单线程过程,如果我不是fin
而是继续踩着看看发生了什么,实际上没有什么可看的。 一步到函数关闭,下一步是在具有错误值的赋值处。瓦尔格林德和阿桑都没有表示任何希金克斯。
我可以查看哪些内容以了解正在发生的事情? 显然,这两者之间出了点问题:
return &from;
以及值的实际返回。 查看程序集转储以获取线索是留给我的唯一途径(假设这会有所帮助,我不是 ASM 人)?
我担心的答案是,除了在代码中搜索valgrind和ASAN没有发现的错误之外,别无他法。 找出在什么情况下他们不会发现腐败是一个起点。
- 我之前确实在一个现已删除的问题中提出了这个问题。 如果我读到这样的问题,任何人都能说:我们需要一个SSCCE,而腐败可能在代码的其他部分。关键是,我必须展示的信息中没有任何内容可以解释问题,但是,没有邀请每个人参加 10-20K LOC 项目,这就是我能做的。 所以我现在问的不是出了什么问题,而是"我怎么能确定出了什么问题?
查看程序集转储以寻找线索是留给我的唯一途径吗
是的,在这里使用disas
命令是合适的方法。
(假设这会有所帮助,我不是 ASM 人)?
即使你不会编写汇编,通常也很容易阅读汇编。特别是如果它是类似于x86_64
并且不涉及复杂的位摆动或浮点。这是一项可以很好地为您服务的技能。
通常这种问题是违反 ODR 的结果:在您的程序中的某个地方,您对socketeering::Socket
有不同的定义,其中this
和from
之间的偏移量是24
(它不是18
字节,而是0x18
字节0
!
通常,这种 ODR 违规来自在代码的不同部分使用不同的#defines
,例如
class Socket {
#if defined(TRACING_ON)
char trace_buf[24];
#endif
sockaddr_storage from;
};
使用-DTRACING_ON
在一个.cc
文件中编译上面的结构,编译另一个没有它的.cc
,将它们链接成一个二进制文件和 BOOM:您可能会准确地看到您所描述的错误。
有时,问题来自没有重新编译所有代码(例如,您可能有一个旧对象或共享库)。
它也可能来自将不同编译器构建的代码链接在一起,尽管这种情况很少见(通常如果编译器不兼容 ABI,它们会使用不同的名称重整来阻止程序链接)。
注意:如果Socket
继承自其他类,则差异可能来自超类,而不是Socket
本身。
- 正在尝试了解输入验证循环
- 了解 GLM- openGL 中的相机转换
- C++我需要了解在哪里使用指针和双指针
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 如何深入了解明显的腐败
- Python中的for循环与C++有何不同
- 了解嵌套循环打印星号图案
- 了解每月第一天函数的代码
- 了解C++标准::shared_ptr
- 尝试了解在导入的静态方法上使用删除方法时的错误
- C++:需要帮助了解运算符重载错误
- 在学习数据结构之前对STL有一个了解是好的吗?
- 在C++中释放内存期间,迭代器与指针有何不同
- 了解算法的性能差异(如果以不同的编程语言实现)
- 了解删除C++
- 了解内存序列和标准::memory_order_relaxed
- 了解其工作原理
- C++ 更深入地了解 rand() 和 srand() 内部
- 我想深入了解C/ c++,但不知道该怎么做
- 深入了解C++受到保护