GDB 显示奇怪的堆栈跟踪

gdb shows weird stack trace

本文关键字:堆栈 跟踪 显示 GDB      更新时间:2023-10-16

我有一个C++守护进程,它在工作几天后出现段错误。我使用调试选项编译了它(我确定我做得很好,因为我用有预谋的崩溃对其进行了测试,并且 gdb 显示了正确的堆栈跟踪),但在生产中的"真实"崩溃中,我只看到以下跟踪:

(gdb) where
#0  0x00007ffff674d5a7 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1  0xffffffffffffffff in ?? ()
#2  0x0000000000000000 in ?? ()

什么意思?

以下源代码存在潜在问题,因为它是自守护程序变得不稳定以来唯一的新代码:

namespace Foo {
    Bar* Bar::instance = NULL;
    Bar* Bar::getInstance() {
        if (!instance)
            instance = new Bar();
        return instance;
    }
    Bar::Bar() {
        curl = curl_easy_init();
        if(CURLE_OK != curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &data_write)
        || CURLE_OK != curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L)
        || CURLE_OK != curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L)
        || CURLE_OK != curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, Bar::timeout)) {
            throw std::runtime_error(std::string("Can't initialize curl."));
        }
    }
    Bar::~Bar() {
        curl_easy_cleanup(curl);
    }
    std::string Bar::getByIp(const std::string &id) {
        Bar *self = getInstance();
        std::string url = "example.com";
        url.append(id); 
        std::ostringstream oss;
        if (CURLE_OK == self->curl_read(url, oss)) {
            std::string output(oss.str());
            if (output.empty())
                return NULL_OBJECT;
            TiXmlDocument xml;
            xml.Parse(output.c_str());
           if (
                xml.Error()
                || !xml.FirstChild("a")
                || !xml.FirstChild("a")->FirstChild("b")
                || !xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lat")
                || !xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lng")
            )
                return NULL_OBJECT;
            std::string lat = xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lat")->GetText();
            std::string lng = xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lng")->GetText();
            return Region::getByCoordinates(lng, lat);
        }
        return NULL_OBJECT;
    }
    size_t Bar::data_write(void* buf, size_t size, size_t nmemb, void* userp)
    {
        if(userp)
        {
            std::ostream& os = *static_cast<std::ostream*>(userp);
            std::streamsize len = size * nmemb;
            if(os.write(static_cast<char*>(buf), len))
                return len;
        }
        return 0;
    }
    CURLcode Bar::curl_read(const std::string& url, std::ostringstream& os)
    {
        CURLcode code(CURLE_FAILED_INIT);
        if(curl)
        {
            if(
                CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FILE, &os))
                && CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_URL, url.c_str()))
            ) {
                code = curl_easy_perform(curl);
            }
        }
        return code;
    }
}

它看起来像是影响堆栈的内存损坏:在分配的内存之外写入。

你可以编写一个小程序来练习你的 Bar 类,就像你的守护程序一样,可能是在一个循环中。您还可以使用MALLOC_CHECK_,电围栏,Valgrind或任何其他内存检查工具运行此程序。

它可以是curl,TiXmlDocument或调用类的代码。

在你的getByIp(...)方法中,第二个if不应该看起来像这样吗?

if (xml.Error()
    || !xml.FirstChild("a")
    || !xml.FirstChild("a")->FirstChild("b")
    || !xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lat")
    || !xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lng")) // <- added missing parenthesis
{ // <- added
    std::string lat = xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lat")->GetText();
    std::string lng = xml.FirstChild("a")->FirstChild("b")->FirstChildElement("lng")->GetText();
    return Region::getByCoordinates(lng, lat);
} // <- added

如果确实缺少大括号,则在检索 lng 字符串时可能会取消引用无效指针,因为它的检索不是条件语句的一部分。

我希望您对指针有一些问题。正如 StackTrace #0 所示,libc.so.6 中有一个没有名称的函数。#1 有一个空 -1 指针。我们需要更多来帮助您修复错误。