From 95c70c8d74a9f64a2645c3aa2e5ad0e77cc5e3a0 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Tue, 19 May 2026 10:32:46 -0400 Subject: [PATCH 1/2] [libunwind] Remove MSVC C11 stdalign.h and stdatomic.h fake headers The fake C11 headers under src/native/external/libunwind/include/remote/win/ were added in 2020 (#37521 "Add libunwind to cross DAC") as a workaround for MSVC's missing C11 stdalign.h and stdatomic.h support. Both have since become either redundant or replaceable with a compile flag: - stdalign.h: shipping in MSVC for years. check_include_files(stdalign.h ...) returns TRUE on every supported MSVC, so the fake-generation branch was already dead code that never ran. - stdatomic.h: still gated behind /experimental:c11atomics, but the flag has been stable since VS 2022 17.5 (2023). Enabling it on the libunwind MSVC compile lets the real from MSVC be used directly. The atomic_compare_exchange_strong call in Gaddress_validator.c compiles against the real header. Changes: - Delete the fake-header configure blocks in libunwind_extras/configure.cmake - Delete fakestdalign.h.in and fakestdatomic.h.in templates - Add /experimental:c11atomics to MSVC compile options in libunwind_extras/CMakeLists.txt (gated on MSVC, not HOST_WIN32, so clang-cl is excluded since it does not accept the flag). The _Thread_local workaround block is intentionally left alone: its check_c_source_compiles probe is missing the C-standard-required `static` qualifier, so it would still fail on modern MSVC and the -D_Thread_local= fallback continues to be applied (libunwind on Windows is UNW_REMOTE_ONLY, so no actual thread-local storage is needed). Side benefit: this also structurally eliminates the cross-build stale-fake shadowing bug (#127814 territory) because no fake exists to shadow real NDK/Bionic headers in a mixed CrossDac + Android build environment. Validation (Windows host, MSVC 19.44.35211 / VS 18): - build.cmd -s linuxdac -c Release: SUCCEEDS (1:25, 0 errors, 0 warnings). mscordaccore.dll built; Gaddress_validator.c.obj compiled (192720 bytes). - build.cmd clr.runtime -os android -arch x64 -c checked -lc release: SUCCEEDS (6:49, 0 errors, 0 warnings). libcoreclr.so for Android built. - artifacts/obj/external/libunwind/include/ contains only the real generated headers (config.h, libunwind-common.h, libunwind.h, tdep/libunwind_i.h); no stdatomic.h, no stdalign.h, no msvc-shim/ subdir. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../include/remote/win/fakestdalign.h.in | 9 ----- .../include/remote/win/fakestdatomic.h.in | 36 ------------------- .../external/libunwind_extras/CMakeLists.txt | 8 +++++ .../external/libunwind_extras/configure.cmake | 13 ------- 4 files changed, 8 insertions(+), 58 deletions(-) delete mode 100644 src/native/external/libunwind/include/remote/win/fakestdalign.h.in delete mode 100644 src/native/external/libunwind/include/remote/win/fakestdatomic.h.in diff --git a/src/native/external/libunwind/include/remote/win/fakestdalign.h.in b/src/native/external/libunwind/include/remote/win/fakestdalign.h.in deleted file mode 100644 index 3baf6268c84965..00000000000000 --- a/src/native/external/libunwind/include/remote/win/fakestdalign.h.in +++ /dev/null @@ -1,9 +0,0 @@ -// This is a fake implementation of stdalign.h for when -// compiler C11 stdaliagn.h support is missing - -#ifndef FAKE_STD_ALIGN_H -#define FAKE_STD_ALIGN_H - -#define alignas(x) - -#endif // FAKE_STD_ALIGN_H diff --git a/src/native/external/libunwind/include/remote/win/fakestdatomic.h.in b/src/native/external/libunwind/include/remote/win/fakestdatomic.h.in deleted file mode 100644 index 799770e8bddca9..00000000000000 --- a/src/native/external/libunwind/include/remote/win/fakestdatomic.h.in +++ /dev/null @@ -1,36 +0,0 @@ -// This is a non-atomic fake implementation of stdatomic.h for when -// compiler C11 stdatomic support is missing and only single threaded -// operation is required - -#ifndef FAKE_STD_ATOMICS_H -#define FAKE_STD_ATOMICS_H - -#include - -#define _Atomic volatile -#define ATOMIC_FLAG_INIT 0 - -typedef uint8_t atomic_bool; -typedef uint8_t atomic_flag; - -#define atomic_compare_and_exchange_strong(x, y, z) return ((*(x) == *(y)) ? ((*(x) = z), true) : ((*(y) = *(x)),false)) - -#define atomic_fetch_add(x, y) *(x) += (y), (*(x) - (y)) - -static inline void atomic_flag_clear(volatile atomic_flag* flag) -{ - *flag = ATOMIC_FLAG_INIT; -} - -static inline atomic_bool atomic_flag_test_and_set( volatile atomic_flag* flag ) -{ - atomic_bool result = *flag; - *flag = 1; - return result; -} - -#define atomic_load(x) (*(x)) -#define atomic_store(x, y) do { *(x) = (y); } while (0) - - -#endif // FAKE_STD_ATOMICS_H diff --git a/src/native/external/libunwind_extras/CMakeLists.txt b/src/native/external/libunwind_extras/CMakeLists.txt index 8b7b708b702649..16519c82bf60b8 100644 --- a/src/native/external/libunwind_extras/CMakeLists.txt +++ b/src/native/external/libunwind_extras/CMakeLists.txt @@ -126,6 +126,14 @@ if(CLR_CMAKE_HOST_WIN32) # Assume we are using default MSVC compiler add_compile_options(/permissive-) + # Enable C11 atomics so libunwind's usage + # (e.g. atomic_compare_exchange_strong in Gaddress_validator.c) compiles + # against MSVC's real header instead of a generated fake. + # /std:c11 is already implied by CMAKE_C_STANDARD=11 set in libunwind/CMakeLists.txt. + if(MSVC) + add_compile_options(/experimental:c11atomics) + endif() + # include paths include_directories(${CLR_SRC_NATIVE_DIR}/external/libunwind/include/tdep) include_directories(${CLR_SRC_NATIVE_DIR}/external/libunwind/include) diff --git a/src/native/external/libunwind_extras/configure.cmake b/src/native/external/libunwind_extras/configure.cmake index c95dfbefc84996..ae2c8b5ea2fbc0 100644 --- a/src/native/external/libunwind_extras/configure.cmake +++ b/src/native/external/libunwind_extras/configure.cmake @@ -7,19 +7,6 @@ if(CLR_CMAKE_HOST_WIN32) set(HAVE_ELF_H 1) set(HAVE_ENDIAN_H 1) - # MSVC compiler is currently missing C11 stdalign.h header - # Fake it until support is added - check_include_files(stdalign.h HAVE_STDALIGN_H) - if (NOT HAVE_STDALIGN_H) - configure_file(${CLR_SRC_NATIVE_DIR}/external/libunwind/include/remote/win/fakestdalign.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/stdalign.h COPYONLY) - endif (NOT HAVE_STDALIGN_H) - - # MSVC compiler is currently missing C11 stdatomic.h header - check_c_source_compiles("#include void main() { _Atomic int a; }" HAVE_STDATOMIC_H) - if (NOT HAVE_STDATOMIC_H) - configure_file(${CLR_SRC_NATIVE_DIR}/external/libunwind/include/remote/win/fakestdatomic.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/stdatomic.h COPYONLY) - endif (NOT HAVE_STDATOMIC_H) - # MSVC compiler is currently missing C11 _Thread_local check_c_source_compiles("void main() { _Thread_local int a; }" HAVE_THREAD_LOCAL) if (NOT HAVE_THREAD_LOCAL) From 1305dba1bb1e18702666b8a8da703b28aaa7cf85 Mon Sep 17 00:00:00 2001 From: Mitchell Hwang Date: Wed, 10 Jun 2026 13:37:02 -0400 Subject: [PATCH 2/2] [libunwind] Address PR review feedback Two fixes for PR #129246 review (Copilot reviewer): 1. libunwind_extras/CMakeLists.txt: gate /experimental:c11atomics more precisely. CMake's MSVC variable means "MSVC-like command-line syntax" and is also TRUE for clang-cl, which does not accept the flag. Use `CMAKE_C_COMPILER_ID STREQUAL "MSVC"` so only real cl.exe gets it. Also scope the flag to C sources via `$<$:...>` so it is not passed to C++ compilation (e.g. remote-unwind.cpp). 2. libunwind/CMakeLists.txt: remove the `if (NOT HAVE_STDALIGN_H)` and `if (NOT HAVE_STDATOMIC_H)` blocks that still referenced the deleted fakestdalign.h.in / fakestdatomic.h.in templates. The CoreCLR build enters libunwind via libunwind_extras/CMakeLists.txt and never reads libunwind/CMakeLists.txt, so the dangling references survived local CrossDac/Android/Windows validation; they would break anyone configuring libunwind directly from the repo. Validated: `build.cmd -s linuxdac -c Release` succeeds (1:19, 0 errors), Gaddress_validator.c.obj = 192720 bytes (byte-identical to prior successful builds, proves the c11atomics flag is in effect), no fake headers generated, no remaining fakestd* references anywhere in the repo. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/external/libunwind/CMakeLists.txt | 14 -------------- .../external/libunwind_extras/CMakeLists.txt | 8 ++++++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/native/external/libunwind/CMakeLists.txt b/src/native/external/libunwind/CMakeLists.txt index 8de31d12e32f59..33625800590c9e 100644 --- a/src/native/external/libunwind/CMakeLists.txt +++ b/src/native/external/libunwind/CMakeLists.txt @@ -74,20 +74,6 @@ if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio.*$") set(HAVE_ELF_H 1) set(HAVE_ENDIAN_H 1) - # MSVC compiler is currently missing C11 stdalign.h header - # Fake it until support is added - check_include_files(stdalign.h HAVE_STDALIGN_H) - if (NOT HAVE_STDALIGN_H) - configure_file(include/remote/win/fakestdalign.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/stdalign.h) - endif (NOT HAVE_STDALIGN_H) - - # MSVC compiler is currently missing C11 stdatomic.h header - # Fake it until support is added - check_include_files(stdatomic.h HAVE_STDATOMIC_H) - if (NOT HAVE_STDATOMIC_H) - configure_file(include/remote/win/fakestdatomic.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/stdatomic.h) - endif (NOT HAVE_STDATOMIC_H) - # MSVC compiler is currently missing C11 _Thread_local check_c_source_compiles("void main() { _Thread_local int a; }" HAVE_THREAD_LOCAL) if (NOT HAVE_THREAD_LOCAL) diff --git a/src/native/external/libunwind_extras/CMakeLists.txt b/src/native/external/libunwind_extras/CMakeLists.txt index 16519c82bf60b8..d32ce41751b481 100644 --- a/src/native/external/libunwind_extras/CMakeLists.txt +++ b/src/native/external/libunwind_extras/CMakeLists.txt @@ -130,8 +130,12 @@ if(CLR_CMAKE_HOST_WIN32) # (e.g. atomic_compare_exchange_strong in Gaddress_validator.c) compiles # against MSVC's real header instead of a generated fake. # /std:c11 is already implied by CMAKE_C_STANDARD=11 set in libunwind/CMakeLists.txt. - if(MSVC) - add_compile_options(/experimental:c11atomics) + # CMAKE_C_COMPILER_ID is used instead of MSVC so that clang-cl (which sets + # MSVC=TRUE but does not accept /experimental:c11atomics) is excluded. + # The COMPILE_LANGUAGE:C generator expression scopes the flag to C sources + # so it is not passed to C++ compilation (e.g. remote-unwind.cpp). + if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + add_compile_options($<$:/experimental:c11atomics>) endif() # include paths