Description
Following simple code example crashes or doesn't work correctly on MSYS2 UCRT64 clang++
and on MSYS2 CLANG64 clang++
. All other compilers don't have problem with this, gcc/clang on linux, msvc or clang-cl msvc and also MSYS2 UCRT64 g++.
It crashes because ConstAppInline::LEFT
is uninitialized during the Model::m_fillable
initialization.
I think that this is happening, here should apply Ordered dynamic initialization
, so the initialization should be sequenced:
within a single translation unit, initialization of these variables is always sequenced in exact order their definitions appear in the source code.
The consequence is that you can not initialize inline static data member with Inline const variables at namespace scope variable with external linkage. ☝️
Click to expand!
#include <iostream>
#include <string>
#include <vector>
//#include <QDebug>
//#include <QStringLiteral>
namespace ConstAppInline
{
// Common chars
// inline const QChar DOT = QChar('.');
// Common strings
inline const std::string LEFT = "left";
// inline const QString LEFT = "left";
} // namespace ConstAppInline
class Model
{
inline static std::vector<std::string> m_fillable {ConstAppInline::LEFT};
// inline static QStringList m_fillable {ConstAppInline::LEFT};
public:
inline void run() const
{
std::cout << m_fillable.size() << "\n";
for (const auto &s : m_fillable)
std::cout << s << "\n";
// qDebug() << m_fillable.size();
// qDebug() << m_fillable;
}
};
int main(int /*unused*/, char */*unused*/[])
{
Model m;
m.run();
return 0;
}
The example contains two types, one types from stl library and other for Qt types, in both versions the ConstAppInline::LEFT
is uninitialized.
Qt version crashes and the output with stl types is like following:
1
Of course, it should look like this with stl types:
1
left
And like this with Qt types:
1
QList("left")
This is the long-running bug that I'm experiencing with during the development of one of my libraries and hoped that it will be fixed, but it wasn't. The problem exists as long as I remember, from Clang 10/11
.
Metadata
Metadata
Assignees
Type
Projects
Status
Activity
llvmbot commentedon Oct 1, 2023
@llvm/issue-subscribers-clang-codegen
It crashes because
ConstAppInline::LEFT
is uninitialized during theModel::m_fillable
initialization.I think that this is happening, here should apply
Ordered dynamic initialization
, so the initialization should be sequenced:> within a single translation unit, initialization of these variables is always sequenced in exact order their definitions appear in the source code.
The consequence is that you can not initialize inline static data member with Inline const variables at namespace scope variable with external linkage. ☝️
<details>
<summary>Click to expand!</summary>
</details>
The example contains two types, one types from stl library and other for Qt types, in both versions the
ConstAppInline::LEFT
is uninitialized.Qt version crashes and the output with stl types is like following:
Of course, it should look like this with stl types:
And like this with Qt types:
This is the long-running bug that I'm experiencing with during the development of one of my libraries and hoped that it will be fixed, but it wasn't. The problem exists as long as I remember, from
Clang 10/11
.alvinhochun commentedon Oct 1, 2023
This looks like to be a mishap with the
.ctors
section.For your code snippet https://godbolt.org/z/ccreG5rdK, Clang emits two separate functions to initialize the two non-local variables:
__cxx_global_var_init
initializesConstAppInline::LEFT
__cxx_global_var_init.1
initializesModel::m_fillable
Pointers to these functions are placed in the
.ctors
section in forward order:However, the trap is that functions in the
.ctors
list are executed in reverse order. The end result is that the constructors get executed in reverse.This turns out to not affect Linux because instead of the
.ctors
section, it uses the.init_array
section which has forward order.GCC for mingw-w64 target is not affected because GCC generates only one function
_GLOBAL__sub_I_main
to put in the.ctors
section. This function in turn calls__static_initialization_and_destruction_0()
, which handles the initialization of bothConstAppInline::LEFT
andModel::m_fillable
in sequence.Note: I wrote the above entirely based on the output from Compiler Explorer without testing locally, so it is possible I may have got something wrong.
CC @MaskRay @mstorsjo
alvinhochun commentedon Oct 4, 2023
I was trying to see if this can be reproduced on Linux: https://godbolt.org/z/zW4a8MYE3
I found that the option
-fno-use-init-array
can be used to tell Clang to use the.ctors
section instead of.init_array
. However, when I do this, Clang correctly generates the section in reverse order unlike for MinGW target:(The linked executable ends up producing the wrong output, but that seems to be caused by different reasons, so irrelevant here.)
It turns out CodeGen/AsmPrinter has code to reverse the constructor / destructor list specifically for this purpose, but it's not being activated by the Clang MinGW driver:
llvm-project/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Lines 2808 to 2811 in 19991d0
Passing
-fno-use-init-array
to cc1 fixes the issue (https://godbolt.org/z/jhnn4r1YT). So the obvious fix for the issue is to addCC1Args.push_back("-fno-use-init-array");
to:llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp
Lines 693 to 695 in 503bc5f
[clang] [MinGW] Explicitly always pass the -fno-use-init-array
mstorsjo commentedon Oct 9, 2023
See #68570 and #68571 for potential fixes for the issue.
silverqx commentedon Oct 9, 2023
I will try to execute my project after it hits stable branch and let know if still crashes, also thx for fixes.
29 remaining items