c++ - 使用 g++ 优化的 Rapidjson 段错误

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

我正在使用 Rapidjson,并注意到当我在 g++ (-O1/-O2/-O3) 中打开优化时,我遇到了段错误。我想我已经将其追踪到rapidjson 中的GenericValue& 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 (正在被优化(这是一个 static const SizeType kDefaultObjectCapacity = 16)

因此行“o.capacity = kDefaultObjectCapacity;”没有被执行,并且 malloc 正在分配 0 字节然后尝试转换它。

为什么要删除这个静态常量?

我尝试过使 Object& o 既可变又静态,但都不起作用。 有什么想法吗?

谢谢 会

编辑: 我无法轻松运行测试,因为它是在嵌入式平台上,rapidjson 目前是使用 buildroot 构建的。我尝试了单元测试,但无法让它们达到目标。

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

仅供引用,这是调用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;
}

如果我将文档文档设置为静态,它不会出现段错误 - 不确定这是否是解决它的最佳方法?

最佳答案

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

看来您的部分意图是让 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) 并直接转到该乘法的结果。

关于c++ - 使用 g++ 优化的 Rapidjson 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32740053/

相关文章:

c++ - 与 std::unordered_map 或 std::map 相比,MFC CMap 是否具有良好的性能

c - shmat 返回段错误(核心已转储)

在c中创建一个二维字符数组

error-handling - 如何更改此应用程序以禁用命令行输入?

c - 在c中读取单独的用户输入行

c++ - 从哪里获得 Explorerframe.lib?

c++ - C++ 是否支持可变长度数组?

c - 段错误(核心已转储)- C 参数

c++ - 如何在另一个目录中使用 G++ 编译具有依赖项的 .cpp 文件

c - OpenGL:根据 C 语言改编的红皮书示例进行不稳定渲染