Home | History | Annotate | Download | only in asan
      1 //===-- asan_malloc_win.cc ------------------------------------------------===//
      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 // Windows-specific malloc interception.
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 #if SANITIZER_WINDOWS
     17 
     18 #include "asan_allocator.h"
     19 #include "asan_interceptors.h"
     20 #include "asan_internal.h"
     21 #include "asan_stack.h"
     22 #include "sanitizer_common/sanitizer_interception.h"
     23 
     24 #include <stddef.h>
     25 
     26 // ---------------------- Replacement functions ---------------- {{{1
     27 using namespace __asan;  // NOLINT
     28 
     29 // FIXME: Simply defining functions with the same signature in *.obj
     30 // files overrides the standard functions in *.lib
     31 // This works well for simple helloworld-like tests but might need to be
     32 // revisited in the future.
     33 
     34 extern "C" {
     35 SANITIZER_INTERFACE_ATTRIBUTE
     36 void free(void *ptr) {
     37   GET_STACK_TRACE_FREE;
     38   return asan_free(ptr, &stack, FROM_MALLOC);
     39 }
     40 
     41 SANITIZER_INTERFACE_ATTRIBUTE
     42 void _free_dbg(void* ptr, int) {
     43   free(ptr);
     44 }
     45 
     46 void cfree(void *ptr) {
     47   CHECK(!"cfree() should not be used on Windows?");
     48 }
     49 
     50 SANITIZER_INTERFACE_ATTRIBUTE
     51 void *malloc(size_t size) {
     52   GET_STACK_TRACE_MALLOC;
     53   return asan_malloc(size, &stack);
     54 }
     55 
     56 SANITIZER_INTERFACE_ATTRIBUTE
     57 void* _malloc_dbg(size_t size, int , const char*, int) {
     58   return malloc(size);
     59 }
     60 
     61 SANITIZER_INTERFACE_ATTRIBUTE
     62 void *calloc(size_t nmemb, size_t size) {
     63   GET_STACK_TRACE_MALLOC;
     64   return asan_calloc(nmemb, size, &stack);
     65 }
     66 
     67 SANITIZER_INTERFACE_ATTRIBUTE
     68 void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
     69   return calloc(n, size);
     70 }
     71 
     72 SANITIZER_INTERFACE_ATTRIBUTE
     73 void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
     74   return calloc(nmemb, size);
     75 }
     76 
     77 SANITIZER_INTERFACE_ATTRIBUTE
     78 void *realloc(void *ptr, size_t size) {
     79   GET_STACK_TRACE_MALLOC;
     80   return asan_realloc(ptr, size, &stack);
     81 }
     82 
     83 SANITIZER_INTERFACE_ATTRIBUTE
     84 void *_realloc_dbg(void *ptr, size_t size, int) {
     85   CHECK(!"_realloc_dbg should not exist!");
     86   return 0;
     87 }
     88 
     89 SANITIZER_INTERFACE_ATTRIBUTE
     90 void* _recalloc(void* p, size_t n, size_t elem_size) {
     91   if (!p)
     92     return calloc(n, elem_size);
     93   const size_t size = n * elem_size;
     94   if (elem_size != 0 && size / elem_size != n)
     95     return 0;
     96   return realloc(p, size);
     97 }
     98 
     99 SANITIZER_INTERFACE_ATTRIBUTE
    100 size_t _msize(void *ptr) {
    101   GET_CURRENT_PC_BP_SP;
    102   (void)sp;
    103   return asan_malloc_usable_size(ptr, pc, bp);
    104 }
    105 
    106 SANITIZER_INTERFACE_ATTRIBUTE
    107 void *_expand(void *memblock, size_t size) {
    108   // _expand is used in realloc-like functions to resize the buffer if possible.
    109   // We don't want memory to stand still while resizing buffers, so return 0.
    110   return 0;
    111 }
    112 
    113 SANITIZER_INTERFACE_ATTRIBUTE
    114 void *_expand_dbg(void *memblock, size_t size) {
    115   return 0;
    116 }
    117 
    118 // TODO(timurrrr): Might want to add support for _aligned_* allocation
    119 // functions to detect a bit more bugs.  Those functions seem to wrap malloc().
    120 
    121 int _CrtDbgReport(int, const char*, int,
    122                   const char*, const char*, ...) {
    123   ShowStatsAndAbort();
    124 }
    125 
    126 int _CrtDbgReportW(int reportType, const wchar_t*, int,
    127                    const wchar_t*, const wchar_t*, ...) {
    128   ShowStatsAndAbort();
    129 }
    130 
    131 int _CrtSetReportMode(int, int) {
    132   return 0;
    133 }
    134 }  // extern "C"
    135 
    136 using __interception::GetRealFunctionAddress;
    137 
    138 // We don't want to include "windows.h" in this file to avoid extra attributes
    139 // set on malloc/free etc (e.g. dllimport), so declare a few things manually:
    140 extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
    141                                         DWORD prot, DWORD *old_prot);
    142 const int PAGE_EXECUTE_READWRITE = 0x40;
    143 
    144 namespace __asan {
    145 void ReplaceSystemMalloc() {
    146 #if defined(_DLL)
    147 # ifdef _WIN64
    148 #  error ReplaceSystemMalloc was not tested on x64
    149 # endif
    150   char *crt_malloc;
    151   if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
    152     // Replace malloc in the CRT dll with a jump to our malloc.
    153     DWORD old_prot, unused;
    154     CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
    155     REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16);  // just in case.
    156 
    157     ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
    158     crt_malloc[0] = 0xE9;  // jmp, should be followed by an offset.
    159     REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
    160 
    161     CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
    162 
    163     // FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
    164   }
    165 
    166   // FIXME: investigate whether anything else is needed.
    167 #endif
    168 }
    169 }  // namespace __asan
    170 
    171 #endif  // _WIN32
    172