gdb 显示奇怪的堆栈跟踪

Posted

技术标签:

【中文标题】gdb 显示奇怪的堆栈跟踪【英文标题】:gdb shows weird stack trace 【发布时间】:2014-02-17 07:24:53 【问题描述】:

我有一个 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;
    

【问题讨论】:

【参考方案1】:

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

您可以编写一个小程序来执行您的 Bar 类,就像您的守护程序一样,可能在一个循环中。您也可以使用MALLOC_CHECK_、electric fence、Valgrind 或任何其他内存检查工具运行此程序。

可能是 curl、TiXmlDocument 或调用您的类的代码。

【讨论】:

【参考方案2】:

您的 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 字符串时取消引用无效指针,因为它的检索不是条件语句的一部分。

【讨论】:

我的错,对不起,但这部分代码看起来有点不同,这不是原因,我已经更新了代码。代码是专有的,我无法按原样显示,这就是我没有复制粘贴它的原因。但是其余的代码是一样的,只是变量/类名不同。 我感觉这更像是一个复制粘贴错误,但我指出了这一点,所以我们不会遗漏任何明显的东西。祝你有美好的一天:-)。 否则这段代码显然不会被编译;)【参考方案3】:

我希望您对指针有一些问题。由于 StackTrace #0 显示了 libc.so.6 中没有名称的函数。并且 #1 有一个 NULL -1 指针。我们需要更多帮助您修复错误。

【讨论】:

我添加了可能有错误的代码。也许 cURL 有内部错误/内存泄漏,我有时必须重新初始化它?

以上是关于gdb 显示奇怪的堆栈跟踪的主要内容,如果未能解决你的问题,请参考以下文章

GDB堆栈跟踪与汇编调试

从核心转储中获取堆栈跟踪

堆栈跟踪中没有函数名称,GDB,但出现在LLDB中[重复]

从程序内部调用 gdb 以打印其堆栈跟踪的最佳方法?

sys.exc_info 在捕获和引发时不跟踪完整的堆栈跟踪?

不可思议的堆栈跟踪