From d4c3bc9c8edc76e455003c6c8ad758d1a382f7c6 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering@fb.com>
Date: Sun, 4 Jan 2015 07:28:13 -0800
Subject: [PATCH 3/3] tests: add support for ASAN memory poisoning

This lets us reliably detect with ASAN some UMR bugs
that would otherwise be detectable only some of the time
with MSAN.  Use ASAN_POISON_MEMORY_REGION to mark the unused
portion of a read buffer as inaccessible.  Then, with ASAN,
any attempt to access those bytes results in an ASAN abort.
* src/system.h: Include "ignore-value.h".
(HAVE_ASAN): Define when address sanitizer is enabled.
* src/grep.c (ASAN_POISON_MEMORY_REGION): Define.
(ASAN_UNPOISON_MEMORY_REGION): Define.
---
 src/grep.c   |  2 ++
 src/system.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/src/grep.c b/src/grep.c
index c85fc6e..3d79d53 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -815,6 +815,8 @@ fillbuf (size_t save, struct stat const *st)
      matchers read (but do not use) those bytes.  This avoids false
      positive reports of these bytes being used uninitialized.  */
   memset (buflim, 0, sizeof (uword));
+  ASAN_POISON_MEMORY_REGION (buflim + sizeof(uword),
+                             bufalloc - (buflim - buffer) - sizeof(uword));

   return cc;
 }
diff --git a/src/system.h b/src/system.h
index 1cc2bd3..06252c4 100644
--- a/src/system.h
+++ b/src/system.h
@@ -26,6 +26,7 @@
 #include "binary-io.h"
 #include "configmake.h"
 #include "dirname.h"
+#include "ignore-value.h"
 #include "minmax.h"
 #include "same-inode.h"

@@ -67,4 +68,45 @@ to_uchar (char ch)

 _GL_INLINE_HEADER_END

+/* Mark memory region [addr, addr+size) as unaddressable.
+   This memory must be previously allocated by the user program.  Accessing
+   addresses in this region from instrumented code is forbidden until
+   this region is unpoisoned.  This function is not guaranteed to poison
+   the whole region - it may poison only a subregion of [addr, addr+size)
+   due to ASan alignment restrictions.
+   Method is NOT thread-safe in the sense that no two threads can
+   (un)poison memory in the same memory region simultaneously.  */
+void __asan_poison_memory_region (void const volatile *addr, size_t size);
+
+/* Mark memory region [addr, addr+size) as addressable.
+   This memory must be previously allocated by the user program.  Accessing
+   addresses in this region is allowed until this region is poisoned again.
+   This function may unpoison a superregion of [addr, addr+size) due to
+   ASan alignment restrictions.
+   Method is NOT thread-safe in the sense that no two threads can
+   (un)poison memory in the same memory region simultaneously.  */
+void __asan_unpoison_memory_region (void const volatile *addr, size_t size);
+
+#if defined __clang__
+# if __has_feature(address_sanitizer)
+#  define HAVE_ASAN 1
+# endif
+#elif defined __GNUC__ \
+  && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ >= 5)) \
+  && __SANITIZE_ADDRESS__
+# define HAVE_ASAN 1
+#endif
+
+#ifdef HAVE_ASAN
+# define ASAN_POISON_MEMORY_REGION(addr, size) \
+  __asan_poison_memory_region ((addr), (size))
+# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+  __asan_unpoison_memory_region ((addr), (size))
+#else
+# define ASAN_POISON_MEMORY_REGION(addr, size) \
+  (ignore_value (addr), ignore_value (size))
+# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+  (ignore_value (addr), ignore_value (size))
+#endif
+
 #endif
-- 
2.2.1

