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/config.h" 13 #if defined(LIBC_COPT_USE_C_ASSERT) || !defined(LIBC_FULL_BUILD) 14 15 // The build is configured to just use the public <assert.h> API 16 // for libc's internal assertions. 17 18 #include <assert.h> 19 20 #define LIBC_ASSERT(COND) assert(COND) 21 22 #else // Not LIBC_COPT_USE_C_ASSERT 23 24 #include "src/__support/OSUtil/exit.h" 25 #include "src/__support/OSUtil/io.h" 26 #include "src/__support/integer_to_string.h" 27 #include "src/__support/macros/attributes.h" // For LIBC_INLINE 28 #include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY 29 30 namespace LIBC_NAMESPACE_DECL { 31 32 // This is intended to be removed in a future patch to use a similar design to 33 // below, but it's necessary for the external assert. 34 LIBC_INLINE void report_assertion_failure(const char *assertion, 35 const char *filename, unsigned line, 36 const char *funcname) { 37 const IntegerToString<unsigned> line_buffer(line); 38 write_to_stderr(filename); 39 write_to_stderr(":"); 40 write_to_stderr(line_buffer.view()); 41 write_to_stderr(": Assertion failed: '"); 42 write_to_stderr(assertion); 43 write_to_stderr("' in function: '"); 44 write_to_stderr(funcname); 45 write_to_stderr("'\n"); 46 } 47 48 } // namespace LIBC_NAMESPACE_DECL 49 50 #ifdef LIBC_ASSERT 51 #error "Unexpected: LIBC_ASSERT macro already defined" 52 #endif 53 54 // The public "assert" macro calls abort on failure. Should it be same here? 55 // The libc internal assert can fire from anywhere inside the libc. So, to 56 // avoid potential chicken-and-egg problems, it is simple to do an exit 57 // on assertion failure instead of calling abort. We also don't want to use 58 // __builtin_trap as it could potentially be implemented using illegal 59 // instructions which can be very misleading when debugging. 60 #ifdef NDEBUG 61 #define LIBC_ASSERT(COND) \ 62 do { \ 63 } while (false) 64 #else 65 66 // Convert __LINE__ to a string using macros. The indirection is necessary 67 // because otherwise it will turn "__LINE__" into a string, not its value. The 68 // value is evaluated in the indirection step. 69 #define __LIBC_MACRO_TO_STR(x) #x 70 #define __LIBC_MACRO_TO_STR_INDIR(y) __LIBC_MACRO_TO_STR(y) 71 #define __LIBC_LINE_STR__ __LIBC_MACRO_TO_STR_INDIR(__LINE__) 72 73 #define LIBC_ASSERT(COND) \ 74 do { \ 75 if (LIBC_UNLIKELY(!(COND))) { \ 76 LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" __LIBC_LINE_STR__ \ 77 ": Assertion failed: '" #COND \ 78 "' in function: '"); \ 79 LIBC_NAMESPACE::write_to_stderr(__PRETTY_FUNCTION__); \ 80 LIBC_NAMESPACE::write_to_stderr("'\n"); \ 81 LIBC_NAMESPACE::internal::exit(0xFF); \ 82 } \ 83 } while (false) 84 #endif // NDEBUG 85 86 #endif // LIBC_COPT_USE_C_ASSERT 87 88 #endif // LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H 89