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