1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkAssert_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkAssert_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAPI.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAttributes.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h" // IWYU pragma: keep
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
16*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
17*c8dee2aaSAndroid Build Coastguard Worker
18*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__) && defined(__has_attribute)
19*c8dee2aaSAndroid Build Coastguard Worker #if __has_attribute(likely)
20*c8dee2aaSAndroid Build Coastguard Worker #define SK_LIKELY [[likely]]
21*c8dee2aaSAndroid Build Coastguard Worker #define SK_UNLIKELY [[unlikely]]
22*c8dee2aaSAndroid Build Coastguard Worker #else
23*c8dee2aaSAndroid Build Coastguard Worker #define SK_LIKELY
24*c8dee2aaSAndroid Build Coastguard Worker #define SK_UNLIKELY
25*c8dee2aaSAndroid Build Coastguard Worker #endif
26*c8dee2aaSAndroid Build Coastguard Worker #else
27*c8dee2aaSAndroid Build Coastguard Worker #define SK_LIKELY
28*c8dee2aaSAndroid Build Coastguard Worker #define SK_UNLIKELY
29*c8dee2aaSAndroid Build Coastguard Worker #endif
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker // c++23 will give us [[assume]] -- until then we're stuck with various other options:
32*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__)
33*c8dee2aaSAndroid Build Coastguard Worker #define SK_ASSUME(cond) __builtin_assume(cond)
34*c8dee2aaSAndroid Build Coastguard Worker #elif defined(__GNUC__)
35*c8dee2aaSAndroid Build Coastguard Worker #if __GNUC__ >= 13
36*c8dee2aaSAndroid Build Coastguard Worker #define SK_ASSUME(cond) __attribute__((assume(cond)))
37*c8dee2aaSAndroid Build Coastguard Worker #else
38*c8dee2aaSAndroid Build Coastguard Worker // NOTE: This implementation could actually evaluate `cond`, which is not desirable.
39*c8dee2aaSAndroid Build Coastguard Worker #define SK_ASSUME(cond) ((cond) ? (void)0 : __builtin_unreachable())
40*c8dee2aaSAndroid Build Coastguard Worker #endif
41*c8dee2aaSAndroid Build Coastguard Worker #elif defined(_MSC_VER)
42*c8dee2aaSAndroid Build Coastguard Worker #define SK_ASSUME(cond) __assume(cond)
43*c8dee2aaSAndroid Build Coastguard Worker #else
44*c8dee2aaSAndroid Build Coastguard Worker #define SK_ASSUME(cond) ((void)0)
45*c8dee2aaSAndroid Build Coastguard Worker #endif
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker /** Called internally if we hit an unrecoverable error.
48*c8dee2aaSAndroid Build Coastguard Worker The platform implementation must not return, but should either throw
49*c8dee2aaSAndroid Build Coastguard Worker an exception or otherwise exit.
50*c8dee2aaSAndroid Build Coastguard Worker */
51*c8dee2aaSAndroid Build Coastguard Worker [[noreturn]] SK_API extern void sk_abort_no_print(void);
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_GOOGLE3)
54*c8dee2aaSAndroid Build Coastguard Worker void SkDebugfForDumpStackTrace(const char* data, void* unused);
55*c8dee2aaSAndroid Build Coastguard Worker namespace base {
56*c8dee2aaSAndroid Build Coastguard Worker void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg);
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker # define SK_DUMP_GOOGLE3_STACK() ::base::DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr)
59*c8dee2aaSAndroid Build Coastguard Worker #else
60*c8dee2aaSAndroid Build Coastguard Worker # define SK_DUMP_GOOGLE3_STACK()
61*c8dee2aaSAndroid Build Coastguard Worker #endif
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_ABORT)
64*c8dee2aaSAndroid Build Coastguard Worker # if defined(SK_BUILD_FOR_WIN)
65*c8dee2aaSAndroid Build Coastguard Worker // This style lets Visual Studio follow errors back to the source file.
66*c8dee2aaSAndroid Build Coastguard Worker # define SK_DUMP_LINE_FORMAT "%s(%d)"
67*c8dee2aaSAndroid Build Coastguard Worker # else
68*c8dee2aaSAndroid Build Coastguard Worker # define SK_DUMP_LINE_FORMAT "%s:%d"
69*c8dee2aaSAndroid Build Coastguard Worker # endif
70*c8dee2aaSAndroid Build Coastguard Worker # define SK_ABORT(message, ...) \
71*c8dee2aaSAndroid Build Coastguard Worker do { \
72*c8dee2aaSAndroid Build Coastguard Worker SkDebugf(SK_DUMP_LINE_FORMAT ": fatal error: \"" message "\"\n", \
73*c8dee2aaSAndroid Build Coastguard Worker __FILE__, __LINE__, ##__VA_ARGS__); \
74*c8dee2aaSAndroid Build Coastguard Worker SK_DUMP_GOOGLE3_STACK(); \
75*c8dee2aaSAndroid Build Coastguard Worker sk_abort_no_print(); \
76*c8dee2aaSAndroid Build Coastguard Worker } while (false)
77*c8dee2aaSAndroid Build Coastguard Worker #endif
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as standalone assertion expressions, e.g.
80*c8dee2aaSAndroid Build Coastguard Worker // uint32_t foo(int x) {
81*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(x > 4);
82*c8dee2aaSAndroid Build Coastguard Worker // return x - 4;
83*c8dee2aaSAndroid Build Coastguard Worker // }
84*c8dee2aaSAndroid Build Coastguard Worker // and are also written to be compatible with constexpr functions:
85*c8dee2aaSAndroid Build Coastguard Worker // constexpr uint32_t foo(int x) {
86*c8dee2aaSAndroid Build Coastguard Worker // return SkASSERT(x > 4),
87*c8dee2aaSAndroid Build Coastguard Worker // x - 4;
88*c8dee2aaSAndroid Build Coastguard Worker // }
89*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__)
90*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERT_RELEASE(cond) \
91*c8dee2aaSAndroid Build Coastguard Worker static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1) \
92*c8dee2aaSAndroid Build Coastguard Worker ? static_cast<void>(0) \
93*c8dee2aaSAndroid Build Coastguard Worker : []{ SK_ABORT("check(%s)", #cond); }() )
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERTF_RELEASE(cond, fmt, ...) \
96*c8dee2aaSAndroid Build Coastguard Worker static_cast<void>( __builtin_expect(static_cast<bool>(cond), 1) \
97*c8dee2aaSAndroid Build Coastguard Worker ? static_cast<void>(0) \
98*c8dee2aaSAndroid Build Coastguard Worker : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
99*c8dee2aaSAndroid Build Coastguard Worker #else
100*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERT_RELEASE(cond) \
101*c8dee2aaSAndroid Build Coastguard Worker static_cast<void>( (cond) ? static_cast<void>(0) : []{ SK_ABORT("check(%s)", #cond); }() )
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERTF_RELEASE(cond, fmt, ...) \
104*c8dee2aaSAndroid Build Coastguard Worker static_cast<void>( (cond) \
105*c8dee2aaSAndroid Build Coastguard Worker ? static_cast<void>(0) \
106*c8dee2aaSAndroid Build Coastguard Worker : [&]{ SK_ABORT("assertf(%s): " fmt, #cond, ##__VA_ARGS__); }() )
107*c8dee2aaSAndroid Build Coastguard Worker #endif
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
110*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERT(cond) SkASSERT_RELEASE(cond)
111*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERTF(cond, fmt, ...) SkASSERTF_RELEASE(cond, fmt, ##__VA_ARGS__)
112*c8dee2aaSAndroid Build Coastguard Worker #define SkDEBUGFAIL(message) SK_ABORT("%s", message)
113*c8dee2aaSAndroid Build Coastguard Worker #define SkDEBUGFAILF(fmt, ...) SK_ABORT(fmt, ##__VA_ARGS__)
114*c8dee2aaSAndroid Build Coastguard Worker #define SkAssertResult(cond) SkASSERT(cond)
115*c8dee2aaSAndroid Build Coastguard Worker #else
116*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERT(cond) static_cast<void>(0)
117*c8dee2aaSAndroid Build Coastguard Worker #define SkASSERTF(cond, fmt, ...) static_cast<void>(0)
118*c8dee2aaSAndroid Build Coastguard Worker #define SkDEBUGFAIL(message)
119*c8dee2aaSAndroid Build Coastguard Worker #define SkDEBUGFAILF(fmt, ...)
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker // unlike SkASSERT, this macro executes its condition in the non-debug build.
122*c8dee2aaSAndroid Build Coastguard Worker // The if is present so that this can be used with functions marked [[nodiscard]].
123*c8dee2aaSAndroid Build Coastguard Worker #define SkAssertResult(cond) if (cond) {} do {} while(false)
124*c8dee2aaSAndroid Build Coastguard Worker #endif
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SkUNREACHABLE)
127*c8dee2aaSAndroid Build Coastguard Worker # if defined(_MSC_VER) && !defined(__clang__)
128*c8dee2aaSAndroid Build Coastguard Worker # include <intrin.h>
129*c8dee2aaSAndroid Build Coastguard Worker # define FAST_FAIL_INVALID_ARG 5
130*c8dee2aaSAndroid Build Coastguard Worker // See https://developercommunity.visualstudio.com/content/problem/1128631/code-flow-doesnt-see-noreturn-with-extern-c.html
131*c8dee2aaSAndroid Build Coastguard Worker // for why this is wrapped. Hopefully removable after msvc++ 19.27 is no longer supported.
sk_fast_fail()132*c8dee2aaSAndroid Build Coastguard Worker [[noreturn]] static inline void sk_fast_fail() { __fastfail(FAST_FAIL_INVALID_ARG); }
133*c8dee2aaSAndroid Build Coastguard Worker # define SkUNREACHABLE sk_fast_fail()
134*c8dee2aaSAndroid Build Coastguard Worker # else
135*c8dee2aaSAndroid Build Coastguard Worker # define SkUNREACHABLE __builtin_trap()
136*c8dee2aaSAndroid Build Coastguard Worker # endif
137*c8dee2aaSAndroid Build Coastguard Worker #endif
138*c8dee2aaSAndroid Build Coastguard Worker
sk_print_index_out_of_bounds(size_t i,size_t size)139*c8dee2aaSAndroid Build Coastguard Worker [[noreturn]] SK_API inline void sk_print_index_out_of_bounds(size_t i, size_t size) {
140*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Index (%zu) out of bounds for size %zu.\n", i, size);
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker
sk_collection_check_bounds(T i,T size)143*c8dee2aaSAndroid Build Coastguard Worker template <typename T> SK_API inline T sk_collection_check_bounds(T i, T size) {
144*c8dee2aaSAndroid Build Coastguard Worker if (0 <= i && i < size) SK_LIKELY {
145*c8dee2aaSAndroid Build Coastguard Worker return i;
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker SK_UNLIKELY {
149*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
150*c8dee2aaSAndroid Build Coastguard Worker sk_print_index_out_of_bounds(static_cast<size_t>(i), static_cast<size_t>(size));
151*c8dee2aaSAndroid Build Coastguard Worker #else
152*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
153*c8dee2aaSAndroid Build Coastguard Worker #endif
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker
sk_print_length_too_big(size_t i,size_t size)157*c8dee2aaSAndroid Build Coastguard Worker [[noreturn]] SK_API inline void sk_print_length_too_big(size_t i, size_t size) {
158*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Length (%zu) is too big for size %zu.\n", i, size);
159*c8dee2aaSAndroid Build Coastguard Worker }
160*c8dee2aaSAndroid Build Coastguard Worker
sk_collection_check_length(T i,T size)161*c8dee2aaSAndroid Build Coastguard Worker template <typename T> SK_API inline T sk_collection_check_length(T i, T size) {
162*c8dee2aaSAndroid Build Coastguard Worker if (0 <= i && i <= size) SK_LIKELY {
163*c8dee2aaSAndroid Build Coastguard Worker return i;
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker
166*c8dee2aaSAndroid Build Coastguard Worker SK_UNLIKELY {
167*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
168*c8dee2aaSAndroid Build Coastguard Worker sk_print_length_too_big(static_cast<size_t>(i), static_cast<size_t>(size));
169*c8dee2aaSAndroid Build Coastguard Worker #else
170*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
171*c8dee2aaSAndroid Build Coastguard Worker #endif
172*c8dee2aaSAndroid Build Coastguard Worker }
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker
sk_collection_not_empty(bool empty)175*c8dee2aaSAndroid Build Coastguard Worker SK_API inline void sk_collection_not_empty(bool empty) {
176*c8dee2aaSAndroid Build Coastguard Worker if (empty) SK_UNLIKELY {
177*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
178*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Collection is empty.\n");
179*c8dee2aaSAndroid Build Coastguard Worker #else
180*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
181*c8dee2aaSAndroid Build Coastguard Worker #endif
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker
sk_print_size_too_big(size_t size,size_t maxSize)185*c8dee2aaSAndroid Build Coastguard Worker [[noreturn]] SK_API inline void sk_print_size_too_big(size_t size, size_t maxSize) {
186*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Size (%zu) can't be represented in bytes. Max size is %zu.\n", size, maxSize);
187*c8dee2aaSAndroid Build Coastguard Worker }
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
check_size_bytes_too_big(size_t size)190*c8dee2aaSAndroid Build Coastguard Worker SK_ALWAYS_INLINE size_t check_size_bytes_too_big(size_t size) {
191*c8dee2aaSAndroid Build Coastguard Worker const size_t kMaxSize = std::numeric_limits<size_t>::max() / sizeof(T);
192*c8dee2aaSAndroid Build Coastguard Worker if (size > kMaxSize) {
193*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
194*c8dee2aaSAndroid Build Coastguard Worker sk_print_size_too_big(size, kMaxSize);
195*c8dee2aaSAndroid Build Coastguard Worker #else
196*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
197*c8dee2aaSAndroid Build Coastguard Worker #endif
198*c8dee2aaSAndroid Build Coastguard Worker }
199*c8dee2aaSAndroid Build Coastguard Worker return size;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker
202*c8dee2aaSAndroid Build Coastguard Worker #endif // SkAssert_DEFINED
203