1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
6 #error This header is meant to be included only once by allocator_shim.cc
7 #endif
8 
9 #ifndef PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
10 #define PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
11 
12 // This header overrides the __wrap_X symbols when using the link-time
13 // -Wl,-wrap,malloc shim-layer approach (see README.md).
14 // All references to malloc, free, etc. within the linker unit that gets the
15 // -wrap linker flags (e.g., libchrome.so) will be rewritten to the
16 // linker as references to __wrap_malloc, __wrap_free, which are defined here.
17 
18 #include "partition_alloc/partition_alloc_buildflags.h"
19 
20 #if BUILDFLAG(USE_ALLOCATOR_SHIM)
21 #include <algorithm>
22 #include <cstring>
23 
24 #include "partition_alloc/shim/allocator_shim_internals.h"
25 
26 extern "C" {
27 
__wrap_calloc(size_t n,size_t size)28 SHIM_ALWAYS_EXPORT void* __wrap_calloc(size_t n, size_t size) {
29   return ShimCalloc(n, size, nullptr);
30 }
31 
__wrap_free(void * ptr)32 SHIM_ALWAYS_EXPORT void __wrap_free(void* ptr) {
33   ShimFree(ptr, nullptr);
34 }
35 
__wrap_malloc(size_t size)36 SHIM_ALWAYS_EXPORT void* __wrap_malloc(size_t size) {
37   return ShimMalloc(size, nullptr);
38 }
39 
__wrap_memalign(size_t align,size_t size)40 SHIM_ALWAYS_EXPORT void* __wrap_memalign(size_t align, size_t size) {
41   return ShimMemalign(align, size, nullptr);
42 }
43 
__wrap_posix_memalign(void ** res,size_t align,size_t size)44 SHIM_ALWAYS_EXPORT int __wrap_posix_memalign(void** res,
45                                              size_t align,
46                                              size_t size) {
47   return ShimPosixMemalign(res, align, size);
48 }
49 
__wrap_pvalloc(size_t size)50 SHIM_ALWAYS_EXPORT void* __wrap_pvalloc(size_t size) {
51   return ShimPvalloc(size);
52 }
53 
__wrap_realloc(void * address,size_t size)54 SHIM_ALWAYS_EXPORT void* __wrap_realloc(void* address, size_t size) {
55   return ShimRealloc(address, size, nullptr);
56 }
57 
__wrap_valloc(size_t size)58 SHIM_ALWAYS_EXPORT void* __wrap_valloc(size_t size) {
59   return ShimValloc(size, nullptr);
60 }
61 
__wrap_malloc_usable_size(void * address)62 SHIM_ALWAYS_EXPORT size_t __wrap_malloc_usable_size(void* address) {
63   return ShimGetSizeEstimate(address, nullptr);
64 }
65 
66 const size_t kPathMaxSize = 8192;
67 static_assert(kPathMaxSize >= PATH_MAX, "");
68 
69 extern char* __wrap_strdup(const char* str);
70 
71 // Override <cstdlib>
72 
73 extern char* __real_realpath(const char* path, char* resolved_path);
74 
__wrap_realpath(const char * path,char * resolved_path)75 SHIM_ALWAYS_EXPORT char* __wrap_realpath(const char* path,
76                                          char* resolved_path) {
77   if (resolved_path) {
78     return __real_realpath(path, resolved_path);
79   }
80 
81   char buffer[kPathMaxSize];
82   if (!__real_realpath(path, buffer)) {
83     return nullptr;
84   }
85   return __wrap_strdup(buffer);
86 }
87 
88 // Override <cstring> functions
89 
__wrap_strdup(const char * str)90 SHIM_ALWAYS_EXPORT char* __wrap_strdup(const char* str) {
91   std::size_t length = std::strlen(str) + 1;
92   void* buffer = ShimMalloc(length, nullptr);
93   if (!buffer) {
94     return nullptr;
95   }
96   return reinterpret_cast<char*>(std::memcpy(buffer, str, length));
97 }
98 
__wrap_strndup(const char * str,size_t n)99 SHIM_ALWAYS_EXPORT char* __wrap_strndup(const char* str, size_t n) {
100   std::size_t length = std::min(std::strlen(str), n);
101   char* buffer = reinterpret_cast<char*>(ShimMalloc(length + 1, nullptr));
102   if (!buffer) {
103     return nullptr;
104   }
105   std::memcpy(buffer, str, length);
106   buffer[length] = '\0';
107   return buffer;
108 }
109 
110 // Override <unistd.h>
111 
112 extern char* __real_getcwd(char* buffer, size_t size);
113 
__wrap_getcwd(char * buffer,size_t size)114 SHIM_ALWAYS_EXPORT char* __wrap_getcwd(char* buffer, size_t size) {
115   if (buffer) {
116     return __real_getcwd(buffer, size);
117   }
118 
119   if (!size) {
120     size = kPathMaxSize;
121   }
122   char local_buffer[size];
123   if (!__real_getcwd(local_buffer, size)) {
124     return nullptr;
125   }
126   return __wrap_strdup(local_buffer);
127 }
128 
129 // Override stdio.h
130 
131 // This is non-standard (_GNU_SOURCE only), but implemented by Bionic on
132 // Android, and used by libc++.
__wrap_vasprintf(char ** strp,const char * fmt,va_list va_args)133 SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
134                                         const char* fmt,
135                                         va_list va_args) {
136   // There are cases where we need to use the list of arguments twice, namely
137   // when the original buffer is too small. It is not allowed to walk the list
138   // twice, so make a copy for the second invocation of vsnprintf().
139   va_list va_args_copy;
140   va_copy(va_args_copy, va_args);
141 
142   constexpr int kInitialSize = 128;
143   *strp = static_cast<char*>(
144       malloc(kInitialSize));  // Our malloc() doesn't return nullptr.
145 
146   int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args);
147   if (actual_size < 0) {
148     va_end(va_args_copy);
149     return actual_size;
150   }
151   *strp =
152       static_cast<char*>(realloc(*strp, static_cast<size_t>(actual_size + 1)));
153 
154   // Now we know the size. This is not very efficient, but we cannot really do
155   // better without accessing internal libc functions, or reimplementing
156   // *printf().
157   //
158   // This is very lightly used in Chromium in practice, see crbug.com/116558 for
159   // details.
160   if (actual_size >= kInitialSize) {
161     int ret = vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt,
162                         va_args_copy);
163     va_end(va_args_copy);
164     return ret;
165   }
166 
167   va_end(va_args_copy);
168   return actual_size;
169 }
170 
__wrap_asprintf(char ** strp,const char * fmt,...)171 SHIM_ALWAYS_EXPORT int __wrap_asprintf(char** strp, const char* fmt, ...) {
172   va_list va_args;
173   va_start(va_args, fmt);
174   int retval = vasprintf(strp, fmt, va_args);
175   va_end(va_args);
176   return retval;
177 }
178 
179 }  // extern "C"
180 
181 #endif  // BUILDFLAG(USE_ALLOCATOR_SHIM)
182 
183 #endif  // PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
184