简体   繁体   English

是否可以通过使用隐藏可见性来避免 ODR 违规?

[英]Can ODR violation be avoided by using hidden visibility?

So for example, I have a slightly complicated case of library dependency in one of my projects:因此,例如,我的一个项目中有一个稍微复杂的库依赖案例:


              /--------------------------------\
              |                                |
      /----> GRPC <------------------\         |
      |                              |         |
      |        (c++)                 |         |        
      \-------   A  -------------->  B         |
                 |                 (rust)      |
                 |                             |
                 \------------------> c++  <---/ 

Rust by default will prefer to use static linkage. Rust 默认会优先使用 static 链接。 Executable A is also built to statically link lib(std)c++.可执行文件 A 也被构建为静态链接 lib(std)c++。 So, to my understanding, there will be two copies of STL implementation in both A and B. This is exactly the pattern that https://developer.android.com/ndk/guides/cpp-support#sr suggests avoiding.因此,据我了解,A 和 B 中都会有两个 STL 实现副本。这正是https://developer.ZC31B32364CE19CA8FCD150A417ECCE58-support.com建议的模式

However, looking through the dynamic linkage table (via nm -D , for example) of B;但是,查看 B 的动态链接表(例如通过nm -D ); I could see no exported lib(std)c++/grpc symbol.我看不到导出的 lib(std)c++/grpc 符号。 This is because rust marks them hidden by default.这是因为 rust 默认将它们标记为隐藏。

  • So, is it safe (or conforming the ODR) if all common symbols in B are hidden?那么,如果 B 中的所有常见符号都被隐藏,它是否安全(或符合 ODR)?

conforming the ODR符合 ODR

One-definition rule is part of C++ programming language.一定义规则是C++编程语言的一部分。 It's relevant to C++ language.它与 C++ 语言有关。 It's irrelevant to anything else.这与其他任何事情都无关。 There is no ODR "outside" of C++. C++ 的“外部”没有 ODR。 C++ standard does not apply outside of C++, it's only about C++ programming language. C++ 标准不适用于 C++ 之外,它仅适用于 C++ 编程语言。

There is no wildly adopted portable super-standard concerning language interoperability.关于语言互操作性,没有广泛采用的可移植超级标准。 These are just tools, there are no definitions and rules.这些只是工具,没有定义和规则。 ODR or any other rule from C++ does not apply here. ODR 或 C++ 中的任何其他规则在此处不适用。

Trying to apply C++ standard rules to unrelated contexts makes little sense.尝试将 C++ 标准规则应用于不相关的上下文几乎没有意义。 Rust is not part of C++. Rust 不是 C++ 的一部分。 RPC is platform specific, outside the scope of C++ programming language. RPC 是特定于平台的,在 C++ 编程语言的 scope 之外。

Ergo, reasoning that some C++ rule will or will not be broken in a work chain that uses platform specific tools - a shared library, "dynamic linkage table" - and uses multiple programming language just doesn't apply here.因此,推理某些 C++ 规则将或不会在使用平台特定工具的工作链中被破坏 - 共享库,“动态链接表” - 并使用多种编程语言在这里并不适用。

In the sense of C++, this all is literally "undefined behavior" - there are no rules from C++ standard that could apply here.在 C++ 的意义上,这一切都是“未定义的行为”——C++ 标准中没有任何规则可以适用于此。

Can ODR violation be avoided by using hidden visibility?是否可以通过使用隐藏可见性来避免 ODR 违规?

Sure.当然。

The android doc says: android 文档说:

In this situation, the STL, including and global data and static constructors, will be present in both libraries.在这种情况下,STL,包括全局数据和 static 构造函数,将出现在两个库中。 The runtime behavior of this application is undefined, and in practice crashes are very common.这个应用程序的运行时行为是未定义的,在实践中崩溃是很常见的。 Other possible issues include:其他可能的问题包括:

Memory allocated in one library, and freed in the other, causing memory leakage or heap corruption. Memory 在一个库中分配,在另一个库中释放,导致 memory 泄漏或堆损坏。

You mentioned those symbols are hidden.你提到那些符号是隐藏的。 However, is it equal to, the global data is not presented twice?但是,是否等于,全局数据呈现两次?

If the global data can be presented twice, then "Memory allocated in one library, and freed in the other, causing memory leakage or heap corruption" may happen.如果全局数据可以呈现两次,则可能会出现“内存分配在一个库中,而在另一个库中释放,导致 memory 泄漏或堆损坏”的情况。 For example, if some memory is allocated in Rust, and we transfer it to C++, and C++ later frees it, then we are facing this situation. For example, if some memory is allocated in Rust, and we transfer it to C++, and C++ later frees it, then we are facing this situation. Of course your code may not have this case, but if some code in the future violates, or if one day you use a third party library which violates it, then we are in trouble (and seems to be hard to debug).当然你的代码可能没有这种情况,但是如果将来有代码违反了,或者如果有一天你使用了违反它的第三方库,那么我们就有麻烦了(并且似乎很难调试)。

Indeed, what about letting C++ to statically link the Rust code?确实,让 C++静态链接 Rust 代码怎么样? Then you get a giant .so file containing your C++, your Rust, your dependency, etc. However, even if you can do that, we may still need to be careful: Is the giant .so file the only one in your whole Android app?然后你会得到一个巨大的.so文件,其中包含你的 C++、你的 Rust、你的依赖项等。但是,即使你可以做到这一点,我们可能仍然需要小心:巨型.so文件是你整个 ZE84ZDB6DB60B9390CDBDD46C 中唯一的一个吗?应用程序? In other words, are you sure you do not have, and will never have any other native libraries?换句话说,你确定你没有,也永远不会有任何其他原生库吗? If not, IMHO we may still be facing the problem again.如果没有,恕我直言,我们可能仍然会再次面临问题。

Anyway I am not an expert in Android/C++.无论如何,我不是 Android/C++ 方面的专家。 I was having a similar problem a few months ago (replace "C++ code" with "the Flutter engine which is written in C++" and so on) and made some workaround.几个月前我遇到了类似的问题(将“C++ 代码”替换为“用 C++ 编写的 Flutter 引擎”等等)并做了一些解决方法。 So this post is not really an answer, but rather some (can be wrong) thoughts and suggestions.所以这篇文章并不是真正的答案,而是一些(可能是错误的)想法和建议。 Hope someone can correct me!希望有人能纠正我!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM