mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**                                                         \noop-*-C-*-vi:ft=c
 | 
						|
 * @file
 | 
						|
 * @author     Ruby developers <ruby-core@ruby-lang.org>
 | 
						|
 * @copyright  This  file  is   a  part  of  the   programming  language  Ruby.
 | 
						|
 *             Permission  is hereby  granted,  to  either redistribute  and/or
 | 
						|
 *             modify this file, provided that  the conditions mentioned in the
 | 
						|
 *             file COPYING are met.  Consult the file for details.
 | 
						|
 * @brief      Internal header for ASAN / MSAN / etc.
 | 
						|
 */
 | 
						|
#ifndef INTERNAL_SANITIZERS_H
 | 
						|
#define INTERNAL_SANITIZERS_H
 | 
						|
#include "ruby/3/config.h"
 | 
						|
#include "internal/compilers.h" /* for __has_feature */
 | 
						|
 | 
						|
#ifdef HAVE_VALGRIND_MEMCHECK_H
 | 
						|
# include <valgrind/memcheck.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_SANITIZER_ASAN_INTERFACE_H
 | 
						|
# include <sanitizer/asan_interface.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_SANITIZER_MSAN_INTERFACE_H
 | 
						|
# if __has_feature(memory_sanitizer)
 | 
						|
#  include <sanitizer/msan_interface.h>
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
#include "ruby/3/stdbool.h"     /* for bool */
 | 
						|
#include "ruby/ruby.h"          /* for VALUE */
 | 
						|
 | 
						|
#if 0
 | 
						|
#elif __has_feature(memory_sanitizer) && __has_feature(address_sanitizer)
 | 
						|
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
 | 
						|
    __attribute__((__no_sanitize__("memory, address"), __noinline__)) x
 | 
						|
#elif __has_feature(address_sanitizer)
 | 
						|
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
 | 
						|
    __attribute__((__no_sanitize__("address"), __noinline__)) x
 | 
						|
#elif defined(NO_SANITIZE_ADDRESS)
 | 
						|
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
 | 
						|
    NO_SANITIZE_ADDRESS(NOINLINE(x))
 | 
						|
#elif defined(NO_ADDRESS_SAFETY_ANALYSIS)
 | 
						|
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
 | 
						|
    NO_ADDRESS_SAFETY_ANALYSIS(NOINLINE(x))
 | 
						|
#else
 | 
						|
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) x
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(NO_SANITIZE) && defined(__GNUC__) &&! defined(__clang__)
 | 
						|
/* GCC warns about unknown sanitizer, which is annoying. */
 | 
						|
# include "internal/warnings.h"
 | 
						|
# undef NO_SANITIZE
 | 
						|
# define NO_SANITIZE(x, y) \
 | 
						|
    COMPILER_WARNING_PUSH; \
 | 
						|
    COMPILER_WARNING_IGNORED(-Wattributes); \
 | 
						|
    __attribute__((__no_sanitize__(x))) y; \
 | 
						|
    COMPILER_WARNING_POP
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef NO_SANITIZE
 | 
						|
# define NO_SANITIZE(x, y) y
 | 
						|
#endif
 | 
						|
 | 
						|
#if !__has_feature(address_sanitizer)
 | 
						|
# define __asan_poison_memory_region(x, y)
 | 
						|
# define __asan_unpoison_memory_region(x, y)
 | 
						|
# define __asan_region_is_poisoned(x, y) 0
 | 
						|
#endif
 | 
						|
 | 
						|
#if !__has_feature(memory_sanitizer)
 | 
						|
# define __msan_allocated_memory(x, y) ((void)(x), (void)(y))
 | 
						|
# define __msan_poison(x, y) ((void)(x), (void)(y))
 | 
						|
# define __msan_unpoison(x, y) ((void)(x), (void)(y))
 | 
						|
# define __msan_unpoison_string(x) ((void)(x))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef VALGRIND_MAKE_READABLE
 | 
						|
# define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef VALGRIND_MAKE_WRITABLE
 | 
						|
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef VALGRIND_MAKE_MEM_DEFINED
 | 
						|
# define VALGRIND_MAKE_MEM_DEFINED(p, n) 0
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef VALGRIND_MAKE_MEM_UNDEFINED
 | 
						|
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef MJIT_HEADER
 | 
						|
 | 
						|
/*!
 | 
						|
 * This function asserts that a (continuous) memory region from ptr to size
 | 
						|
 * being "poisoned".  Both read / write access to such memory region are
 | 
						|
 * prohibited until properly unpoisoned.  The region must be previously
 | 
						|
 * allocated (do not pass a freed pointer here), but not necessarily be an
 | 
						|
 * entire object that the malloc returns.  You can punch hole a part of a
 | 
						|
 * gigantic heap arena.  This is handy when you do not free an allocated memory
 | 
						|
 * region to reuse later: poison when you keep it unused, and unpoison when you
 | 
						|
 * reuse.
 | 
						|
 *
 | 
						|
 * \param[in]  ptr   pointer to the beginning of the memory region to poison.
 | 
						|
 * \param[in]  size  the length of the memory region to poison.
 | 
						|
 */
 | 
						|
static inline void
 | 
						|
asan_poison_memory_region(const volatile void *ptr, size_t size)
 | 
						|
{
 | 
						|
    __msan_poison(ptr, size);
 | 
						|
    __asan_poison_memory_region(ptr, size);
 | 
						|
}
 | 
						|
 | 
						|
/*!
 | 
						|
 * This is a variant of asan_poison_memory_region that takes a VALUE.
 | 
						|
 *
 | 
						|
 * \param[in]  obj   target object.
 | 
						|
 */
 | 
						|
static inline void
 | 
						|
asan_poison_object(VALUE obj)
 | 
						|
{
 | 
						|
    MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj;
 | 
						|
    asan_poison_memory_region(ptr, SIZEOF_VALUE);
 | 
						|
}
 | 
						|
 | 
						|
#if !__has_feature(address_sanitizer)
 | 
						|
#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
 | 
						|
#else
 | 
						|
#define asan_poison_object_if(ptr, obj) do { \
 | 
						|
        if (ptr) asan_poison_object(obj); \
 | 
						|
    } while (0)
 | 
						|
#endif
 | 
						|
 | 
						|
/*!
 | 
						|
 * This function predicates if the given object is fully addressable or not.
 | 
						|
 *
 | 
						|
 * \param[in]  obj        target object.
 | 
						|
 * \retval     0          the given object is fully addressable.
 | 
						|
 * \retval     otherwise  pointer to first such byte who is poisoned.
 | 
						|
 */
 | 
						|
static inline void *
 | 
						|
asan_poisoned_object_p(VALUE obj)
 | 
						|
{
 | 
						|
    MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj;
 | 
						|
    return __asan_region_is_poisoned(ptr, SIZEOF_VALUE);
 | 
						|
}
 | 
						|
 | 
						|
/*!
 | 
						|
 * This function asserts that a (formally poisoned) memory region from ptr to
 | 
						|
 * size is now addressable.  Write access to such memory region gets allowed.
 | 
						|
 * However read access might or might not be possible depending on situations,
 | 
						|
 * because the region can have contents of previous usages.  That information
 | 
						|
 * should be passed by the malloc_p flag.  If that is true, the contents of the
 | 
						|
 * region is _not_ fully defined (like the return value of malloc behaves).
 | 
						|
 * Reading from there is NG; write something first.  If malloc_p is false on
 | 
						|
 * the other hand, that memory region is fully defined and can be read
 | 
						|
 * immediately.
 | 
						|
 *
 | 
						|
 * \param[in]  ptr       pointer to the beginning of the memory region to unpoison.
 | 
						|
 * \param[in]  size      the length of the memory region.
 | 
						|
 * \param[in]  malloc_p  if the memory region is like a malloc's return value or not.
 | 
						|
 */
 | 
						|
static inline void
 | 
						|
asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p)
 | 
						|
{
 | 
						|
    __asan_unpoison_memory_region(ptr, size);
 | 
						|
    if (malloc_p) {
 | 
						|
        __msan_allocated_memory(ptr, size);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        __msan_unpoison(ptr, size);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*!
 | 
						|
 * This is a variant of asan_unpoison_memory_region that takes a VALUE.
 | 
						|
 *
 | 
						|
 * \param[in]  obj       target object.
 | 
						|
 * \param[in]  malloc_p  if the memory region is like a malloc's return value or not.
 | 
						|
 */
 | 
						|
static inline void
 | 
						|
asan_unpoison_object(VALUE obj, bool newobj_p)
 | 
						|
{
 | 
						|
    MAYBE_UNUSED(struct RVALUE *) ptr = (void *)obj;
 | 
						|
    asan_unpoison_memory_region(ptr, SIZEOF_VALUE, newobj_p);
 | 
						|
}
 | 
						|
 | 
						|
#endif /* MJIT_HEADER */
 | 
						|
 | 
						|
#endif /* INTERNAL_SANITIZERS_H */
 |