Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -944,6 +945,7 @@ set(files
__vector/vector_bool.h
__vector/vector_bool_formatter.h
__verbose_abort
__verbose_trap
algorithm
any
array
Expand Down
32 changes: 31 additions & 1 deletion libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,36 @@ _LIBCPP_HARDENING_MODE_EXTENSIVE, \
_LIBCPP_HARDENING_MODE_DEBUG
# endif

// Hardening assertion semantics mirror the evaluation semantics of P3100 Contracts:
// - `ignore` does not evaluate the assertion;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is incorrect. We do evaluate the assertion, but then we do nothing with that. Let's make this documentation accurate.

That being said, let's also file a Github issue to later go back and fix this: we should mirror what the actual C++26 contracts do, and not evaluate the assertion. Since that's going to require a rework of our assertion machinery, let's not do that right now.

// - `observe` logs an error (indicating, if possible, that the error is fatal) and continues execution;
// - `quick-enforce` terminates the program as fast as possible (via trapping);
// - `enforce` logs an error and then terminates the program.
// Notes:
// - Continuing execution after a hardening check fails results in undefined behavior; the `observe` semantic is meant
// to make adopting hardening easier but should not be used outside of this scenario;
// - P3471 "Standard Library Hardening" wording precludes using the Contracts `ignore` semantic for hardened
// preconditions in the Library; allowing this semantic to be used is a libc++ vendor extension.
// clang-format off
# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 1)
# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 2)
# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 3)
# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 4)
// clang-format on

// Allow users to define an arbitrary assertion semantic; otherwise, use the default mapping from modes to semantics.
// The default is for production-capable modes to use `quick-enforce` (i.e., trap) and for the `debug` mode to use
// `enforce` (i.e., log and abort).
# ifndef _LIBCPP_ASSERTION_SEMANTIC

# if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_ENFORCE
# else
# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE
# endif

# endif // _LIBCPP_ASSERTION_SEMANTIC

// } HARDENING

# define _LIBCPP_TOSTRING2(x) #x
Expand Down Expand Up @@ -489,7 +519,7 @@ typedef __char32_t char32_t;
# ifndef _LIBCPP_NO_ABI_TAG
# define _LIBCPP_HIDE_FROM_ABI \
_LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION \
__attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_ODR_SIGNATURE))))
__attribute__((__abi_tag__(_LIBCPP_TOSTRING(_LIBCPP_ODR_SIGNATURE))))
# else
# define _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION
# endif
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/__configuration/availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
#define _LIBCPP_AVAILABILITY_HAS_VERBOSE_ABORT _LIBCPP_INTRODUCED_IN_LLVM_15
#define _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE

// This controls whether the library provides a function to log hardening failures without terminating the program (for
// the `observe` assertion semantic).
#define _LIBCPP_AVAILABILITY_HAS_LOG_HARDENING_FAILURE _LIBCPP_INTRODUCED_IN_LLVM_21
#define _LIBCPP_AVAILABILITY_LOG_HARDENING_FAILURE _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE

// This controls the availability of the C++17 std::pmr library,
// which is implemented in large part in the built library.
//
Expand Down
45 changes: 45 additions & 0 deletions libcxx/include/__log_hardening_failure
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// -*- 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

_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.
_LIBCPP_AVAILABILITY_LOG_HARDENING_FAILURE _LIBCPP_OVERRIDABLE_FUNC_VIS void
__libcpp_log_hardening_failure(const char* message) _NOEXCEPT;

// _LIBCPP_LOG_HARDENING_FAILURE(message)
//
// This macro is used to log a hardening failure without terminating the program (as is the case if the `observe`
// assertion semantic is used). Where possible, it logs in a way that indicates a fatal error (which might include
// capturing the stack trace).
#if !defined(_LIBCPP_LOG_HARDENING_FAILURE)

# if !_LIBCPP_AVAILABILITY_HAS_LOG_HARDENING_FAILURE
// The decltype is there to suppress -Wunused warnings in this configuration.
void __use(const char*);
# define _LIBCPP_LOG_HARDENING_FAILURE(message) (decltype(::std::__use(message))())
# else
# define _LIBCPP_LOG_HARDENING_FAILURE(message) ::std::__libcpp_log_hardening_failure(message)
# endif

#endif // !defined(_LIBCPP_LOG_HARDENING_FAILURE)

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___LOG_HARDENING_FAILURE
37 changes: 37 additions & 0 deletions libcxx/include/__verbose_trap
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// -*- 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___VERBOSE_TRAP
#define _LIBCPP___VERBOSE_TRAP

#include <__config>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

# if __has_builtin(__builtin_verbose_trap)
// AppleClang shipped a slightly different version of __builtin_verbose_trap from the upstream
// version before upstream Clang actually got the builtin.
// TODO: Remove once AppleClang supports the two-arguments version of the builtin.
# if defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1700
# define _LIBCPP_VERBOSE_TRAP(message) __builtin_verbose_trap(message)
# else
# define _LIBCPP_VERBOSE_TRAP(message) __builtin_verbose_trap("libc++", message)
# endif
# else
# define _LIBCPP_VERBOSE_TRAP(message) ((void)message, __builtin_trap())
# endif


_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___VERBOSE_TRAP
1 change: 1 addition & 0 deletions libcxx/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(LIBCXX_SOURCES
include/ryu/ryu.h
include/to_chars_floating_point.h
include/from_chars_floating_point.h
log_hardening_failure.cpp
memory.cpp
memory_resource.cpp
new_handler.cpp
Expand Down
49 changes: 49 additions & 0 deletions libcxx/src/log_hardening_failure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// 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>
extern "C" void android_set_abort_message(const char* msg);
#endif // __BIONIC__

#if defined(__APPLE__) && __has_include(<os/reason_private.h>)
# include <os/reason_private.h>
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_WEAK void __libcpp_log_hardening_failure(const char* message) noexcept {
// On Apple platforms, use the `os_fault_with_payload` OS function that simulates a crash.
#if defined(__APPLE__) && __has_include(<os/reason_private.h>)
os_fault_with_payload(
/*reason_namespace=*/OS_REASON_SECURITY,
/*reason_code=*/0,
/*payload=*/nullptr,
/*payload_size=*/0,
/*reason_string=*/message,
/*reason_flags=*/0);

#elif defined(__BIONIC__)
// Show error in tombstone.
android_set_abort_message(message);

// Show error in logcat.
openlog("libc++", 0, 0);
syslog(LOG_CRIT, "%s", message);
closelog();

#else
fprintf(stderr, "%s", message);
#endif
}

_LIBCPP_END_NAMESPACE_STD
Loading
Loading