1
wjx0912 OP 猜测的原因:__attribute__((constructor))时,c++ runtime 还未初始化,std::string 的一些操作可能不稳定。
测试: ``` std::string g_test1; std::string g_test2; __attribute__((constructor)) static void init() { g_test1 = "hello test1"; printf("init: %s\n", g_test1.c_str()); } void hello_func1(void) { g_test2 = "hello test2"; printf("Hello World: %s, %s\n", g_test1.c_str(), g_test2.c_str()); return; } void hello_func2(void) { printf("Hello World: %s, %s\n", g_test1.c_str(), g_test2.c_str()); return; } ``` 在 hello_func2 里面,g_test1 无法打印,g_test2 正常。 不知道这个思路是否正确,求大神指点 |
2
chingyat 2023-07-17 16:36:56 +08:00
应该是 init() 在 g_test 初始化之前就被调用了。
|
3
wjx0912 OP ```
搞定了,把: std::string g_test1; std::string g_test2; 改成: __attribute__((init_priority(101))) std::string g_test1; __attribute__((init_priority(101))) std::string g_test2; 参考: https://stackoverflow.com/questions/43941159/global-static-variables-initialization-issue-with-attribute-constructor-i ``` |
4
chingyat 2023-07-17 16:38:28 +08:00
```c++
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <string> #include "hello.h" std::string g_test = "initial value"; __attribute__((constructor)) static void init() { g_test = "hello test"; printf("init: %s\n", g_test.c_str()); } void hello_func(void) { printf("Hello World: %s\n", g_test.c_str()); return; } ``` 执行结果: ``` init: hello test Hello World: initial value ``` |
5
wjx0912 OP 这个不是编译器 bug ,是未指定行为
|
6
Shatyuka 2023-07-17 16:40:30 +08:00
`__attribute__((constructor))`在全局变量初始化之前执行。试试给全局变量添加`__attribute__((init_priority(101)))`属性。
|
7
wjx0912 OP @chingyat 嗯。这个是没问题的。但是 g_test 不是固定值(会从文本读取)。runtime 执行一堆 constructor 的顺序问题。
|
9
wjx0912 OP @Shatyuka windows 的 DllMain.DLL_PROCESS_ATTACH 执行的比较晚,所以不会有这个问题,对吧
|
10
yulon 2023-07-17 16:44:22 +08:00
这个问题和 DllMain 一样,在大部分实现上,C 的部分一般比 C++ 运行时要早或者说更底层运行,不要使用 C 方言,不要混用 C/C++ 关于生存周期的部分。
|
11
zpd2009 2023-07-17 16:47:18 +08:00
反汇编看了一下,在.init_array 段,执行完 init 以后,又执行了一个函数,把 g_test1 和 g_test2 又初始化为了空
|
12
yulon 2023-07-17 16:49:35 +08:00
@yulon MSVC 在 DllMain 里使用 C++ 标准库部分功能会炸或者死锁,Mingw-w64 GCC 相对安全一点,因为包了另一套东西,但是微软一直推荐不要在 DllMain 中执行太复杂的操作,DLL 的核心功能应该放在导出函数中。
|
13
zpd2009 2023-07-17 16:54:48 +08:00
如果 g_test1 指定了__attribute__((init_priority(101))),在.init_array 段执行的最后一个函数里,只初始化了 g_test2 ,没有重新初始化 g_test1
|
14
wjx0912 OP |
16
ysc3839 2023-07-17 17:13:30 +08:00 via Android
@wjx0912 #9 不是,DllMain 是最早执行的,但是 CRT 会在执行用户的 DllMain 之前先执行初始化代码。
|
17
yulon 2023-07-17 17:17:51 +08:00
@wjx0912 我说整个标准库,又不是单纯的 std::string ,还有语言层面的特性(线程安全保证之类的)有很多 MSVC 直接用标准库来实现,这种碰到了都会炸😅
|
19
yulon 2023-07-17 17:25:26 +08:00
@wjx0912 还有你这个测试,是在同一个编译单元内,一般来说同编译单元在编译时初始化顺序就决定了,这个很好优化,不同编译单元的初始化顺序是完全不可预料的,链接器可能会帮你排好序,但是遇到冲突是不可能完全按照你预料的顺序来初始化,只有 C++ 运行时完全初始化后,才能保证所有全局变量都初始化了。
|
20
lts9165 2023-07-17 17:32:22 +08:00
std::string& get_test1() {
static std::string test1; return test1; } std::string& get_test2() { static std::string test2; return test2; } __attribute__((constructor)) static void init() { get_test1() = "hello test1"; printf("init: %s\n", get_test1().c_str()); } void hello_func1(void) { get_test2() = "hello test2"; printf("Hello World: %s, %s\n", get_test1().c_str(), get_test2().c_str()); return; } void hello_func2(void) { printf("Hello World: %s, %s\n", get_test1().c_str(), get_test2().c_str()); return; } 这是 chatgpt 给出的方案 |