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))
130RUBY_SYMBOL_EXPORT_BEGIN
136void rb_asan_poison_object(
VALUE obj);
145void *rb_asan_poisoned_object_p(
VALUE obj);
153void rb_asan_unpoison_object(
VALUE obj,
bool newobj_p);
155RUBY_SYMBOL_EXPORT_END
173asan_unpoison_memory_region(
const volatile void *ptr,
size_t size,
bool malloc_p)
175 __asan_unpoison_memory_region(ptr, size);
177 __msan_allocated_memory(ptr, size);
180 __msan_unpoison(ptr, size);
185asan_unpoison_object_temporary(
VALUE obj)
187 void *ptr = rb_asan_poisoned_object_p(obj);
188 rb_asan_unpoison_object(obj,
false);
193asan_poison_object_restore(
VALUE obj,
void *ptr)
196 rb_asan_poison_object(obj);
201#define asan_unpoisoning_object(obj) \
202 for (void *poisoned = asan_unpoison_object_temporary(obj), \
203 *unpoisoning = &poisoned; \
205 unpoisoning = asan_poison_object_restore(obj, poisoned))
209asan_unpoison_memory_region_temporary(
void *ptr,
size_t len)
211 void *poisoned_ptr = __asan_region_is_poisoned(ptr,
len);
212 asan_unpoison_memory_region(ptr,
len,
false);
217asan_poison_memory_region_restore(
void *ptr,
size_t len,
void *poisoned_ptr)
220 asan_poison_memory_region(ptr,
len);
225#define asan_unpoisoning_memory_region(ptr, len) \
226 for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
227 *unpoisoning = &poisoned; \
229 unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
247asan_get_real_stack_addr(
void* slot)
250 addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
251 return addr ? addr : slot;
260asan_get_thread_fake_stack_handle(
void)
262 return __asan_get_current_fake_stack();
286asan_get_fake_stack_extents(
void *thread_fake_stack_handle,
VALUE slot,
287 void *machine_stack_start,
void *machine_stack_end,
288 void **fake_stack_start_out,
void **fake_stack_end_out)
292#ifdef RUBY_ASAN_ENABLED
293 void *fake_frame_start;
294 void *fake_frame_end;
295 void *real_stack_frame = __asan_addr_is_in_fake_stack(
296 thread_fake_stack_handle, (
void *)slot, &fake_frame_start, &fake_frame_end
298 if (real_stack_frame) {
300#if STACK_GROW_DIRECTION < 0
301 in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end;
303 in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end;
306 *fake_stack_start_out = fake_frame_start;
307 *fake_stack_end_out = fake_frame_end;
312 *fake_stack_start_out = 0;
313 *fake_stack_end_out = 0;
int len
Length of the buffer.
uintptr_t VALUE
Type that represents a Ruby object.