[libc++][hardening] Add an experimental function to log hardening errors (#149452)

Unlike `verbose_abort`, this function merely logs the error but does not
terminate execution. It is intended to make it possible to implement the
`observe` semantic for Hardening.

(cherry picked from commit d750c6de8a75cbe2bc16c136764195471be8f0b7)
This commit is contained in:
Konstantin Varlamov 2025-07-24 10:39:48 -07:00 committed by Tobias Hieta
parent 1ddf4e3887
commit ee86ae0a69
9 changed files with 110 additions and 0 deletions

View File

@ -535,6 +535,7 @@ set(files
__locale_dir/time.h
__locale_dir/wbuffer_convert.h
__locale_dir/wstring_convert.h
__log_hardening_failure
__math/abs.h
__math/copysign.h
__math/error_functions.h

View File

@ -207,6 +207,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_HAS_EXPERIMENTAL_PSTL _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
# define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
# define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
# define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
# if defined(__MVS__)
# include <features.h> // for __NATIVE_ASCII_F

View File

@ -0,0 +1,42 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___LOG_HARDENING_FAILURE
#define _LIBCPP___LOG_HARDENING_FAILURE
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
// Hardening logging is not available in the C++03 mode; moreover, it is currently only available in the experimental
// library.
#if _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC && !defined(_LIBCPP_CXX03_LANG)
_LIBCPP_BEGIN_NAMESPACE_STD
// This function should never be called directly from the code -- it should only be called through the
// `_LIBCPP_LOG_HARDENING_FAILURE` macro.
[[__gnu__::__cold__]] _LIBCPP_EXPORTED_FROM_ABI void __log_hardening_failure(const char* __message) noexcept;
// _LIBCPP_LOG_HARDENING_FAILURE(message)
//
// This macro is used to log an error without terminating the program (as is the case for hardening failures if the
// `observe` assertion semantic is used).
# if !defined(_LIBCPP_LOG_HARDENING_FAILURE)
# define _LIBCPP_LOG_HARDENING_FAILURE(__message) ::std::__log_hardening_failure(__message)
# endif // !defined(_LIBCPP_LOG_HARDENING_FAILURE)
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC && !defined(_LIBCPP_CXX03_LANG)
#endif // _LIBCPP___LOG_HARDENING_FAILURE

View File

@ -2353,6 +2353,9 @@ module std [system] {
header "__std_mbstate_t.h"
export *
}
module log_hardening_failure {
header "__log_hardening_failure"
}
module verbose_abort {
header "__verbose_abort"
}

View File

@ -309,6 +309,7 @@ add_custom_target(cxx DEPENDS ${LIBCXX_BUILD_TARGETS})
# Build the experimental static library
set(LIBCXX_EXPERIMENTAL_SOURCES
experimental/keep.cpp
experimental/log_hardening_failure.cpp
)
if (LIBCXX_PSTL_BACKEND STREQUAL "libdispatch")

View File

@ -0,0 +1,31 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__config>
#include <__log_hardening_failure>
#include <cstdio>
#ifdef __BIONIC__
# include <syslog.h>
#endif // __BIONIC__
_LIBCPP_BEGIN_NAMESPACE_STD
void __log_hardening_failure(const char* message) noexcept {
// Always log the message to `stderr` in case the platform-specific system calls fail.
std::fputs(message, stderr);
#if defined(__BIONIC__)
// Show error in logcat. The latter two arguments are ignored on Android.
openlog("libc++", 0, 0);
syslog(LOG_CRIT, "%s", message);
closelog();
#endif
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Basic smoke test for `__log_hardening_failure`.
//
// UNSUPPORTED: c++03
// UNSUPPORTED: libcpp-has-no-experimental-hardening-observe-semantic
#include <__log_hardening_failure>
#include "test_macros.h"
ASSERT_NOEXCEPT(std::__log_hardening_failure(""));
int main(int, char**) {
std::__log_hardening_failure("Some message");
// It's difficult to properly test platform-specific logging behavior of the function; just make sure it exists and
// can be called at runtime.
return 0;
}

View File

@ -29,3 +29,7 @@
#if !_LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM
# error "-fexperimental-library should enable the syncstream header"
#endif
#if !_LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC
# error "-fexperimental-library should allow using the Hardening observe semantic"
#endif

View File

@ -361,6 +361,7 @@ DEFAULT_PARAMETERS = [
AddFeature("libcpp-has-no-incomplete-pstl"),
AddFeature("libcpp-has-no-experimental-tzdb"),
AddFeature("libcpp-has-no-experimental-syncstream"),
AddFeature("libcpp-has-no-experimental-hardening-observe-semantic"),
],
),
# TODO: This can be improved once we use a version of GoogleBenchmark that supports the dry-run mode.