From 1555185d5b7867472b0e5f0589f71d9b1242e842 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering@fb.com>
Date: Sun, 4 Jan 2015 07:28:13 -0800
Subject: [PATCH] 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".
(__has_feature): Define.
(HAVE_ASAN): Define when address sanitizer is enabled.
[HAVE_ASAN]: Declare these two __asan_* symbols.
[!HAVE_ASAN] (__asan_poison_memory_region): Define stub.
[!HAVE_ASAN] (__asan_unpoison_memory_region): Likewise.
* src/grep.c: Use __asan_poison_memory_region.
---
 src/grep.c   |  5 +++++
 src/system.h | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/src/grep.c b/src/grep.c
index c85fc6e..7d70f4a 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -816,6 +816,11 @@ fillbuf (size_t save, struct stat const *st)
      positive reports of these bytes being used uninitialized.  */
   memset (buflim, 0, sizeof (uword));

+  /* Mark the part of the buffer not filled by the read or set by
+     the above memset call as ASAN-poisoned.  */
+  __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..15a1abb 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,43 @@ to_uchar (char ch)

 _GL_INLINE_HEADER_END

+#ifndef __has_feature
+# define __has_feature(F) false
+#endif
+
+#if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
+# define HAVE_ASAN 1
+#else
+# define HAVE_ASAN 0
+#endif
+
+#if HAVE_ASAN
+
+/* 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);
+
+#else
+
+static _GL_UNUSED void
+__asan_poison_memory_region (void const volatile *addr, size_t size) { }
+static _GL_UNUSED void
+__asan_unpoison_memory_region (void const volatile *addr, size_t size) { }
+#endif
+
 #endif
-- 
2.2.1

