【问题标题】:Protobuf object gets corrupted when passed to a dynamic libraryProtobuf 对象在传递给动态库时被损坏
【发布时间】:2020-04-28 13:05:45
【问题描述】:

我正在将我的库与一些深度学习框架集成,但遇到了一些内存问题。我怀疑 protobuf 是这里的问题,但我想征求你们的意见和一些帮助,因为我已经花了太多时间在这上面。简而言之,该框架在 ONNX 格式的深度学习模型上运行。它将它们读入内存到onnx::ModelProto 对象。然后将这些对象传递给我的库,在那里它们被转换(和优化)为我的自定义表示并返回到框架。 onnx::ModelProto 是使用来自https://github.com/onnx/onnx/blob/master/onnx/onnx.protoprotoc 生成的 C++ 类 - 一个常规的 protobuf 消息。

ModelProto 到达我的图书馆时,就会出现问题。 ModelProto 的主要成员是图形,它是一个指针:onnx::GraphProto* onnx::ModelProto::graph_。当对象被传递到我的库时,图形指针被设置为一些不同的地址,这不是正确的GraphProto 对象位置:

framework:
model_proto: 0x2ccb450
graph address: 0x2cc1d20
---
mylib:
model_proto: 0x2ccb450
graph address: 0x7fb6529c2560

烦人的事情是它只发生在发布版本中。当我在调试中编译两者时 - 它可以正常工作。

此外,在出现此错误之前,我使用 std::stringstreamModelProto 对象传递给我的库 - 我首先将框架中的模型序列化为字符串,从中创建一个流并在我的库中反序列化.反序列化完成后,图表也被破坏了,这太糟糕了,以至于我的代码中进一步出现了段错误。

这与框架和我的库都与它们自己的 protobuf 副本静态链接这一事实有关吗? Protobuf 作为依赖项添加,并与框架和我的库一起编译。我确保我使用相同的版本(目前是 3.11)。我也使用相同的 ONNX 版本(1.6)。

以下是依赖项和工作流的外观:

【问题讨论】:

标签: c++ memory protocol-buffers onnx


【解决方案1】:

由于 C++ 中没有标准的 ABI,因此在单独构建的库之间传递对象的门槛相当高。

使用 protobuf 的全部原因是将对象转换为字符串,然后在两个端点之间交换这些字符数组。这样您就可以解决与具有不同布局、格式、精度、字节顺序的对象有关的所有问题。

如果您绝对要传递指针,则构建设置必须相同。一切。所有编译器和链接器版本、设置、所有#defines、优化级别等......这是一条很难遵循的路径,并且会导致一个脆弱的解决方案。

【讨论】:

  • 谢谢,我知道所有可能的 ABI 不一致。不幸的是,当我在框架中序列化模型并从库中的 istream 解析它时,我描述了另一个问题。内存损坏仍然会发生,并且偶尔会导致整个过程出现段错误。
  • 您是否尝试过传递一个 char* 并确保另一方只是从中读取信息?传递字符串流也有同样的风险。
【解决方案2】:

我想我已经找到了解决方案,但我仍然不能 100% 确定根本原因是什么。

ONNX 库允许您自定义生成的类将驻留的命名空间https://github.com/onnx/onnx/blob/master/CMakeLists.txt#L76-L78

我在我的库中将它设置为任意值,最终解决了这个问题。我已经切换回 istringstream 版本,它似乎可以工作。它已经通过了许多 CI 检查,所以目前看起来还不错。

【讨论】:

    猜你喜欢
    • 2018-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多