diff --git a/CMakeLists.txt b/CMakeLists.txt index 88994d828a..a02cc8ce75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,6 +263,17 @@ endif() set(CMAKE_C_VISIBILITY_PRESET hidden) +set(print_msan_notice) +if(SECP256K1_BUILD_CTIME_TESTS) + include(CheckMemorySanitizer) + check_memory_sanitizer(msan_enabled) + if(msan_enabled) + try_append_c_flags(-fno-sanitize-memory-param-retval) + set(print_msan_notice YES) + endif() + unset(msan_enabled) +endif() + # Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target. # CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing. # See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2 @@ -332,7 +343,7 @@ message("Valgrind .............................. ${SECP256K1_VALGRIND}") get_directory_property(definitions COMPILE_DEFINITIONS) string(REPLACE ";" " " definitions "${definitions}") message("Preprocessor defined macros ........... ${definitions}") -message("C compiler ............................ ${CMAKE_C_COMPILER}") +message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}") message("CFLAGS ................................ ${CMAKE_C_FLAGS}") get_directory_property(compile_options COMPILE_OPTIONS) string(REPLACE ";" " " compile_options "${compile_options}") @@ -358,7 +369,14 @@ endif() if(SECP256K1_LATE_CFLAGS) message("SECP256K1_LATE_CFLAGS ................. ${SECP256K1_LATE_CFLAGS}") endif() -message("\n") +message("") +if(print_msan_notice) + message( + "Note:\n" + " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n" + " to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n" + ) +endif() if(SECP256K1_EXPERIMENTAL) message( " ******\n" diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4 index fee2d7b4db..048267fa6e 100644 --- a/build-aux/m4/bitcoin_secp.m4 +++ b/build-aux/m4/bitcoin_secp.m4 @@ -50,10 +50,14 @@ AC_MSG_CHECKING(whether MemorySanitizer is enabled) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ #if defined(__has_feature) # if __has_feature(memory_sanitizer) - # error "MemorySanitizer is enabled." + /* MemorySanitizer is enabled. */ + # elif + # error "MemorySanitizer is disabled." # endif + #else + # error "__has_feature is not defined." #endif - ]])], [msan_enabled=no], [msan_enabled=yes]) + ]])], [msan_enabled=yes], [msan_enabled=no]) AC_MSG_RESULT([$msan_enabled]) ]) diff --git a/cmake/CheckMemorySanitizer.cmake b/cmake/CheckMemorySanitizer.cmake new file mode 100644 index 0000000000..d9ef681e65 --- /dev/null +++ b/cmake/CheckMemorySanitizer.cmake @@ -0,0 +1,18 @@ +include_guard(GLOBAL) +include(CheckCSourceCompiles) + +function(check_memory_sanitizer output) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + check_c_source_compiles(" + #if defined(__has_feature) + # if __has_feature(memory_sanitizer) + /* MemorySanitizer is enabled. */ + # elif + # error \"MemorySanitizer is disabled.\" + # endif + #else + # error \"__has_feature is not defined.\" + #endif + " HAVE_MSAN) + set(${output} ${HAVE_MSAN} PARENT_SCOPE) +endfunction() diff --git a/configure.ac b/configure.ac index 9640a67399..b6d20cc9e1 100644 --- a/configure.ac +++ b/configure.ac @@ -248,7 +248,7 @@ if test x"$enable_ctime_tests" = x"auto"; then fi print_msan_notice=no -if test x"$enable_ctime_tests" = x"yes" && test x"$GCC" = x"yes"; then +if test x"$enable_ctime_tests" = x"yes"; then SECP_MSAN_CHECK # MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if # the uninitalized variable is never actually "used". This is called "eager" checking, and it's