1//===-- Definition of a libc internal assert macro --------------*- C++ -*-===//
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#ifndef LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H
10#define LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H
11
12#include "src/__support/macros/attributes.h" // For LIBC_INLINE
13#include "src/__support/macros/config.h"
14#include "src/__support/macros/hardening.h"
15#include "src/__support/macros/macro-utils.h"
16#include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY
17#include "src/__support/macros/properties/os.h"
18
19#ifdef LIBC_FULL_BUILD
20#include "src/__support/OSUtil/exit.h"
21#include "src/__support/OSUtil/io.h"
22#include "src/__support/integer_to_string.h"
23#endif
24
25//===----------------------------------------------------------------------===//
26// LIBC_REQUIRE(COND, MSG) (always-on assert regardless of NDEBUG)
27//===----------------------------------------------------------------------===//
28#ifndef LIBC_FULL_BUILD
29#ifdef LIBC_TARGET_OS_IS_LINUX
30// __assert_fail is in Linux Standard Base (LSB), hence we should always be able
31// to use it here.
32#include <assert.h>
33#define LIBC_REQUIRE(COND, MSG) \
34 do { \
35 if (LIBC_UNLIKELY(!(COND))) \
36 __assert_fail(MSG, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
37 } while (false)
38#else
39// Fallback path will just trap: we cannot reliably do anything else.
40#define LIBC_REQUIRE(COND, MSG) \
41 do { \
42 if (LIBC_UNLIKELY(!(COND))) \
43 __builtin_trap(); \
44 } while (false)
45#endif // LIBC_TARGET_OS_IS_LINUX
46#else
47// FIXME: Calling abort on assertion is actually required by standards like LSB.
48// Calling exit also confuses the debugger as exiting will not trigger
49// debugger's stop-on-signal behavior by default. Currently, adding abort will
50// result in cyclic dependency.
51#define LIBC_REQUIRE(COND, MSG) \
52 do { \
53 if (LIBC_UNLIKELY(!(COND))) { \
54 LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" LLVM_LIBC_STRINGIFY( \
55 __LINE__) ": Assertion failed: '" MSG "' in function: '"); \
56 LIBC_NAMESPACE::write_to_stderr(__PRETTY_FUNCTION__); \
57 LIBC_NAMESPACE::write_to_stderr("'\n"); \
58 LIBC_NAMESPACE::internal::exit(0xFF); \
59 } \
60 } while (false)
61#endif // LIBC_FULL_BUILD
62
63//===----------------------------------------------------------------------===//
64// LIBC_ASSERT(COND) (NDEBUG guarded assertion)
65//===----------------------------------------------------------------------===//
66#if defined(LIBC_COPT_USE_C_ASSERT) || !defined(LIBC_FULL_BUILD)
67
68// The build is configured to just use the public <assert.h> API
69// for libc's internal assertions.
70#ifndef LIBC_ASSERT
71#include <assert.h>
72#define LIBC_ASSERT(COND) assert(COND)
73#endif // LIBC_ASSERT
74
75#else // Not LIBC_COPT_USE_C_ASSERT
76namespace LIBC_NAMESPACE_DECL {
77
78// This is intended to be removed in a future patch to use a similar design to
79// below, but it's necessary for the external assert.
80LIBC_INLINE void report_assertion_failure(const char *assertion,
81 const char *filename, unsigned line,
82 const char *funcname) {
83 const IntegerToString<unsigned> line_buffer(line);
84 write_to_stderr(filename);
85 write_to_stderr(":");
86 write_to_stderr(line_buffer.view());
87 write_to_stderr(": Assertion failed: '");
88 write_to_stderr(assertion);
89 write_to_stderr("' in function: '");
90 write_to_stderr(funcname);
91 write_to_stderr("'\n");
92}
93
94} // namespace LIBC_NAMESPACE_DECL
95
96#ifdef LIBC_ASSERT
97#error "Unexpected: LIBC_ASSERT macro already defined"
98#endif
99
100#ifdef NDEBUG
101#define LIBC_ASSERT(COND) \
102 do { \
103 } while (false)
104#else
105// Forward to LIBC_REQUIRE with the condition stringified.
106#define LIBC_ASSERT(COND) LIBC_REQUIRE(COND, #COND)
107#endif // NDEBUG
108
109#endif // LIBC_COPT_USE_C_ASSERT
110
111//===----------------------------------------------------------------------===//
112// Hardening runtime check
113//===----------------------------------------------------------------------===//
114
115#if LIBC_COPT_HARDENING_MODE == LIBC_HARDENING_MODE_NONE
116#define LIBC_HEAP_INTEGRITY_CHECK(COND, MSG) ((void)0)
117#elif LIBC_COPT_HARDENING_MODE == LIBC_HARDENING_MODE_FAST
118#define LIBC_HEAP_INTEGRITY_CHECK(COND, MSG) ((void)0)
119#elif LIBC_COPT_HARDENING_MODE == LIBC_HARDENING_MODE_EXTENSIVE
120#define LIBC_HEAP_INTEGRITY_CHECK(COND, MSG) LIBC_REQUIRE(COND, MSG)
121#elif LIBC_COPT_HARDENING_MODE == LIBC_HARDENING_MODE_DEBUG
122#define LIBC_HEAP_INTEGRITY_CHECK(COND, MSG) LIBC_REQUIRE(COND, MSG)
123#else
124#error "Unsupported hardening mode"
125#endif
126#endif // LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H
127