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>
32#ifdef HAVE_SANITIZER_TSAN_INTERFACE_H
33# if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
34# define RUBY_TSAN_ENABLED
35# include <sanitizer/tsan_interface.h>
43#elif defined(RUBY_ASAN_ENABLED) && defined(RUBY_MSAN_ENABLED)
44# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
45 __attribute__((__no_sanitize__("memory, address"), __noinline__)) x
46#elif defined(RUBY_ASAN_ENABLED)
47# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
48 __attribute__((__no_sanitize__("address"), __noinline__)) x
49#elif defined(RUBY_MSAN_ENABLED)
50 # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
51 __attribute__((__no_sanitize__("memory"), __noinline__)) x
52#elif defined(RUBY_TSAN_ENABLED)
53# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
54 __attribute__((__no_sanitize__("thread"), __noinline__)) x
55#elif defined(NO_SANITIZE_ADDRESS)
56# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
57 NO_SANITIZE_ADDRESS(NOINLINE(x))
58#elif defined(NO_ADDRESS_SAFETY_ANALYSIS)
59# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
60 NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x))
62# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x
65#if defined(NO_SANITIZE) && RBIMPL_COMPILER_IS(GCC)
67# include "internal/warnings.h"
69# define NO_SANITIZE(x, y) \
70 COMPILER_WARNING_PUSH \
71 COMPILER_WARNING_IGNORED(-Wattributes) \
72 __attribute__((__no_sanitize__(x))) y; \
73 COMPILER_WARNING_POP \
78# define NO_SANITIZE(x, y) y
81#ifndef RUBY_ASAN_ENABLED
82# define __asan_poison_memory_region(x, y)
83# define __asan_unpoison_memory_region(x, y)
84# define __asan_region_is_poisoned(x, y) 0
85# define __asan_get_current_fake_stack() NULL
86# define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL
89#ifndef RUBY_MSAN_ENABLED
90# define __msan_allocated_memory(x, y) ((void)(x), (void)(y))
91# define __msan_poison(x, y) ((void)(x), (void)(y))
92# define __msan_unpoison(x, y) ((void)(x), (void)(y))
93# define __msan_unpoison_string(x) ((void)(x))
96#ifdef VALGRIND_MAKE_READABLE
97# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
100#ifdef VALGRIND_MAKE_WRITABLE
101# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
104#ifndef VALGRIND_MAKE_MEM_DEFINED
105# define VALGRIND_MAKE_MEM_DEFINED(p, n) 0
108#ifndef VALGRIND_MAKE_MEM_UNDEFINED
109# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
126asan_poison_memory_region(
const volatile void *ptr,
size_t size)
128 __msan_poison(ptr, size);
129 __asan_poison_memory_region(ptr, size);
132#ifdef RUBY_ASAN_ENABLED
133#define asan_poison_object_if(ptr, obj) do { \
134 if (ptr) rb_asan_poison_object(obj); \
137#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
140#ifdef RUBY_ASAN_ENABLED
141RUBY_SYMBOL_EXPORT_BEGIN
147void rb_asan_poison_object(
VALUE obj);
156void *rb_asan_poisoned_object_p(
VALUE obj);
164void rb_asan_unpoison_object(
VALUE obj,
bool newobj_p);
166RUBY_SYMBOL_EXPORT_END
168# define rb_asan_poison_object(obj) ((void)obj)
169# define rb_asan_poisoned_object_p(obj) ((void)obj, NULL)
170# define rb_asan_unpoison_object(obj, newobj_p) ((void)obj, (void)newobj_p)
189asan_unpoison_memory_region(
const volatile void *ptr,
size_t size,
bool malloc_p)
191 __asan_unpoison_memory_region(ptr, size);
193 __msan_allocated_memory(ptr, size);
196 __msan_unpoison(ptr, size);
201asan_unpoison_object_temporary(
VALUE obj)
203 void *ptr = rb_asan_poisoned_object_p(obj);
204 rb_asan_unpoison_object(obj,
false);
209asan_poison_object_restore(
VALUE obj,
void *ptr)
212 rb_asan_poison_object(obj);
217#define asan_unpoisoning_object(obj) \
218 for (void *poisoned = asan_unpoison_object_temporary(obj), \
219 *unpoisoning = &poisoned; \
221 unpoisoning = asan_poison_object_restore(obj, poisoned))
225asan_unpoison_memory_region_temporary(
void *ptr,
size_t len)
227 void *poisoned_ptr = __asan_region_is_poisoned(ptr,
len);
228 asan_unpoison_memory_region(ptr,
len,
false);
233asan_poison_memory_region_restore(
void *ptr,
size_t len,
void *poisoned_ptr)
236 asan_poison_memory_region(ptr,
len);
241#define asan_unpoisoning_memory_region(ptr, len) \
242 for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
243 *unpoisoning = &poisoned; \
245 unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
263asan_get_real_stack_addr(
void* slot)
266 addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
267 return addr ? addr : slot;
276asan_get_thread_fake_stack_handle(
void)
278 return __asan_get_current_fake_stack();
302asan_get_fake_stack_extents(
void *thread_fake_stack_handle,
VALUE slot,
303 void *machine_stack_start,
void *machine_stack_end,
304 void **fake_stack_start_out,
void **fake_stack_end_out)
308#ifdef RUBY_ASAN_ENABLED
309 void *fake_frame_start;
310 void *fake_frame_end;
311 void *real_stack_frame = __asan_addr_is_in_fake_stack(
312 thread_fake_stack_handle, (
void *)slot, &fake_frame_start, &fake_frame_end
314 if (real_stack_frame) {
316#if STACK_GROW_DIRECTION < 0
317 in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end;
319 in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end;
322 *fake_stack_start_out = fake_frame_start;
323 *fake_stack_end_out = fake_frame_end;
328 *fake_stack_start_out = 0;
329 *fake_stack_end_out = 0;
333extern const char ruby_asan_default_options[];
335#ifdef RUBY_ASAN_ENABLED
339# undef RUBY__ASAN_DEFAULT_OPTIONS
340# define RUBY__ASAN_DEFAULT_OPTIONS \
341 RBIMPL_SYMBOL_EXPORT_BEGIN() \
342 const char * __asan_default_options(void) {return ruby_asan_default_options;} \
343 RBIMPL_SYMBOL_EXPORT_END()
int len
Length of the buffer.
uintptr_t VALUE
Type that represents a Ruby object.