c++ - 为什么列表初始化会导致 Seg 错误?
问题描述
我正在调试我的应用程序的未定义行为。今天,我有机会尝试使用-fsanitize=undefined -fsanitize=address
标志,并且像往常一样继续编译我的应用程序。原来,它在运行时发现了一些东西并打印了这个日志,
AddressSanitizer:DEADLYSIGNAL
=================================================================
==502288==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x0000004ce04b bp 0x611000000b98 sp 0x7ffc441a5bf8 T0)
==502288==The signal is caused by a READ memory access.
==502288==Hint: this fault was caused by a dereference of a high value address (see register values below). Dissassemble the provided pc to learn which register was used.
#0 0x4ce04b in llhttp__on_message_begin /home/llhttp/src/native/api.c:144:3
#1 0x4ce4f4 in llhttp__internal__run /home/llhttp/build/c/llhttp.c:14590:13
#2 0x4ce3e1 in llhttp__internal_execute /home/llhttp/build/c/llhttp.c:14624:10
#3 0x4c8661 in HTTPTransport::initialize() /home/example.cpp:70:29
#4 0x4c890f in main /home/example.cpp:76:12
#5 0x7f09e9f590b2 in __libc_start_main /build/glibc-ZN95T4/glibc-2.31/csu/../csu/libc-start.c:308:16
#6 0x41d53d in _start (/home/example+0x41d53d)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/llhttp/src/native/api.c:144:3 in llhttp__on_message_begin
==502288==ABORTING
我最终弄清楚了造成这种情况的原因。来了,
class Connection : public HTTPTransport
{
public:
llhttp_t httpParser;
llhttp_settings_t httpParserSettings;
sessions session;
bool auth;
// This line causing it but if I remove it everything works.
Connection() : auth(){}
};
但是我发现如果我删除unique_ptr并直接初始化类,该行没有效果,因此出现segfault。
有趣的是,如果我使用 unique_ptr 并删除该行,则不会发生这种情况,之后一切正常。
我还尝试在类中使用类内成员初始化方法;但它只是不起作用并引发相同的段错误。
我在 Clang 编译器上编译它并以 C++17 为目标。
总而言之,这是我尝试过的事情,但并没有以任何方式影响段错误,
- 类内成员初始化
- 直接初始化类而不是
unique_ptr
- 删除了此类与
HTTPTransport
基类的继承
我知道它std::make_unique
不会调用类列表初始化程序,但事实是我在直接初始化类时遇到了相同的段错误,我像这样初始化它,
Connection currentConnection;
最少的可重现代码,
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include "llhttp.h"
class HTTPTransport
{
public:
struct sessions
{
std::string url;
};
private:
static int handleOnUrl(llhttp_t *ll, const char *buf, size_t len);
public:
void initialize();
};
class Connection : public HTTPTransport
{
public:
llhttp_t httpParser;
llhttp_settings_t httpParserSettings;
sessions session;
bool auth;
Connection() : auth(){}
};
int HTTPTransport::handleOnUrl(llhttp_t *ll, const char *buf, size_t len)
{
sessions *session = static_cast<sessions *>(ll->data);
session->url = std::string(buf, len);
return 0;
}
void HTTPTransport::initialize()
{
auto currentConnection = std::make_unique<Connection>();
llhttp_init(¤tConnection->httpParser, HTTP_REQUEST, ¤tConnection->httpParserSettings);
/* Set callbacks */
currentConnection->httpParserSettings.on_url = handleOnUrl;
currentConnection->httpParser.data = ¤tConnection->session;
std::string res = "CONNECT [2607:f8b0:4008:80c::2004]:443 HTTP/1.1\r\nHost: [2607:f8b0:4008:80c::2004]:443\r\n\r\n";
enum llhttp_errno err = llhttp_execute(¤tConnection->httpParser, res.c_str(), res.length());
}
int main() {
HTTPTransport Server;
Server.initialize();
return 0;
}
您将需要llhttp
解析器库来构建它。你可以在Github上找到它。
值得补充的是,即使我没有使用 unique_ptr,行为仍然相同
解决方案
在您的默认构造函数中,您没有进行初始化httpParserSettings
,这意味着在构造对象时它将具有垃圾数据Connection
,并最终llhttp_init
会尝试使用该垃圾数据。为了解决这个问题,值初始化默认构造函数中的所有成员:
class Connection : public HTTPTransport
{
public:
llhttp_t httpParser;
llhttp_settings_t httpParserSettings;
sessions session;
bool auth;
Connection()
: httpParser{},
httpParserSettings{},
session{},
auth{}
{}
};
或提供成员初始化器:
class Connection : public HTTPTransport
{
public:
llhttp_t httpParser{};
llhttp_settings_t httpParserSettings{};
sessions session{};
bool auth{};
// no constructor needed in this case
};
Connection
它在没有默认构造函数的情况下工作的原因是,std::make_unique<Connection>()
如果没有用户提供的默认构造函数, value 会初始化分配的对象。
推荐阅读
- wordpress - 在移动菜单上对齐最后 3 个菜单项
- java - 服务器从java中的另一个客户端发送事件?
- python - 如何从具有熊猫系列对象和浮点数的列表中删除浮点值
- google-apps-script - 如果选中复选框,则删除部分行
- inheritance - Kotlin 中的主构造函数 + 调用超级构造函数
- multidimensional-array - 有没有办法将表单中的所有字段收集到二维数组中以写入 Google 表格?
- visual-studio-code - Visual Studio graphql“执行查询”如何工作?
- spring - 根据枚举值选择验证
- python - ImportError:DLL 加载失败:找不到指定的模块。(NASA Fortran CEA 的 Python Rocketcea 包装器)
- python - 尝试打开文件时 TKinter 窗口“无响应”