1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef RTC_BASE_SANITIZER_H_
12 #define RTC_BASE_SANITIZER_H_
13
14 #include <stddef.h> // For size_t.
15
16 #ifdef __cplusplus
17 #include "absl/meta/type_traits.h"
18 #endif
19
20 #if defined(__has_feature)
21 #if __has_feature(address_sanitizer)
22 #define RTC_HAS_ASAN 1
23 #endif
24 #if __has_feature(memory_sanitizer)
25 #define RTC_HAS_MSAN 1
26 #endif
27 #endif
28 #ifndef RTC_HAS_ASAN
29 #define RTC_HAS_ASAN 0
30 #endif
31 #ifndef RTC_HAS_MSAN
32 #define RTC_HAS_MSAN 0
33 #endif
34
35 #if RTC_HAS_ASAN
36 #include <sanitizer/asan_interface.h>
37 #endif
38 #if RTC_HAS_MSAN
39 #include <sanitizer/msan_interface.h>
40 #endif
41
42 #ifdef __has_attribute
43 #if __has_attribute(no_sanitize)
44 #define RTC_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
45 #endif
46 #endif
47 #ifndef RTC_NO_SANITIZE
48 #define RTC_NO_SANITIZE(what)
49 #endif
50
51 // Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
52 // as being unaddressable, so that reads and writes are not allowed. ASan may
53 // narrow the range to the nearest alignment boundaries.
rtc_AsanPoison(const volatile void * ptr,size_t element_size,size_t num_elements)54 static inline void rtc_AsanPoison(const volatile void* ptr,
55 size_t element_size,
56 size_t num_elements) {
57 #if RTC_HAS_ASAN
58 ASAN_POISON_MEMORY_REGION(ptr, element_size * num_elements);
59 #endif
60 }
61
62 // Ask ASan to mark the memory range [ptr, ptr + element_size * num_elements)
63 // as being addressable, so that reads and writes are allowed. ASan may widen
64 // the range to the nearest alignment boundaries.
rtc_AsanUnpoison(const volatile void * ptr,size_t element_size,size_t num_elements)65 static inline void rtc_AsanUnpoison(const volatile void* ptr,
66 size_t element_size,
67 size_t num_elements) {
68 #if RTC_HAS_ASAN
69 ASAN_UNPOISON_MEMORY_REGION(ptr, element_size * num_elements);
70 #endif
71 }
72
73 // Ask MSan to mark the memory range [ptr, ptr + element_size * num_elements)
74 // as being uninitialized.
rtc_MsanMarkUninitialized(const volatile void * ptr,size_t element_size,size_t num_elements)75 static inline void rtc_MsanMarkUninitialized(const volatile void* ptr,
76 size_t element_size,
77 size_t num_elements) {
78 #if RTC_HAS_MSAN
79 __msan_poison(ptr, element_size * num_elements);
80 #endif
81 }
82
83 // Force an MSan check (if any bits in the memory range [ptr, ptr +
84 // element_size * num_elements) are uninitialized the call will crash with an
85 // MSan report).
rtc_MsanCheckInitialized(const volatile void * ptr,size_t element_size,size_t num_elements)86 static inline void rtc_MsanCheckInitialized(const volatile void* ptr,
87 size_t element_size,
88 size_t num_elements) {
89 #if RTC_HAS_MSAN
90 __msan_check_mem_is_initialized(ptr, element_size * num_elements);
91 #endif
92 }
93
94 #ifdef __cplusplus
95
96 namespace rtc {
97 namespace sanitizer_impl {
98
99 template <typename T>
IsTriviallyCopyable()100 constexpr bool IsTriviallyCopyable() {
101 return static_cast<bool>(absl::is_trivially_copy_constructible<T>::value &&
102 (absl::is_trivially_copy_assignable<T>::value ||
103 !std::is_copy_assignable<T>::value) &&
104 absl::is_trivially_destructible<T>::value);
105 }
106
107 } // namespace sanitizer_impl
108
109 template <typename T>
AsanPoison(const T & mem)110 inline void AsanPoison(const T& mem) {
111 rtc_AsanPoison(mem.data(), sizeof(mem.data()[0]), mem.size());
112 }
113
114 template <typename T>
AsanUnpoison(const T & mem)115 inline void AsanUnpoison(const T& mem) {
116 rtc_AsanUnpoison(mem.data(), sizeof(mem.data()[0]), mem.size());
117 }
118
119 template <typename T>
MsanMarkUninitialized(const T & mem)120 inline void MsanMarkUninitialized(const T& mem) {
121 rtc_MsanMarkUninitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
122 }
123
124 template <typename T>
MsanUninitialized(T t)125 inline T MsanUninitialized(T t) {
126 #if RTC_HAS_MSAN
127 // TODO(bugs.webrtc.org/8762): Switch to std::is_trivially_copyable when it
128 // becomes available in downstream projects.
129 static_assert(sanitizer_impl::IsTriviallyCopyable<T>(), "");
130 #endif
131 rtc_MsanMarkUninitialized(&t, sizeof(T), 1);
132 return t;
133 }
134
135 template <typename T>
MsanCheckInitialized(const T & mem)136 inline void MsanCheckInitialized(const T& mem) {
137 rtc_MsanCheckInitialized(mem.data(), sizeof(mem.data()[0]), mem.size());
138 }
139
140 } // namespace rtc
141
142 #endif // __cplusplus
143
144 #endif // RTC_BASE_SANITIZER_H_
145