1//===- nsan_malloc_linux.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Interceptors for memory allocation functions on ELF OSes.
10//
11//===----------------------------------------------------------------------===//
12
13#include "interception/interception.h"
14#include "nsan/nsan.h"
15#include "sanitizer_common/sanitizer_allocator_dlsym.h"
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_platform.h"
18#include "sanitizer_common/sanitizer_platform_interceptors.h"
19
20#if !SANITIZER_APPLE && !SANITIZER_WINDOWS
21using namespace __sanitizer;
22using __nsan::nsan_initialized;
23
24namespace {
25struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
26 static bool UseImpl() { return !nsan_initialized; }
27};
28} // namespace
29
30INTERCEPTOR(void *, aligned_alloc, uptr align, uptr size) {
31 void *res = REAL(aligned_alloc)(align, size);
32 if (res)
33 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size);
34 return res;
35}
36
37INTERCEPTOR(void *, calloc, uptr nmemb, uptr size) {
38 if (DlsymAlloc::Use())
39 return DlsymAlloc::Callocate(nmemb, size);
40
41 void *res = REAL(calloc)(nmemb, size);
42 if (res)
43 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size: nmemb * size);
44 return res;
45}
46
47INTERCEPTOR(void, free, void *ptr) {
48 if (DlsymAlloc::PointerIsMine(ptr))
49 return DlsymAlloc::Free(ptr);
50 REAL(free)(ptr);
51}
52
53INTERCEPTOR(void *, malloc, uptr size) {
54 if (DlsymAlloc::Use())
55 return DlsymAlloc::Allocate(size_in_bytes: size);
56 void *res = REAL(malloc)(size);
57 if (res)
58 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size);
59 return res;
60}
61
62INTERCEPTOR(void *, realloc, void *ptr, uptr size) {
63 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
64 return DlsymAlloc::Realloc(ptr, new_size: size);
65 void *res = REAL(realloc)(ptr, size);
66 // TODO: We might want to copy the types from the original allocation
67 // (although that would require that we know its size).
68 if (res)
69 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size);
70 return res;
71}
72
73#if SANITIZER_INTERCEPT_REALLOCARRAY
74INTERCEPTOR(void *, reallocarray, void *ptr, uptr nmemb, uptr size) {
75 void *res = REAL(reallocarray)(ptr, nmemb, size);
76 if (res)
77 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size: nmemb * size);
78 return res;
79}
80#endif // SANITIZER_INTERCEPT_REALLOCARRAY
81
82INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr size) {
83 int res = REAL(posix_memalign)(memptr, align, size);
84 if (res == 0 && *memptr)
85 __nsan_set_value_unknown(addr: static_cast<u8 *>(*memptr), size);
86 return res;
87}
88
89// Deprecated allocation functions (memalign, etc).
90#if SANITIZER_INTERCEPT_MEMALIGN
91INTERCEPTOR(void *, memalign, uptr align, uptr size) {
92 void *const res = REAL(memalign)(align, size);
93 if (res)
94 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size);
95 return res;
96}
97
98INTERCEPTOR(void *, __libc_memalign, uptr align, uptr size) {
99 void *const res = REAL(__libc_memalign)(align, size);
100 if (res)
101 __nsan_set_value_unknown(addr: static_cast<u8 *>(res), size);
102 return res;
103}
104#endif
105
106void __nsan::InitializeMallocInterceptors() {
107 INTERCEPT_FUNCTION(aligned_alloc);
108 INTERCEPT_FUNCTION(calloc);
109 INTERCEPT_FUNCTION(free);
110 INTERCEPT_FUNCTION(malloc);
111 INTERCEPT_FUNCTION(posix_memalign);
112 INTERCEPT_FUNCTION(realloc);
113#if SANITIZER_INTERCEPT_REALLOCARRAY
114 INTERCEPT_FUNCTION(reallocarray);
115#endif
116
117#if SANITIZER_INTERCEPT_MEMALIGN
118 INTERCEPT_FUNCTION(memalign);
119 INTERCEPT_FUNCTION(__libc_memalign);
120#endif
121}
122
123#endif
124