我有一个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;
}
}
答案 0 :(得分:1)
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 字符串时可能会取消引用无效指针,因为它的检索不是条件语句的一部分。
答案 1 :(得分:1)
它看起来像是影响堆栈的内存损坏:在已分配的内存之外写入。
你可以编写一个小程序来练习你的Bar类,就像守护进程一样,可能是循环。您还可以使用MALLOC_CHECK_,electric fence,Valgrind或任何其他内存检查工具运行此程序。
可能是curl,TiXmlDocument或调用你的类的代码。
答案 2 :(得分:0)
我希望你有一些关于指针的问题。由于StackTrace#0在libc.so.6中显示了一个没有名称的函数。 #1有一个NULL -1指针。我们还需要更多帮助您修复错误。