Home | History | Annotate | Line # | Download | only in asan
      1 //===-- asan_interceptors_memintrinsics.h -----------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===---------------------------------------------------------------------===//
      9 //
     10 // This file is a part of AddressSanitizer, an address sanity checker.
     11 //
     12 // ASan-private header for asan_memintrin.cc
     13 //===---------------------------------------------------------------------===//
     14 #ifndef ASAN_MEMINTRIN_H
     15 #define ASAN_MEMINTRIN_H
     16 
     17 #include "asan_interface_internal.h"
     18 #include "asan_internal.h"
     19 #include "asan_mapping.h"
     20 #include "interception/interception.h"
     21 
     22 DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
     23 DECLARE_REAL(void*, memset, void *block, int c, uptr size)
     24 
     25 namespace __asan {
     26 
     27 // Return true if we can quickly decide that the region is unpoisoned.
     28 // We assume that a redzone is at least 16 bytes.
     29 static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
     30   if (size == 0) return true;
     31   if (size <= 32)
     32     return !AddressIsPoisoned(beg) &&
     33            !AddressIsPoisoned(beg + size - 1) &&
     34            !AddressIsPoisoned(beg + size / 2);
     35   if (size <= 64)
     36     return !AddressIsPoisoned(beg) &&
     37            !AddressIsPoisoned(beg + size / 4) &&
     38            !AddressIsPoisoned(beg + size - 1) &&
     39            !AddressIsPoisoned(beg + 3 * size / 4) &&
     40            !AddressIsPoisoned(beg + size / 2);
     41   return false;
     42 }
     43 
     44 struct AsanInterceptorContext {
     45   const char *interceptor_name;
     46 };
     47 
     48 // We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
     49 // and ASAN_WRITE_RANGE as macro instead of function so
     50 // that no extra frames are created, and stack trace contains
     51 // relevant information only.
     52 // We check all shadow bytes.
     53 #define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do {            \
     54     uptr __offset = (uptr)(offset);                                     \
     55     uptr __size = (uptr)(size);                                         \
     56     uptr __bad = 0;                                                     \
     57     if (__offset > __offset + __size) {                                 \
     58       GET_STACK_TRACE_FATAL_HERE;                                       \
     59       ReportStringFunctionSizeOverflow(__offset, __size, &stack);       \
     60     }                                                                   \
     61     if (!QuickCheckForUnpoisonedRegion(__offset, __size) &&             \
     62         (__bad = __asan_region_is_poisoned(__offset, __size))) {        \
     63       AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx;     \
     64       bool suppressed = false;                                          \
     65       if (_ctx) {                                                       \
     66         suppressed = IsInterceptorSuppressed(_ctx->interceptor_name);   \
     67         if (!suppressed && HaveStackTraceBasedSuppressions()) {         \
     68           GET_STACK_TRACE_FATAL_HERE;                                   \
     69           suppressed = IsStackTraceSuppressed(&stack);                  \
     70         }                                                               \
     71       }                                                                 \
     72       if (!suppressed) {                                                \
     73         GET_CURRENT_PC_BP_SP;                                           \
     74         ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
     75       }                                                                 \
     76     }                                                                   \
     77   } while (0)
     78 
     79 // memcpy is called during __asan_init() from the internals of printf(...).
     80 // We do not treat memcpy with to==from as a bug.
     81 // See http://llvm.org/bugs/show_bug.cgi?id=11763.
     82 #define ASAN_MEMCPY_IMPL(ctx, to, from, size)                           \
     83   do {                                                                  \
     84     if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
     85     if (asan_init_is_running) {                                         \
     86       return REAL(memcpy)(to, from, size);                              \
     87     }                                                                   \
     88     ENSURE_ASAN_INITED();                                               \
     89     if (flags()->replace_intrin) {                                      \
     90       if (to != from) {                                                 \
     91         CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);           \
     92       }                                                                 \
     93       ASAN_READ_RANGE(ctx, from, size);                                 \
     94       ASAN_WRITE_RANGE(ctx, to, size);                                  \
     95     }                                                                   \
     96     return REAL(memcpy)(to, from, size);                                \
     97   } while (0)
     98 
     99 // memset is called inside Printf.
    100 #define ASAN_MEMSET_IMPL(ctx, block, c, size)                           \
    101   do {                                                                  \
    102     if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
    103     if (asan_init_is_running) {                                         \
    104       return REAL(memset)(block, c, size);                              \
    105     }                                                                   \
    106     ENSURE_ASAN_INITED();                                               \
    107     if (flags()->replace_intrin) {                                      \
    108       ASAN_WRITE_RANGE(ctx, block, size);                               \
    109     }                                                                   \
    110     return REAL(memset)(block, c, size);                                \
    111   } while (0)
    112 
    113 #define ASAN_MEMMOVE_IMPL(ctx, to, from, size)                           \
    114   do {                                                                   \
    115     if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
    116     ENSURE_ASAN_INITED();                                                \
    117     if (flags()->replace_intrin) {                                       \
    118       ASAN_READ_RANGE(ctx, from, size);                                  \
    119       ASAN_WRITE_RANGE(ctx, to, size);                                   \
    120     }                                                                    \
    121     return internal_memmove(to, from, size);                             \
    122   } while (0)
    123 
    124 #define ASAN_READ_RANGE(ctx, offset, size) \
    125   ACCESS_MEMORY_RANGE(ctx, offset, size, false)
    126 #define ASAN_WRITE_RANGE(ctx, offset, size) \
    127   ACCESS_MEMORY_RANGE(ctx, offset, size, true)
    128 
    129 // Behavior of functions like "memcpy" or "strcpy" is undefined
    130 // if memory intervals overlap. We report error in this case.
    131 // Macro is used to avoid creation of new frames.
    132 static inline bool RangesOverlap(const char *offset1, uptr length1,
    133                                  const char *offset2, uptr length2) {
    134   return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
    135 }
    136 #define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2)   \
    137   do {                                                                     \
    138     const char *offset1 = (const char *)_offset1;                          \
    139     const char *offset2 = (const char *)_offset2;                          \
    140     if (RangesOverlap(offset1, length1, offset2, length2)) {               \
    141       GET_STACK_TRACE_FATAL_HERE;                                          \
    142       bool suppressed = IsInterceptorSuppressed(name);                     \
    143       if (!suppressed && HaveStackTraceBasedSuppressions()) {              \
    144         suppressed = IsStackTraceSuppressed(&stack);                       \
    145       }                                                                    \
    146       if (!suppressed) {                                                   \
    147         ReportStringFunctionMemoryRangesOverlap(name, offset1, length1,    \
    148                                                 offset2, length2, &stack); \
    149       }                                                                    \
    150     }                                                                      \
    151   } while (0)
    152 
    153 }  // namespace __asan
    154 
    155 #endif  // ASAN_MEMINTRIN_H
    156