fix(command): fix static initialization crash on Kunpeng/Kylin platform#3416
fix(command): fix static initialization crash on Kunpeng/Kylin platform#3416PragmaTwice merged 4 commits intoapache:unstablefrom
Conversation
| static std::deque<CommandAttributes> &getRedisCommandTable() { | ||
| static std::deque<CommandAttributes> redis_command_table; | ||
| return redis_command_table; | ||
| } |
There was a problem hiding this comment.
This will introduce a mutex to every call, which is exactly the reason why I avoid to use static local variables.
There was a problem hiding this comment.
I think there is a small misunderstanding here.
Using a function-local static does not imply taking a lock on every call. With C++11 thread-safe statics, synchronization is only needed during the first initialization. After initialization, the common case is just a guard check, which is typically a load plus a branch, not a contended lock operation.
Also, after the object has been initialized, that guard is effectively read-only. So in practice this should not create the kind of MESI ping-pong that we usually worry about with frequently written shared state. The steady-state overhead is much closer to an extra branch than to repeated locking.
In this code path, the cost is also likely dominated by the following map lookup and string comparisons, so the incremental overhead of the guard check should be negligible relative to the rest of the operation.
The reason for this change is to avoid the static initialization order issue across translation units, which is exactly what caused the startup crash here. So this trades a very small steady-state check for correctness and deterministic initialization.
There was a problem hiding this comment.
I feel that I'm chatting with Claude code instead of a real person 😅
This should not happen. Check related wording in the standard.
|
I agree that, based on the standard wording, this should not happen in theory. What makes this tricky is that we did hit a real startup crash on KylinOS + GCC 12.5.0 in this path, and the function-local static version fixes it consistently. So at the moment my working assumption is that we are dealing with either a toolchain-specific issue or some implementation-sensitive behavior, rather than a contradiction of the standard itself. To verify that, we will also build a minimal multi-translation-unit reproducer and use it to determine whether the root cause is in the toolchain, the initialization model, or some interaction specific to our codebase. |
|
If this is inconsistent with the standard, could it be an issue with the upstream GCC? Would using a different compiler or a newer version resolve the problem? I don't think it's acceptable to introduce additional costs for all platforms just to fix issues with certain upstream components. |
I've reproduced the crash consistently under optimized builds (-O2/-O3) across GCC 12.5.0 and 13.4.0. The failure occurs specifically during static initialization in: The crash disappears when i disable optimizations only for commander.cc. I'm conducting further analysis to identify the root cause. |
|
I've confirmed that when LTO is enabled, the compiler reorders the construction of static variables, which causes crashes on ARM64 with GCC 12.5.0/13.4.0. As a temporary solution, I'll disable LTO for the binary build. Thank you for your patient guidance throughout this issue. |
Hmm I think we can disable LTO by default in CMake to prevent such issues. |
I will add an option in CMake to allow manually enabling LTO when I have some free time. |
|
Line 33 in 5f6d7b2 Just need to toggle |
45dcd74 to
5cffb77
Compare
|



Problem:
We've identified a critical startup crash specific to Kunpeng processors (aarch64) running Kylin OS v10 with GCC 12.5.0. The root cause is a static initialization order issue where:
CommandTable::commands[attr.name] = ...; // ❌ Accesses uninitialized mapSolution:
Implement the "construct on first use" pattern to guarantee safe initialization.
Key Changes: