]> granicus.if.org Git - gc/commitdiff
Support AddressSanitizer and MemorySanitizer (clang)
authorIvan Maidanski <ivmai@mail.ru>
Tue, 15 Nov 2016 14:35:40 +0000 (17:35 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Sun, 27 Nov 2016 07:13:12 +0000 (10:13 +0300)
* include/private/gc_priv.h (GC_ATTR_NO_SANITIZE_ADDR,
GC_ATTR_NO_SANITIZE_MEMORY): New macro.
* include/private/gcconfig.h [__has_feature(address_sanitizer)]
(ADDRESS_SANITIZER): New macro.
* include/private/gcconfig.h [__has_feature(memory_sanitizer)]
(MEMORY_SANITIZER): Likewise.
* mach_dep.c (GC_with_callee_saves_pushed): Use
GC_ATTR_NO_SANITIZE_ADDR attribute.
* mark.c (GC_mark_from, GC_push_all_eager): Likewise.
* mark.c (GC_mark_from, GC_push_all_eager): Use
GC_ATTR_NO_SANITIZE_MEMORY attribute.
* os_dep.c [ADDRESS_SANITIZER && (UNIX_LIKE || NEED_FIND_LIMIT
|| MPROTECT_VDB)] (__asan_default_options): New function.
* os_dep.c [(NEED_FIND_LIMIT || UNIX_LIKE) && CPPCHECK
&& ADDRESS_SANITIZER] (GC_set_and_save_fault_handler):
Reference __asan_default_options.
* os_dep.c [MPROTECT_VDB && !DARWIN && CPPCHECK && ADDRESS_SANITIZER]
(GC_dirty_init): Likewise.
* tests/test.c [MEMORY_SANITIZER] (check_heap_stats): Increase
max_heap_sz by 25% (to avoid "Unexpected heap growth" error if MSan is
used).
* tests/test_cpp.cc [ADDRESS_SANITIZER || MEMORY_SANITIZER] (main):
Call GC_FREE(a) instead of delete a; add comment.

include/private/gc_priv.h
include/private/gcconfig.h
mach_dep.c
mark.c
os_dep.c
tests/test.c
tests/test_cpp.cc

index f1a51857c12414949540f45ff73214b05b76505b..e5c870d7b398812cd58d626baccc4f3b719da939 100644 (file)
@@ -148,6 +148,22 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
 # include "gc_hdrs.h"
 #endif
 
+#ifndef GC_ATTR_NO_SANITIZE_ADDR
+# ifdef ADDRESS_SANITIZER
+#   define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
+# else
+#   define GC_ATTR_NO_SANITIZE_ADDR /* empty */
+# endif
+#endif /* !GC_ATTR_NO_SANITIZE_ADDR */
+
+#ifndef GC_ATTR_NO_SANITIZE_MEMORY
+# ifdef MEMORY_SANITIZER
+#   define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
+# else
+#   define GC_ATTR_NO_SANITIZE_MEMORY /* empty */
+# endif
+#endif /* !GC_ATTR_NO_SANITIZE_MEMORY */
+
 #ifndef GC_ATTR_UNUSED
 # if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 #   define GC_ATTR_UNUSED __attribute__((__unused__))
index d45abda8b48576c7f966aca55b5322e06ad9ebfa..b1f370f9af48c464791d0959c0ac2b17099e869a 100644 (file)
 # endif
 #endif /* !GC_WORD_C */
 
+#if defined(__has_feature)
+  /* __has_feature() is supported.      */
+# if __has_feature(address_sanitizer) && !defined(ADDRESS_SANITIZER)
+#   define ADDRESS_SANITIZER
+# endif
+# if __has_feature(memory_sanitizer) && !defined(MEMORY_SANITIZER)
+#   define MEMORY_SANITIZER
+# endif
+#endif
+
 #if defined(SPARC)
 # define ASM_CLEAR_CODE /* Stack clearing is crucial, and we    */
                         /* include assembly code to do it well. */
index 61b5ed26e038373f5ca76e594e2782fdc6ff238f..850a9902acdb6881fd9898b4c4c1a968423cef4b 100644 (file)
 /* ctxt is either a pointer to a ucontext_t we generated, or NULL.      */
 GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
                                           volatile ptr_t arg)
+                                          GC_ATTR_NO_SANITIZE_ADDR
 {
   volatile int dummy;
   void * context = 0;
diff --git a/mark.c b/mark.c
index 20307fb6048beabf49ba3d239d57e5e09968d194..b83ad9130bc09fb4ca80e8d80a19db0efecb1b42 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -598,6 +598,7 @@ GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp)
  */
 GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
                             mse *mark_stack_limit)
+                        GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY
 {
   signed_word credit = HBLKSIZE;  /* Remaining credit for marking work  */
   ptr_t current_p;      /* Pointer to current candidate ptr.            */
@@ -1527,6 +1528,7 @@ GC_API void GC_CALL GC_print_trace(word gc_no)
  * change.
  */
 GC_API void GC_CALL GC_push_all_eager(char *bottom, char *top)
+                        GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY
 {
     word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
     word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
index e8601b26f9c3f33ba560b111ecad7f8ded4871a7..a0ded5f3ac144b08ad9e6559654fcf5df41216a1 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -505,6 +505,15 @@ GC_INNER char * GC_get_maps(void)
   }
 #endif /* NETBSD */
 
+#if defined(ADDRESS_SANITIZER) && (defined(UNIX_LIKE) \
+                    || defined(NEED_FIND_LIMIT) || defined(MPROTECT_VDB))
+  /* To tell ASan to allow GC to use its own SIGBUS/SEGV handlers.      */
+  const char *__asan_default_options(void)
+  {
+    return "allow_user_segv_handler=1";
+  }
+#endif
+
 #ifdef OPENBSD
   static struct sigaction old_segv_act;
   STATIC sigjmp_buf GC_jmp_buf_openbsd;
@@ -893,6 +902,9 @@ GC_INNER size_t GC_page_size = 0;
 #         ifdef HAVE_SIGBUS
             old_bus_handler = signal(SIGBUS, h);
 #         endif
+#       endif
+#       if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
+          GC_noop1((word)&__asan_default_options);
 #       endif
     }
 # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
@@ -3409,6 +3421,9 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
 #   elif defined(MSWINCE)
       /* MPROTECT_VDB is unsupported for WinCE at present.      */
       /* FIXME: implement it (if possible). */
+#   endif
+#   if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
+      GC_noop1((word)&__asan_default_options);
 #   endif
   }
 #endif /* !DARWIN */
index 2580a0f7a78e33f84575e573b2c203dbd709d563..8e4c4b5f4bef631169666e99169d6c79150a1442 100644 (file)
@@ -1526,6 +1526,9 @@ void check_heap_stats(void)
                 max_heap_sz += max_heap_sz * NFRAMES / 4;
 #           endif
 #       endif
+#   endif
+#   ifdef MEMORY_SANITIZER
+        max_heap_sz += max_heap_sz / 4;
 #   endif
     max_heap_sz *= n_tests;
 #   if defined(USE_MMAP) || defined(MSWIN32)
index 823f818e8f0a1763ece1103543830c22d93b2624..1a6c5b646108071b33ae2609a8a237abeee07105 100644 (file)
@@ -318,7 +318,14 @@ void* Undisguise( GC_word i ) {
             A* a = static_cast<A*>(Undisguise(as[i]));
             B* b = static_cast<B*>(Undisguise(bs[i]));
             a->Test( i );
-            delete a;
+#           if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
+              // Workaround for ASan/MSan: the linker uses operator delete
+              // implementation from libclang_rt instead of gc_cpp (thus
+              // causing incompatible alloc/free).
+              GC_FREE(a);
+#           else
+              delete a;
+#           endif
             b->Test( i );
             B::Deleting( 1 );
             delete b;