使用g ++优化的Rapidjson seg错误

时间:2015-09-23 12:47:38

标签: c++ c segmentation-fault compiler-optimization rapidjson

我正在使用Rapidjson,并注意到当我打开g ++中的优化(-O1 / -O2 / -O3)时,我遇到了分段错误。我想我已将其追溯到GenericValue& Rapidjson中的AddMember()函数。

GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
    RAPIDJSON_ASSERT(IsObject());
    RAPIDJSON_ASSERT(name.IsString());

    Object& o = data_.o;
    if (o.size >= o.capacity) {
        if (o.capacity == 0) {
            o.capacity = kDefaultObjectCapacity;
            o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
        }
        else {
            SizeType oldCapacity = o.capacity;
            o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
            o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
        }
    }
    o.members[o.size].name.RawAssign(name);
    o.members[o.size].value.RawAssign(value);
    o.size++;
    return *this;
}

调试时,我可以看到kDefaultObjectCapacity(正在优化出来(这是一个静态const SizeType kDefaultObjectCapacity = 16)

因此,行&#34; o.capacity = kDefaultObjectCapacity;&#34;没有被执行,并且malloc正在mallocing 0字节然后尝试投射它。

为什么要删除这个静态const?

我试过制作Object&amp; o挥发性和静态,都没有效果。 有什么想法吗?

由于 将

编辑: 我不能像在嵌入式平台上那样轻松运行测试,目前使用buildroot构建rapidjson。我尝试了单元测试,但无法让它们进入目标。

我可以看看提供程序集,但它是大型应用程序的一部分,因此可能很难找到正确的位。

有关信息,这是调用rapidjson代码的方法,这就是问题所在:

int16_t FrontEndJSONHandlers::get_run_cfg_packer(JSONEngine& json_engine, char *message, int32_t *length)
{
Document doc;

// Need to pack an empty request to get the data
doc.SetObject();
doc.AddMember(JSONRPC_MEMBER, JSONRPC_VERSION, doc.GetAllocator());
doc.AddMember(METHOD_MEMBER, JSON_RPC_METH_GET_RUN_CFG, doc.GetAllocator());
doc.AddMember(ID_MEMBER, json_engine.GetNextMessageID(), doc.GetAllocator());

// Format the message
json_engine.FormatMessageAndRegisterResponseHandler(&doc, &message, &length, get_run_cfg_handler);

return 0;
}

如果我将Document doc设为静态,那么它不会出错 - 不确定这是否是围绕它的最佳方式?

2 个答案:

答案 0 :(得分:1)

您的代码看起来非常错误,并且让我怀疑您也误解了您在调试器中看到的内容。尝试先修复bug,然后再担心优化器可能会做什么:

您的部分意图似乎是o.capacity结束>(或者您打算>=)o.size

但是当o.capacity从零开始时你是否考虑过案例o.size > kDefaultObjectCapacity?更严重的是,对于增加容量的代码,您对增加1.5倍的评论是错误的。您可能打算oldCapacity*3/2

if (o.size >= o.capacity) {
    if (o.capacity == 0) {
        o.capacity = kDefaultObjectCapacity;
        o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
    }
    else {
        SizeType oldCapacity = o.capacity;
        o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
        o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
    }
}
编辑:我误解了上面的大部分内容。但我仍然认为对调试器中看到的内容的误解更可能是优化器破坏该代码的原因。

“90”是十进制,还是十六进制?优化器当然可以跳过乘以sizeof(Member)并直接转到乘法的结果。

答案 1 :(得分:0)

我遇到了类似的问题,使用GCC 4.9编译:当指定优化标志(-On)时,我遇到了分段错误。这很容易复制,这是代码:

//...
#include "extern/rapidjson/document.h"
//...
void* MyThread(void*)
{
   std::cout << "Start of MyThread" << std::endl;

   rapidjson::Document doc;
   doc.Parse("{ \"NAME\": \"Peter\", \"AGE\": 38, \"Male\": true}");

   std::cout << "End!";

   return NULL;
}

int main(int argc, char** argv) 
{
   pthread_t thread;

   pthread_create(&thread, NULL, &MyThread, NULL);

   std::string str;
   std::cout << "Press <Return>"  << std::endl;
   std::getline(std::cin, str);

   return 0;
 }

这里的关键是在单独的线程中创建和解析的文档。如果我们直接在main()中调用“MyThread(NULL)”,我们就不会有任何错误。

与Visual Studio 2012类似的代码经过优化,运行良好。我运行了VS代码分析,没有发现错误。唯一的区别是线程:

std::thread th([] { MyThread(NULL); }); 
th.join();

===============================================

问题已在版本1.0.2之后修复。使用最新的代码工作正常。