-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MSYS2] Ordered dynamic initialization is not sequenced #55938
[MSYS2] Ordered dynamic initialization is not sequenced #55938
Comments
@llvm/issue-subscribers-clang-codegen
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 I think that this is happening, here should apply > 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> #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;
} </details> The example contains two types, one types from stl library and other for Qt types, in both versions the 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 |
This looks like to be a mishap with the For your code snippet https://godbolt.org/z/ccreG5rdK, Clang emits two separate functions to initialize the two non-local variables:
Pointers to these functions are placed in the .section .ctors,"dw",associative,ConstAppInline::LEFT[abi:cxx11]
.p2align 3, 0x0
.quad __cxx_global_var_init
.section .ctors,"dw",associative,Model::m_fillable[abi:cxx11]
.p2align 3, 0x0
.quad __cxx_global_var_init.1 However, the trap is that functions in the This turns out to not affect Linux because instead of the GCC for mingw-w64 target is not affected because GCC generates only one function 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. |
I was trying to see if this can be reproduced on Linux: https://godbolt.org/z/zW4a8MYE3 I found that the option .section .ctors,"aGw",@progbits,Model::m_fillable[abi:cxx11],comdat
.p2align 3, 0x90
.quad __cxx_global_var_init.1
.section .ctors,"aGw",@progbits,ConstAppInline::LEFT[abi:cxx11],comdat
.p2align 3, 0x90
.quad __cxx_global_var_init (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 llvm-project/clang/lib/Driver/ToolChains/MinGW.cpp Lines 693 to 695 in 503bc5f
|
On MinGW targets, the .ctors section is always used (as opposed to on ELF platforms, where .init_section is the default but one can select using .ctors, with the -use-ctors option, or the UseInitArray field in TargetOptions). Apply the reverse ordering regardless of whether the caller has set the UseInitArray flag for this target, as this target unconditionally uses the .ctors section anyway. For the CodeGen/X86/constructor.ll testcase, note how this now produces the same output ordering as for ELF targets with -use-ctors. This fixes llvm#55938.
On MinGW targets, the .ctors section is always used for constructors. Make sure that all layers of code generation is aware of this, wherever it matters, by passing the -fno-use-init-array option, setting the TargetOptions field UseInitArray to false. This fixes llvm#55938.
I will try to execute my project after it hits stable branch and let know if still crashes, also thx for fixes. |
Reopening for backporting the fix, which should be small and safe enough. |
/cherry-pick a2b8c49 |
/branch llvm/llvm-project-release-prs/issue55938 |
On MinGW targets, the .ctors section is always used for constructors. When using the .ctors section, the constructors need to be emitted in reverse order to get them execute in the right order. (Constructors with a specific priority are sorted separately by the linker later.) In LLVM, in CodeGen/AsmPrinter/AsmPrinter.cpp, there's code that reverses them before writing them out, executed when using the .ctors section. This logic is done whenever TM.Options.UseInitArray is set to false. Thus, make sure to set UseInitArray to false for this target. This fixes llvm/llvm-project#55938. (cherry picked from commit a2b8c49c1839076b540c542c024fcfe2361a3e47)
/pull-request llvm/llvm-project-release-prs#727 |
I want to ask in which release it will be available? |
It's in git main now, so it would be included in 18.x. But I put in a request to backport the fix to 17.x, so if that's accepted in llvm/llvm-project-release-prs#727 and deemed acceptable by the release managers, it could be in one of the following point releases (e.g. 17.0.3 next week). |
Ok, thx for info |
I wonder why this was closed? It was supposed to be open while waiting for the backport. Any idea what happened @owenca ? |
Not sure what happened. My apologies! |
On MinGW targets, the .ctors section is always used for constructors. When using the .ctors section, the constructors need to be emitted in reverse order to get them execute in the right order. (Constructors with a specific priority are sorted separately by the linker later.) In LLVM, in CodeGen/AsmPrinter/AsmPrinter.cpp, there's code that reverses them before writing them out, executed when using the .ctors section. This logic is done whenever TM.Options.UseInitArray is set to false. Thus, make sure to set UseInitArray to false for this target. This fixes llvm/llvm-project#55938. (cherry picked from commit a2b8c49c1839076b540c542c024fcfe2361a3e47)
The fix was backported to 17.0.3, which was released yesterday, and a release of llvm-mingw with that version of LLVM is out now as well: https://github.com/mstorsjo/llvm-mingw/releases/tag/20231017 |
Great, thx |
@llvm/issue-subscribers-clang-driver Author: Silver Zachara (silverqx)
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 I think that this is happening, here should apply > 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> #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;
} </details> The example contains two types, one types from stl library and other for Qt types, in both versions the 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 |
Now I have tested my project with inline constants enabled and it builds, so this bug is fixed for sure. Thx @mstorsjo @alvinhochun [OT] But a very similar bug exists for extern constants for shared builds 😅, now I tested it as well and it still exists, but it's reproducible only with clang-cl with msvc, MSYS2 is fine with this extern constants shared build combination. |
Following simple code example crashes or doesn't work correctly on
MSYS2 UCRT64 clang++
and onMSYS2 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 theModel::m_fillable
initialization.I think that this is happening, here should apply
Ordered dynamic initialization
, so the initialization should be sequenced: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!
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
.The text was updated successfully, but these errors were encountered: