【问题标题】:segfault in basic_string destructorbasic_string 析构函数中的段错误
【发布时间】:2014-08-04 07:51:18
【问题描述】:

我有一个函数,ModuleManager::tick(),代码如下:

void ModuleManager::tick()
{
auto now = std::chrono::steady_clock::now();
auto nowSys = std::chrono::system_clock::now().time_since_epoch();

for(auto& m : m_modules)
{
    if(std::chrono::duration_cast<std::chrono::seconds>(now - m.second) >=
        std::chrono::seconds(m.first.m_settings.m_interval))
    {
        std::string result = m.first.run(); //run() returns a std::string
        m.second = now;

        try
        {
            HTTPConn conn("127.0.0.1", 80);

            conn.request("POST", "/", std::vector<std::string>{"Host: localhost", "Connection: close"}, result);
        }
        catch(HTTPException& e)
        {
            Log::write(e.getErrorString());
        }
    }
}

程序在从HTTPConn::request() 函数返回时在 basic_string 析构函数中出现段错误(已使用 GDB 来确定这一点)。如果我注释掉request()函数里面的所有代码,segfault还是会出现,所以问题肯定在那个函数之外。

我认为问题在于,在我的 HTTPConn 构造函数的某个地方我破坏了堆。代码如下:

HTTPConn::HTTPConn(const std::string& host, int port)
{
addrinfo hints;
addrinfo* res;
memset(&hints, 0, sizeof(hints));

hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

int result = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &res);

if(result)
{
    throw HTTPException(HTTPE_GETADDRINFO_FAILED);
}

addrinfo* ptr = res;
bool validSocket = false;

while(ptr)
{
    m_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

    if(m_socket == -1)
    {
        ptr = ptr->ai_next;
    }
    else
    {
        validSocket = true;
        break;
    }
}

if(!validSocket)
{
    freeaddrinfo(res);
    throw HTTPException(HTTPE_SOCKET_FAILED);
}

result = connect(m_socket, ptr->ai_addr, ptr->ai_addrlen);

freeaddrinfo(res);

if(result == -1)
{
    close(m_socket);
    m_socket = -1;

    if(errno == ECONNREFUSED)
    {
        throw HTTPException(HTTPE_CONNECTION_REFUSED);
    }
    else if(errno == ENETUNREACH)
    {
        throw HTTPException(HTTPE_NETWORK_UNREACHABLE);
    }
    else if(errno == ETIMEDOUT)
    {
        throw HTTPException(HTTPE_TIMED_OUT);
    }
    else
    {
        throw HTTPException(HTTPE_CONNECT_FAILED);
    }
}
}

对于大量代码,我深表歉意;我尝试制作一个简短的、独立的示例,但无法重现该问题。

更新

所以问题似乎是我没有在 HTTPConn::request 函数中返回任何 std::string 对象,但它被声明为具有 std::string 返回类型。我现在的问题是:为什么要编译?这是我用来编译它的命令行,使用g++ 4.8.2:

g++ -Iinclude -std=c++11 -g -D__DEBUG -c src/HTTP.cpp -o obj/HTTP.o

没有发出警告或错误。

【问题讨论】:

  • 我曾经遇到过类似的问题,是用一个版本的Visual Studio(和运行时库)编译DLL,但是用另一个版本的Visual Studio(和运行时库)编译可执行文件引起的)。他们链接得很好,但是任何涉及传递std::vectorstd::string 等的DLL 调用都会以根据语言没有意义的方式失败。我建议先看一下:确保项目中的所有内容都由相同的编译器、相同版本的编译器构建,并且具有基本相同的编译器标志。
  • 我在构造函数中看不到任何可能直接破坏内存的地方。我看到的唯一问题是您应该在调用close 之前保存errno,因为close 可能会设置errno。请改为显示request 函数。
  • 那么问题可能不在您认为的位置?至少你可以向我们展示request的声明?
  • @JoachimPileborg 谢谢你,当我复制声明时,我注意到 std::string 函数的返回类型,但是我没有返回 std::string。请参阅我的问题中的更新。
  • @Brett,如果你将-Wall 传递给g++,它应该警告函数缺少返回值。但是,默认情况下不会产生错误,因为标准只认为它未定义的行为

标签: c++ segmentation-fault g++


【解决方案1】:

问题是我声明了HTTPConn::request() 函数的返回类型为std::string,但没有返回任何内容。正如 Frédéric Hamidi 所说,这会导致未定义的行为。

在我看来,这应该是在 g++ 中默认启用的警告,因为它会导致未定义的行为。或者它应该是一个错误。将-Wall 标志添加到编译命令会启用此警告(或-Wreturn-type 仅启用该特定警告)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-05
    • 2018-09-24
    • 1970-01-01
    • 2016-07-05
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2015-03-28
    相关资源
    最近更新 更多