]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libsanitizer/asan/asan_poisoning.h
Libsanitizer merge from trunk r368656.
[thirdparty/gcc.git] / libsanitizer / asan / asan_poisoning.h
index 866c0a57c7ef7ea39f604a6619c1ee31092d4798..62dd9bd0edd3200c0f5738bb6bd2343ca315f4a9 100644 (file)
@@ -1,7 +1,8 @@
 //===-- asan_poisoning.h ----------------------------------------*- C++ -*-===//
 //
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
 //
 #include "asan_interceptors.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_platform.h"
 
 namespace __asan {
 
+// Enable/disable memory poisoning.
+void SetCanPoisonMemory(bool value);
+bool CanPoisonMemory();
+
 // Poisons the shadow memory for "size" bytes starting from "addr".
 void PoisonShadow(uptr addr, uptr size, u8 value);
 
@@ -31,16 +38,48 @@ void PoisonShadowPartialRightRedzone(uptr addr,
 // performance-critical code with care.
 ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
                                     u8 value) {
-  DCHECK(flags()->poison_heap);
+  DCHECK(!value || CanPoisonMemory());
+#if SANITIZER_FUCHSIA
+  __sanitizer_fill_shadow(aligned_beg, aligned_size, value,
+                          common_flags()->clear_shadow_mmap_threshold);
+#else
   uptr shadow_beg = MEM_TO_SHADOW(aligned_beg);
   uptr shadow_end = MEM_TO_SHADOW(
       aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1;
-  REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+  // FIXME: Page states are different on Windows, so using the same interface
+  // for mapping shadow and zeroing out pages doesn't "just work", so we should
+  // probably provide higher-level interface for these operations.
+  // For now, just memset on Windows.
+  if (value || SANITIZER_WINDOWS == 1 ||
+      // RTEMS doesn't have have pages, let alone a fast way to zero
+      // them, so default to memset.
+      SANITIZER_RTEMS == 1 ||
+      shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
+    REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
+  } else {
+    uptr page_size = GetPageSizeCached();
+    uptr page_beg = RoundUpTo(shadow_beg, page_size);
+    uptr page_end = RoundDownTo(shadow_end, page_size);
+
+    if (page_beg >= page_end) {
+      REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
+    } else {
+      if (page_beg != shadow_beg) {
+        REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
+      }
+      if (page_end != shadow_end) {
+        REAL(memset)((void *)page_end, 0, shadow_end - page_end);
+      }
+      ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr);
+    }
+  }
+#endif // SANITIZER_FUCHSIA
 }
 
 ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
     uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
-  DCHECK(flags()->poison_heap);
+  DCHECK(CanPoisonMemory());
+  bool poison_partial = flags()->poison_partial;
   u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
   for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
     if (i + SHADOW_GRANULARITY <= size) {
@@ -49,9 +88,13 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
       *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value;  // unaddressable
     } else {
       // first size-i bytes are addressable
-      *shadow = static_cast<u8>(size - i);
+      *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
     }
   }
 }
 
+// Calls __sanitizer::ReleaseMemoryPagesToOS() on
+// [MemToShadow(p), MemToShadow(p+size)].
+void FlushUnneededASanShadowMemory(uptr p, uptr size);
+
 }  // namespace __asan