Skip to content

Commit c6d95c4

Browse files
authored
[libc++] Fix initialization-order-fiasco with iostream.cpp constructors (llvm#126995)
Asan reports it after llvm#124103. It's know case of false positive for Asan. https://github.com/google/sanitizers/wiki/AddressSanitizerInitializationOrderFiasco#false-positives It's can be avoided with `constexpr` constructors. In general order global constructors in different modules is undefined. If global constructor uses external global, they can be not constructed yet. However, implementation may contain workaround for that, or the state of non-constructed global can be still valid. Asan will still falsely report such cases, as it has no machinery to detect correctness of such cases. We need to fix/workaround the issue in libc++, as it will affect many libc++ with Asan users.
1 parent 2157aec commit c6d95c4

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

libcxx/src/iostream.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
1818

1919
template <class StreamT, class BufferT>
2020
union stream_data {
21-
stream_data() {}
22-
~stream_data() {}
21+
constexpr stream_data() {}
22+
constexpr ~stream_data() {}
2323
struct {
2424
// The stream has to be the first element, since that's referenced by the stream declarations in <iostream>
2525
StreamT stream;
@@ -38,13 +38,19 @@ union stream_data {
3838
#define CHAR_MANGLING_wchar_t "_W"
3939
#define CHAR_MANGLING(CharT) CHAR_MANGLING_##CharT
4040

41+
#ifdef _LIBCPP_COMPILER_CLANG_BASED
42+
# define STRING_DATA_CONSTINIT constinit
43+
#else
44+
# define STRING_DATA_CONSTINIT
45+
#endif
46+
4147
#ifdef _LIBCPP_ABI_MICROSOFT
4248
# define STREAM(StreamT, BufferT, CharT, var) \
43-
stream_data<StreamT<CharT>, BufferT<CharT>> var __asm__( \
49+
STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var __asm__( \
4450
"?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \
4551
"@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12@A")
4652
#else
47-
# define STREAM(StreamT, BufferT, CharT, var) stream_data<StreamT<CharT>, BufferT<CharT>> var
53+
# define STREAM(StreamT, BufferT, CharT, var) STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var
4854
#endif
4955

5056
// These definitions and the declarations in <iostream> technically cause ODR violations, since they have different
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <iostream>
10+
11+
// FIXME: Remove after issue https://github.com/llvm/llvm-project/issues/127348 resolved.
12+
extern "C" const char* __asan_default_options() { return "check_initialization_order=true:strict_init_order=true"; }
13+
14+
// Test that ios used from globals constructors doesn't trigger Asan initialization-order-fiasco.
15+
16+
struct Global {
17+
Global() { std::cout << "Hello!"; }
18+
} global;
19+
20+
int main(int, char**) { return 0; }

0 commit comments

Comments
 (0)