C++ 为什么列表初始化会导致Seg故障?
我正在调试应用程序的未定义行为。今天,我有机会尝试了C++ 为什么列表初始化会导致Seg故障?,c++,C++,我正在调试应用程序的未定义行为。今天,我有机会尝试了-fsanitize=undefined-fsanitize=address标志,像往常一样,我继续编译我的应用程序。结果是,它在运行时发现了一些东西并打印出了这个日志 AddressSanitizer:DEADLYSIGNAL ================================================================= ==502288==ERROR: AddressSanitizer: SEGV on
-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并删除该行,然后一切正常,这就不会发生
我还尝试在类中使用类内成员初始值设定方法;但它就是不工作,并抛出相同的seg故障
我是在Clang编译器上编译的,目标是C++17
总而言之,以下是我尝试过的东西,但没有以任何方式影响seg故障
- 类内成员初始化
- 直接初始化类,而不是
unique\u ptr
- 已删除该类对
基类的继承HTTPTransport
std::make_unique
不会调用类列表初始值设定项,但事实上,我在直接初始化类时遇到了相同的seg错误,我是这样初始化的
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.h”
HTTPTransport类
{
公众:
结构会话
{
std::字符串url;
};
私人:
静态int handleOnUrl(llhttp\u t*ll,const char*buf,size\u t len);
公众:
void初始化();
};
类连接:公共HTTPTransport
{
公众:
llhttp_t httpParser;
llhttp_设置_t httpParserSettings;
会议;
bool-auth;
连接():auth(){}
};
int-HTTPTransport::handleOnUrl(llhttp\u t*ll,const char*buf,size\u t len)
{
sessions*session=static_cast(ll->data);
session->url=std::string(buf,len);
返回0;
}
void HTTPTransport::initialize()
{
自动currentConnection=std::使_唯一();
llhttp_init(¤tConnection->httpParser,HTTP_请求,¤tConnection->httpParserSettings);
/*设置回调*/
currentConnection->httpParserSettings.on_url=handleOnUrl;
currentConnection->httpParser.data=¤tConnection->session;
std::string res=“CONNECT[2607:f8b0:4008:80c::2004]:443 HTTP/1.1\r\n主机:[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(){
http传输服务器;
初始化();
返回0;
}
您将需要llhttp
parser库来构建它。你可以在
值得补充的是,即使我没有使用唯一的\u ptr,行为仍然是一样的
// This line causing it but if I remove it everything works.
查看此页:
由于您需要连接
对象可移动(通过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;
};
编辑:您似乎只定义了默认的ctor,所以我不确定这是否是问题所在…在默认构造函数中,您没有初始化
httpParserSettings
,这意味着在构造连接时它将有垃圾数据,最后,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
};
它与没有默认构造函数的连接一起工作的原因是std::make_unique()
value在没有用户提供的默认构造函数的情况下初始化分配的对象。可能相关:没有声明构造函数,你的类连接可能是一个。谁删除了关于res生命终结的答案?答案作者删除了它。这可能不是问题,因为我怀疑llhttp存储传递的原始const char*
指针而不是复制其内容。std::make_unique()
将值初始化连接
对象。如果没有用户提供的默认ctor,这意味着零初始化(后面是默认初始化)。但是有了1,就没有零初始。不确定这是否会对您的情况产生影响…@jeffbRTC这不太可能是编译器错误。为什么我必须显式定义~Connection()?您的解决方案不起作用。它输出相同的seg故障!假设所有其他成员变量也是如此(至少如果它们是基本变量或聚合变量)。基本上,我们不应该编写任何成员都可能未初始化的类。如果是基本类型或聚合类型,请在成员声明末尾粘贴一个{}
,以避免出现这种情况。依我拙见(甚至可能养成为所有成员编写的习惯!)@IlCapitano它是有效的。我必须把{]放在std::string,std::vector的末尾吗(我在这个类的RealApp中有这些)?@underline_d我选择了httpParserSettings
,因为llhttp_init
似乎是用来初始化httpParser
,所以不必严格地对其进行值初始化。不过,总的来说,我同意你的看法,应该总是初始化成员。@jeffbRTC你不必这样做,因为默认构造函数将运行regardless,但最好将{}
放在所有成员的末尾。@jeffbRTC您不必这样做,因为“real”(经过良好编程、非聚合等)类永远不会未初始化,即使没有{}
,也会调用默认的构造函数,但这可能是一个好习惯——因为这意味着您正在编写{}
更多,因此以后对于基本/聚合类型不太可能忘记它。此外,这意味着您不会受您使用的类的任何人的摆布,他们自己可能有一天会忘记初始化这样的成员并给出您的代码!