1#ifndef INTERNAL_SANITIZERS_H
2#define INTERNAL_SANITIZERS_H
11#include "ruby/internal/config.h"
12#include "internal/compilers.h"
14#ifdef HAVE_VALGRIND_MEMCHECK_H
15# include <valgrind/memcheck.h>
18#ifdef HAVE_SANITIZER_ASAN_INTERFACE_H
19# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
20# define RUBY_ASAN_ENABLED
21# include <sanitizer/asan_interface.h>
25#ifdef HAVE_SANITIZER_MSAN_INTERFACE_H
26# if __has_feature(memory_sanitizer)
27# define RUBY_MSAN_ENABLED
28# include <sanitizer/msan_interface.h>
36#elif defined(RUBY_ASAN_ENABLED) && defined(RUBY_MSAN_ENABLED)
37# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
38 __attribute__((__no_sanitize__("memory, address"), __noinline__)) x
39#elif defined(RUBY_ASAN_ENABLED)
40# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
41 __attribute__((__no_sanitize__("address"), __noinline__)) x
42#elif defined(RUBY_MSAN_ENABLED)
43 # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
44 __attribute__((__no_sanitize__("memory"), __noinline__)) x
45#elif defined(NO_SANITIZE_ADDRESS)
46# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
47 NO_SANITIZE_ADDRESS(NOINLINE(x))
48#elif defined(NO_ADDRESS_SAFETY_ANALYSIS)
49# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
50 NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x))
52# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x
55#if defined(NO_SANITIZE) && RBIMPL_COMPILER_IS(GCC)
57# include "internal/warnings.h"
59# define NO_SANITIZE(x, y) \
60 COMPILER_WARNING_PUSH \
61 COMPILER_WARNING_IGNORED(-Wattributes) \
62 __attribute__((__no_sanitize__(x))) y; \
63 COMPILER_WARNING_POP \
68# define NO_SANITIZE(x, y) y
71#ifndef RUBY_ASAN_ENABLED
72# define __asan_poison_memory_region(x, y)
73# define __asan_unpoison_memory_region(x, y)
74# define __asan_region_is_poisoned(x, y) 0
75# define __asan_get_current_fake_stack() NULL
76# define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL
79#ifndef RUBY_MSAN_ENABLED
80# define __msan_allocated_memory(x, y) ((void)(x), (void)(y))
81# define __msan_poison(x, y) ((void)(x), (void)(y))
82# define __msan_unpoison(x, y) ((void)(x), (void)(y))
83# define __msan_unpoison_string(x) ((void)(x))
86#ifdef VALGRIND_MAKE_READABLE
87# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
90#ifdef VALGRIND_MAKE_WRITABLE
91# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
94#ifndef VALGRIND_MAKE_MEM_DEFINED
95# define VALGRIND_MAKE_MEM_DEFINED(p, n) 0
98#ifndef VALGRIND_MAKE_MEM_UNDEFINED
99# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
116asan_poison_memory_region(
const volatile void *ptr,
size_t size)
118 __msan_poison(ptr, size);
119 __asan_poison_memory_region(ptr, size);
122#ifdef RUBY_ASAN_ENABLED
123#define asan_poison_object_if(ptr, obj) do { \
124 if (ptr) rb_asan_poison_object(obj); \
127#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
130#ifdef RUBY_ASAN_ENABLED
131RUBY_SYMBOL_EXPORT_BEGIN
137void rb_asan_poison_object(
VALUE obj);
146void *rb_asan_poisoned_object_p(
VALUE obj);
154void rb_asan_unpoison_object(
VALUE obj,
bool newobj_p);
156RUBY_SYMBOL_EXPORT_END
158# define rb_asan_poison_object(obj) ((void)obj)
159# define rb_asan_poisoned_object_p(obj) ((void)obj, NULL)
160# define rb_asan_unpoison_object(obj, newobj_p) ((void)obj, (void)newobj_p)
179asan_unpoison_memory_region(
const volatile void *ptr,
size_t size,
bool malloc_p)
181 __asan_unpoison_memory_region(ptr, size);
183 __msan_allocated_memory(ptr, size);
186 __msan_unpoison(ptr, size);
191asan_unpoison_object_temporary(
VALUE obj)
193 void *ptr = rb_asan_poisoned_object_p(obj);
194 rb_asan_unpoison_object(obj,
false);
199asan_poison_object_restore(
VALUE obj,
void *ptr)
202 rb_asan_poison_object(obj);
207#define asan_unpoisoning_object(obj) \
208 for (void *poisoned = asan_unpoison_object_temporary(obj), \
209 *unpoisoning = &poisoned; \
211 unpoisoning = asan_poison_object_restore(obj, poisoned))
215asan_unpoison_memory_region_temporary(
void *ptr,
size_t len)
217 void *poisoned_ptr = __asan_region_is_poisoned(ptr,
len);
218 asan_unpoison_memory_region(ptr,
len,
false);
223asan_poison_memory_region_restore(
void *ptr,
size_t len,
void *poisoned_ptr)
226 asan_poison_memory_region(ptr,
len);
231#define asan_unpoisoning_memory_region(ptr, len) \
232 for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
233 *unpoisoning = &poisoned; \
235 unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
253asan_get_real_stack_addr(
void* slot)
256 addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
257 return addr ? addr : slot;
266asan_get_thread_fake_stack_handle(
void)
268 return __asan_get_current_fake_stack();
292asan_get_fake_stack_extents(
void *thread_fake_stack_handle,
VALUE slot,
293 void *machine_stack_start,
void *machine_stack_end,
294 void **fake_stack_start_out,
void **fake_stack_end_out)
298#ifdef RUBY_ASAN_ENABLED
299 void *fake_frame_start;
300 void *fake_frame_end;
301 void *real_stack_frame = __asan_addr_is_in_fake_stack(
302 thread_fake_stack_handle, (
void *)slot, &fake_frame_start, &fake_frame_end
304 if (real_stack_frame) {
306#if STACK_GROW_DIRECTION < 0
307 in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end;
309 in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end;
312 *fake_stack_start_out = fake_frame_start;
313 *fake_stack_end_out = fake_frame_end;
318 *fake_stack_start_out = 0;
319 *fake_stack_end_out = 0;
323extern const char ruby_asan_default_options[];
325#ifdef RUBY_ASAN_ENABLED
329# undef RUBY__ASAN_DEFAULT_OPTIONS
330# define RUBY__ASAN_DEFAULT_OPTIONS \
331 RBIMPL_SYMBOL_EXPORT_BEGIN() \
332 const char * __asan_default_options(void) {return ruby_asan_default_options;} \
333 RBIMPL_SYMBOL_EXPORT_END()
int len
Length of the buffer.
uintptr_t VALUE
Type that represents a Ruby object.