【问题标题】:gdb shows weird stack tracegdb 显示奇怪的堆栈跟踪
【发布时间】: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;
    }
}

【问题讨论】:

    标签: c++ curl gdb


    【解决方案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 有内部错误/内存泄漏,我有时必须重新初始化它?
      猜你喜欢
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多