我正在调试应用程序的未定义行为。今天,我有机会尝试使用 -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 行为仍然相同
答案 0 :(得分:3)
在您的默认构造函数中,您没有初始化 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>()
值会初始化分配的对象。
答案 1 :(得分:0)
// This line causing it but if I remove it everything works.
检查此页面:https://en.cppreference.com/w/cpp/language/rule_of_three
由于您需要 Connection
对象可移动(通过 std::unique_ptr)但不可复制,我建议您这样做:
{
public:
llhttp_t httpParser;
llhttp_settings_t httpParserSettings;
sessions session;
bool auth;
Connection() : auth(){}
~Connection() = default;
// Non-copyable
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
// Movable
Connection(Connection&&) = default;
Connection& operator=(Connection&&) = default;
};
编辑:不过,您似乎只定义了默认构造函数,所以我不确定这是问题...