Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Sanitizer.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Debug_Sanitizer_h_
5#define _Stroika_Foundation_Debug_Sanitizer_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#if __has_include(<sanitizer/asan_interface.h>)
10#include <sanitizer/asan_interface.h>
11#endif
12#if __has_include(<sanitizer/lsan_interface.h>)
13#include <sanitizer/lsan_interface.h>
14#endif
15#if __has_include(<sanitizer/tsan_interface.h>)
16#include <sanitizer/tsan_interface.h>
17#endif
18
19#if qCompilerAndStdLib_undefined_behavior_macro_Buggy
20extern "C" void __attribute__ ((weak)) __ubsan_handle_builtin_unreachable ();
21#endif
22
23/**
24 * \file
25 *
26 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
27 *
28 */
29
30#if defined(__cplusplus)
31namespace Stroika::Foundation::Debug {
32
33 /**
34 * Detect if Address Sanitizer is enabled in this compilation.
35 *
36 * Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer
37 *
38 * \note this is defined as a macro, since sometimes its very hard to use constexpr to disable bunches of code
39 * BUT - use Debug::kBuiltWithAddressSanitizer in preference to this where you can.
40 */
41#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer)
42#if defined(__SANITIZE_ADDRESS__)
43#define Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer 1
44#endif
45#endif
46#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer)
47#if defined(__has_feature)
48// @ see https://clang.llvm.org/docs/AddressSanitizer.html#conditional-compilation-with-has-feature-address-sanitizer
49#define Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer __has_feature (address_sanitizer)
50#endif
51#endif
52#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer)
53#define Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer 0
54#endif
55
56 /**
57 * \brief kBuiltWithAddressSanitizer can be checked in compiled code to see if the address sanitizer
58 * support is compiled into this executable
59 */
60 constexpr bool kBuiltWithAddressSanitizer = Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer;
61
62 /*
63 * Macro: Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
64 *
65 * \par Example Usage
66 * \code
67 * #if qCompilerAndStdLib_arm_asan_FaultStackUseAfterScope_Buggy
68 * Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
69 * #endif
70 * void Debug::Private_::Emitter::DoEmit_ (const wchar_t* p, const wchar_t* e) noexcept
71 * \endcode
72 *
73 * \par Example Usage
74 * \code
75 * // OLD EXAMPLE - NOT SURE THIS SYNTAX WORKS - MAYBE HAS TO GO BEFORE [] not after function()??
76 * ToObjectMapperType<CLASS> toObjectMapper = [fields, preflightBeforeToObject] (const ObjectVariantMapper& mapper, const VariantValue& d, CLASS* intoObjOfTypeT)
77 * Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
78 * -> void {...}
79 * \endcode
80 */
81#if Stroika_Foundation_Debug_Sanitizer_HAS_AddressSanitizer
82#if defined(__clang__)
83 // using [[gnu::no_sanitize_undefined]] syntax on clang++-10 on lambdas produces warning of no_sanitize_address undefined but this seems to work?
84#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__ ((no_sanitize_address))
85#elif defined(__GNUC__)
86#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS [[gnu::no_sanitize_address]]
87#elif defined(_MSC_VER)
88#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec (no_sanitize_address)
89#endif
90#endif
91#if !defined(Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS)
92#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_ADDRESS
93#endif
94
95 /**
96 * Detect if Thread Sanitizer is enabled in this compilation.
97 *
98 * Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer
99 *
100 * \note this is defined as a macro, since sometimes its very hard to use constexpr to disable bunchs of code
101 * BUT - use Debug::kBuiltWithThreadSanitizer in preference to this where you can.
102 */
103#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer)
104#if defined(__SANITIZE_THREAD__)
105#define Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer 1
106#endif
107#endif
108#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer)
109// see https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer
110#if defined(__has_feature)
111#define Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer __has_feature (thread_sanitizer)
112#endif
113#endif
114#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer)
115#define Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer 0
116#endif
117
118 /**
119 * \brief kBuiltWithThreadSanitizer can be checked in compiled code to see if the thread sanitizer
120 * support is compiled into this executable
121 */
122 constexpr bool kBuiltWithThreadSanitizer = Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer;
123
124 /**
125 * Macro: Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_THREAD
126 *
127 * \par Example Usage
128 * \code
129 * #if qCompiler_ThreadSantizer_SPR_717_Buggy
130 * Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_THREAD
131 * #endif
132 * static void DoIt (void* ignored) {...}
133 * \endcode
134 */
135#if Stroika_Foundation_Debug_Sanitizer_HAS_ThreadSanitizer
136#if defined(__clang__) || defined(__GNUC__)
137#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_THREAD [[gnu::no_sanitize_thread]]
138#endif
139#endif
140#if !defined(Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_THREAD)
141#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_THREAD
142#endif
143
144 /**
145 * Detect if Undefined Behavior Sanitizer is enabled in this compilation.
146 *
147 * Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer
148 *
149 * \note this is defined as a macro, since sometimes its very hard to use constexpr to disable bunchs of code
150 * BUT - use Debug::kBuiltWithUndefinedBehaviorSanitizer in preference to this where you can.
151 *
152 * \note sure this works with GCC - https://github.com/google/sanitizers/issues/765
153 */
154#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer)
155#if defined(__SANITIZE_UNDEFINED__)
156#define Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer 1
157#endif
158#endif
159#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer)
160#if defined(__has_feature)
161 // not documented - https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html - not sure if ever works
162 // appears to work on apple XCode 11 clang, at least
163#define Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer __has_feature (undefined_behavior_sanitizer)
164#endif
165#endif
166#if !defined(Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer)
167#define Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer 0
168#endif
169
170/**
171 * \brief kBuiltWithUndefinedBehaviorSanitizer can be checked in compiled code to see if the undfined behavior sanitizer
172 * support is compiled into this executable
173 *
174 * \note WARNING: This incorrectly reports false on GCC builds, at least up to gcc 12, it appears.
175 */
176#if qCompilerAndStdLib_undefined_behavior_macro_Buggy
177 namespace Private_ {
178 inline bool isUndefinedBehavorSanitizerRunning_ ()
179 {
180 // trick from https://stackoverflow.com/questions/39371798/how-can-i-determine-if-ubsan-has-been-compiled-in-using-clang-or-gcc
181 return &__ubsan_handle_builtin_unreachable;
182 }
183 }
184 inline const bool kBuiltWithUndefinedBehaviorSanitizer = Private_::isUndefinedBehavorSanitizerRunning_ ();
185#else
186 constexpr bool kBuiltWithUndefinedBehaviorSanitizer = Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer;
187#endif
188
189 /**
190 * Macro: Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
191 *
192 * \par Example Usage
193 * \code
194 * #if qSomeBugFlag
195 * Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
196 * #endif
197 * Interface GetInterfaces_POSIX_mkInterface_ (int sd, const ifreq* i) {...}
198 * \endcode
199 */
200#if Stroika_Foundation_Debug_Sanitizer_HAS_UndefinedBehaviorSanitizer
201#if defined(__clang__)
202#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize ("undefined")))
203#elif defined(__GNUC__)
204#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED [[gnu::no_sanitize_undefined]]
205// NO UBSAN YET ON VS
206#endif
207#endif
208#if !defined(Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED)
209#define Stroika_Foundation_Debug_ATTRIBUTE_NO_SANITIZE_UNDEFINED
210#endif
211
212}
213#endif
214
215/*
216 ********************************************************************************
217 ***************************** Implementation Details ***************************
218 ********************************************************************************
219 */
220#include "Sanitizer.inl"
221
222#endif /*_Stroika_Foundation_Debug_Sanitizer_h_*/