13cab2bb3Spatrick //===-- sanitizer_common.cpp ----------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries.
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
133cab2bb3Spatrick #include "sanitizer_common.h"
14*810390e3Srobert
153cab2bb3Spatrick #include "sanitizer_allocator_interface.h"
163cab2bb3Spatrick #include "sanitizer_allocator_internal.h"
173cab2bb3Spatrick #include "sanitizer_atomic.h"
183cab2bb3Spatrick #include "sanitizer_flags.h"
19*810390e3Srobert #include "sanitizer_interface_internal.h"
203cab2bb3Spatrick #include "sanitizer_libc.h"
213cab2bb3Spatrick #include "sanitizer_placement_new.h"
223cab2bb3Spatrick
233cab2bb3Spatrick namespace __sanitizer {
243cab2bb3Spatrick
253cab2bb3Spatrick const char *SanitizerToolName = "SanitizerTool";
263cab2bb3Spatrick
273cab2bb3Spatrick atomic_uint32_t current_verbosity;
283cab2bb3Spatrick uptr PageSizeCached;
293cab2bb3Spatrick u32 NumberOfCPUsCached;
303cab2bb3Spatrick
313cab2bb3Spatrick // PID of the tracer task in StopTheWorld. It shares the address space with the
323cab2bb3Spatrick // main process, but has a different PID and thus requires special handling.
333cab2bb3Spatrick uptr stoptheworld_tracer_pid = 0;
343cab2bb3Spatrick // Cached pid of parent process - if the parent process dies, we want to keep
353cab2bb3Spatrick // writing to the same log file.
363cab2bb3Spatrick uptr stoptheworld_tracer_ppid = 0;
373cab2bb3Spatrick
ReportMmapFailureAndDie(uptr size,const char * mem_type,const char * mmap_type,error_t err,bool raw_report)383cab2bb3Spatrick void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
393cab2bb3Spatrick const char *mmap_type, error_t err,
403cab2bb3Spatrick bool raw_report) {
413cab2bb3Spatrick static int recursion_count;
42d89ec533Spatrick if (raw_report || recursion_count) {
43d89ec533Spatrick // If raw report is requested or we went into recursion just die. The
44d89ec533Spatrick // Report() and CHECK calls below may call mmap recursively and fail.
453cab2bb3Spatrick RawWrite("ERROR: Failed to mmap\n");
463cab2bb3Spatrick Die();
473cab2bb3Spatrick }
483cab2bb3Spatrick recursion_count++;
49*810390e3Srobert if (ErrorIsOOM(err)) {
50*810390e3Srobert ERROR_OOM("failed to %s 0x%zx (%zd) bytes of %s (error code: %d)\n",
51*810390e3Srobert mmap_type, size, size, mem_type, err);
52*810390e3Srobert } else {
53*810390e3Srobert Report(
54*810390e3Srobert "ERROR: %s failed to "
553cab2bb3Spatrick "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
563cab2bb3Spatrick SanitizerToolName, mmap_type, size, size, mem_type, err);
57*810390e3Srobert }
583cab2bb3Spatrick #if !SANITIZER_GO
593cab2bb3Spatrick DumpProcessMap();
603cab2bb3Spatrick #endif
613cab2bb3Spatrick UNREACHABLE("unable to mmap");
623cab2bb3Spatrick }
633cab2bb3Spatrick
643cab2bb3Spatrick typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
653cab2bb3Spatrick typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
663cab2bb3Spatrick
StripPathPrefix(const char * filepath,const char * strip_path_prefix)673cab2bb3Spatrick const char *StripPathPrefix(const char *filepath,
683cab2bb3Spatrick const char *strip_path_prefix) {
693cab2bb3Spatrick if (!filepath) return nullptr;
703cab2bb3Spatrick if (!strip_path_prefix) return filepath;
713cab2bb3Spatrick const char *res = filepath;
723cab2bb3Spatrick if (const char *pos = internal_strstr(filepath, strip_path_prefix))
733cab2bb3Spatrick res = pos + internal_strlen(strip_path_prefix);
743cab2bb3Spatrick if (res[0] == '.' && res[1] == '/')
753cab2bb3Spatrick res += 2;
763cab2bb3Spatrick return res;
773cab2bb3Spatrick }
783cab2bb3Spatrick
StripModuleName(const char * module)793cab2bb3Spatrick const char *StripModuleName(const char *module) {
803cab2bb3Spatrick if (!module)
813cab2bb3Spatrick return nullptr;
823cab2bb3Spatrick if (SANITIZER_WINDOWS) {
833cab2bb3Spatrick // On Windows, both slash and backslash are possible.
843cab2bb3Spatrick // Pick the one that goes last.
853cab2bb3Spatrick if (const char *bslash_pos = internal_strrchr(module, '\\'))
863cab2bb3Spatrick return StripModuleName(bslash_pos + 1);
873cab2bb3Spatrick }
883cab2bb3Spatrick if (const char *slash_pos = internal_strrchr(module, '/')) {
893cab2bb3Spatrick return slash_pos + 1;
903cab2bb3Spatrick }
913cab2bb3Spatrick return module;
923cab2bb3Spatrick }
933cab2bb3Spatrick
ReportErrorSummary(const char * error_message,const char * alt_tool_name)943cab2bb3Spatrick void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
953cab2bb3Spatrick if (!common_flags()->print_summary)
963cab2bb3Spatrick return;
97d89ec533Spatrick InternalScopedString buff;
983cab2bb3Spatrick buff.append("SUMMARY: %s: %s",
993cab2bb3Spatrick alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
1003cab2bb3Spatrick __sanitizer_report_error_summary(buff.data());
1013cab2bb3Spatrick }
1023cab2bb3Spatrick
1033cab2bb3Spatrick // Removes the ANSI escape sequences from the input string (in-place).
RemoveANSIEscapeSequencesFromString(char * str)1043cab2bb3Spatrick void RemoveANSIEscapeSequencesFromString(char *str) {
1053cab2bb3Spatrick if (!str)
1063cab2bb3Spatrick return;
1073cab2bb3Spatrick
1083cab2bb3Spatrick // We are going to remove the escape sequences in place.
1093cab2bb3Spatrick char *s = str;
1103cab2bb3Spatrick char *z = str;
1113cab2bb3Spatrick while (*s != '\0') {
1123cab2bb3Spatrick CHECK_GE(s, z);
1133cab2bb3Spatrick // Skip over ANSI escape sequences with pointer 's'.
1143cab2bb3Spatrick if (*s == '\033' && *(s + 1) == '[') {
1153cab2bb3Spatrick s = internal_strchrnul(s, 'm');
1163cab2bb3Spatrick if (*s == '\0') {
1173cab2bb3Spatrick break;
1183cab2bb3Spatrick }
1193cab2bb3Spatrick s++;
1203cab2bb3Spatrick continue;
1213cab2bb3Spatrick }
1223cab2bb3Spatrick // 's' now points at a character we want to keep. Copy over the buffer
1233cab2bb3Spatrick // content if the escape sequence has been perviously skipped andadvance
1243cab2bb3Spatrick // both pointers.
1253cab2bb3Spatrick if (s != z)
1263cab2bb3Spatrick *z = *s;
1273cab2bb3Spatrick
1283cab2bb3Spatrick // If we have not seen an escape sequence, just advance both pointers.
1293cab2bb3Spatrick z++;
1303cab2bb3Spatrick s++;
1313cab2bb3Spatrick }
1323cab2bb3Spatrick
1333cab2bb3Spatrick // Null terminate the string.
1343cab2bb3Spatrick *z = '\0';
1353cab2bb3Spatrick }
1363cab2bb3Spatrick
set(const char * module_name,uptr base_address)1373cab2bb3Spatrick void LoadedModule::set(const char *module_name, uptr base_address) {
1383cab2bb3Spatrick clear();
1393cab2bb3Spatrick full_name_ = internal_strdup(module_name);
1403cab2bb3Spatrick base_address_ = base_address;
1413cab2bb3Spatrick }
1423cab2bb3Spatrick
set(const char * module_name,uptr base_address,ModuleArch arch,u8 uuid[kModuleUUIDSize],bool instrumented)1433cab2bb3Spatrick void LoadedModule::set(const char *module_name, uptr base_address,
1443cab2bb3Spatrick ModuleArch arch, u8 uuid[kModuleUUIDSize],
1453cab2bb3Spatrick bool instrumented) {
1463cab2bb3Spatrick set(module_name, base_address);
1473cab2bb3Spatrick arch_ = arch;
1483cab2bb3Spatrick internal_memcpy(uuid_, uuid, sizeof(uuid_));
149*810390e3Srobert uuid_size_ = kModuleUUIDSize;
1503cab2bb3Spatrick instrumented_ = instrumented;
1513cab2bb3Spatrick }
1523cab2bb3Spatrick
setUuid(const char * uuid,uptr size)153*810390e3Srobert void LoadedModule::setUuid(const char *uuid, uptr size) {
154*810390e3Srobert if (size > kModuleUUIDSize)
155*810390e3Srobert size = kModuleUUIDSize;
156*810390e3Srobert internal_memcpy(uuid_, uuid, size);
157*810390e3Srobert uuid_size_ = size;
158*810390e3Srobert }
159*810390e3Srobert
clear()1603cab2bb3Spatrick void LoadedModule::clear() {
1613cab2bb3Spatrick InternalFree(full_name_);
1623cab2bb3Spatrick base_address_ = 0;
163*810390e3Srobert max_address_ = 0;
1643cab2bb3Spatrick full_name_ = nullptr;
1653cab2bb3Spatrick arch_ = kModuleArchUnknown;
1663cab2bb3Spatrick internal_memset(uuid_, 0, kModuleUUIDSize);
1673cab2bb3Spatrick instrumented_ = false;
1683cab2bb3Spatrick while (!ranges_.empty()) {
1693cab2bb3Spatrick AddressRange *r = ranges_.front();
1703cab2bb3Spatrick ranges_.pop_front();
1713cab2bb3Spatrick InternalFree(r);
1723cab2bb3Spatrick }
1733cab2bb3Spatrick }
1743cab2bb3Spatrick
addAddressRange(uptr beg,uptr end,bool executable,bool writable,const char * name)1753cab2bb3Spatrick void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
1763cab2bb3Spatrick bool writable, const char *name) {
1773cab2bb3Spatrick void *mem = InternalAlloc(sizeof(AddressRange));
1783cab2bb3Spatrick AddressRange *r =
1793cab2bb3Spatrick new(mem) AddressRange(beg, end, executable, writable, name);
1803cab2bb3Spatrick ranges_.push_back(r);
181*810390e3Srobert max_address_ = Max(max_address_, end);
1823cab2bb3Spatrick }
1833cab2bb3Spatrick
containsAddress(uptr address) const1843cab2bb3Spatrick bool LoadedModule::containsAddress(uptr address) const {
1853cab2bb3Spatrick for (const AddressRange &r : ranges()) {
1863cab2bb3Spatrick if (r.beg <= address && address < r.end)
1873cab2bb3Spatrick return true;
1883cab2bb3Spatrick }
1893cab2bb3Spatrick return false;
1903cab2bb3Spatrick }
1913cab2bb3Spatrick
1923cab2bb3Spatrick static atomic_uintptr_t g_total_mmaped;
1933cab2bb3Spatrick
IncreaseTotalMmap(uptr size)1943cab2bb3Spatrick void IncreaseTotalMmap(uptr size) {
1953cab2bb3Spatrick if (!common_flags()->mmap_limit_mb) return;
1963cab2bb3Spatrick uptr total_mmaped =
1973cab2bb3Spatrick atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
1983cab2bb3Spatrick // Since for now mmap_limit_mb is not a user-facing flag, just kill
1993cab2bb3Spatrick // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
2003cab2bb3Spatrick RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
2013cab2bb3Spatrick }
2023cab2bb3Spatrick
DecreaseTotalMmap(uptr size)2033cab2bb3Spatrick void DecreaseTotalMmap(uptr size) {
2043cab2bb3Spatrick if (!common_flags()->mmap_limit_mb) return;
2053cab2bb3Spatrick atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
2063cab2bb3Spatrick }
2073cab2bb3Spatrick
TemplateMatch(const char * templ,const char * str)2083cab2bb3Spatrick bool TemplateMatch(const char *templ, const char *str) {
2093cab2bb3Spatrick if ((!str) || str[0] == 0)
2103cab2bb3Spatrick return false;
2113cab2bb3Spatrick bool start = false;
2123cab2bb3Spatrick if (templ && templ[0] == '^') {
2133cab2bb3Spatrick start = true;
2143cab2bb3Spatrick templ++;
2153cab2bb3Spatrick }
2163cab2bb3Spatrick bool asterisk = false;
2173cab2bb3Spatrick while (templ && templ[0]) {
2183cab2bb3Spatrick if (templ[0] == '*') {
2193cab2bb3Spatrick templ++;
2203cab2bb3Spatrick start = false;
2213cab2bb3Spatrick asterisk = true;
2223cab2bb3Spatrick continue;
2233cab2bb3Spatrick }
2243cab2bb3Spatrick if (templ[0] == '$')
2253cab2bb3Spatrick return str[0] == 0 || asterisk;
2263cab2bb3Spatrick if (str[0] == 0)
2273cab2bb3Spatrick return false;
2283cab2bb3Spatrick char *tpos = (char*)internal_strchr(templ, '*');
2293cab2bb3Spatrick char *tpos1 = (char*)internal_strchr(templ, '$');
2303cab2bb3Spatrick if ((!tpos) || (tpos1 && tpos1 < tpos))
2313cab2bb3Spatrick tpos = tpos1;
2323cab2bb3Spatrick if (tpos)
2333cab2bb3Spatrick tpos[0] = 0;
2343cab2bb3Spatrick const char *str0 = str;
2353cab2bb3Spatrick const char *spos = internal_strstr(str, templ);
2363cab2bb3Spatrick str = spos + internal_strlen(templ);
2373cab2bb3Spatrick templ = tpos;
2383cab2bb3Spatrick if (tpos)
2393cab2bb3Spatrick tpos[0] = tpos == tpos1 ? '$' : '*';
2403cab2bb3Spatrick if (!spos)
2413cab2bb3Spatrick return false;
2423cab2bb3Spatrick if (start && spos != str0)
2433cab2bb3Spatrick return false;
2443cab2bb3Spatrick start = false;
2453cab2bb3Spatrick asterisk = false;
2463cab2bb3Spatrick }
2473cab2bb3Spatrick return true;
2483cab2bb3Spatrick }
2493cab2bb3Spatrick
2503cab2bb3Spatrick static char binary_name_cache_str[kMaxPathLength];
2513cab2bb3Spatrick static char process_name_cache_str[kMaxPathLength];
2523cab2bb3Spatrick
GetProcessName()2533cab2bb3Spatrick const char *GetProcessName() {
2543cab2bb3Spatrick return process_name_cache_str;
2553cab2bb3Spatrick }
2563cab2bb3Spatrick
ReadProcessName(char * buf,uptr buf_len)2573cab2bb3Spatrick static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
2583cab2bb3Spatrick ReadLongProcessName(buf, buf_len);
2593cab2bb3Spatrick char *s = const_cast<char *>(StripModuleName(buf));
2603cab2bb3Spatrick uptr len = internal_strlen(s);
2613cab2bb3Spatrick if (s != buf) {
2623cab2bb3Spatrick internal_memmove(buf, s, len);
2633cab2bb3Spatrick buf[len] = '\0';
2643cab2bb3Spatrick }
2653cab2bb3Spatrick return len;
2663cab2bb3Spatrick }
2673cab2bb3Spatrick
UpdateProcessName()2683cab2bb3Spatrick void UpdateProcessName() {
2693cab2bb3Spatrick ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
2703cab2bb3Spatrick }
2713cab2bb3Spatrick
2723cab2bb3Spatrick // Call once to make sure that binary_name_cache_str is initialized
CacheBinaryName()2733cab2bb3Spatrick void CacheBinaryName() {
2743cab2bb3Spatrick if (binary_name_cache_str[0] != '\0')
2753cab2bb3Spatrick return;
2763cab2bb3Spatrick ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
2773cab2bb3Spatrick ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
2783cab2bb3Spatrick }
2793cab2bb3Spatrick
ReadBinaryNameCached(char * buf,uptr buf_len)2803cab2bb3Spatrick uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
2813cab2bb3Spatrick CacheBinaryName();
2823cab2bb3Spatrick uptr name_len = internal_strlen(binary_name_cache_str);
2833cab2bb3Spatrick name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
2843cab2bb3Spatrick if (buf_len == 0)
2853cab2bb3Spatrick return 0;
2863cab2bb3Spatrick internal_memcpy(buf, binary_name_cache_str, name_len);
2873cab2bb3Spatrick buf[name_len] = '\0';
2883cab2bb3Spatrick return name_len;
2893cab2bb3Spatrick }
2903cab2bb3Spatrick
ReadBinaryDir(char * buf,uptr buf_len)291d89ec533Spatrick uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
292d89ec533Spatrick ReadBinaryNameCached(buf, buf_len);
293d89ec533Spatrick const char *exec_name_pos = StripModuleName(buf);
294d89ec533Spatrick uptr name_len = exec_name_pos - buf;
295d89ec533Spatrick buf[name_len] = '\0';
296d89ec533Spatrick return name_len;
297d89ec533Spatrick }
298d89ec533Spatrick
2991f9cb04fSpatrick #if !SANITIZER_GO
PrintCmdline()3003cab2bb3Spatrick void PrintCmdline() {
3013cab2bb3Spatrick char **argv = GetArgv();
3023cab2bb3Spatrick if (!argv) return;
3033cab2bb3Spatrick Printf("\nCommand: ");
3043cab2bb3Spatrick for (uptr i = 0; argv[i]; ++i)
3053cab2bb3Spatrick Printf("%s ", argv[i]);
3063cab2bb3Spatrick Printf("\n\n");
3073cab2bb3Spatrick }
3081f9cb04fSpatrick #endif
3093cab2bb3Spatrick
3103cab2bb3Spatrick // Malloc hooks.
3113cab2bb3Spatrick static const int kMaxMallocFreeHooks = 5;
3123cab2bb3Spatrick struct MallocFreeHook {
3133cab2bb3Spatrick void (*malloc_hook)(const void *, uptr);
3143cab2bb3Spatrick void (*free_hook)(const void *);
3153cab2bb3Spatrick };
3163cab2bb3Spatrick
3173cab2bb3Spatrick static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
3183cab2bb3Spatrick
RunMallocHooks(void * ptr,uptr size)319*810390e3Srobert void RunMallocHooks(void *ptr, uptr size) {
320*810390e3Srobert __sanitizer_malloc_hook(ptr, size);
3213cab2bb3Spatrick for (int i = 0; i < kMaxMallocFreeHooks; i++) {
3223cab2bb3Spatrick auto hook = MFHooks[i].malloc_hook;
323*810390e3Srobert if (!hook)
324*810390e3Srobert break;
3253cab2bb3Spatrick hook(ptr, size);
3263cab2bb3Spatrick }
3273cab2bb3Spatrick }
3283cab2bb3Spatrick
RunFreeHooks(void * ptr)329*810390e3Srobert void RunFreeHooks(void *ptr) {
330*810390e3Srobert __sanitizer_free_hook(ptr);
3313cab2bb3Spatrick for (int i = 0; i < kMaxMallocFreeHooks; i++) {
3323cab2bb3Spatrick auto hook = MFHooks[i].free_hook;
333*810390e3Srobert if (!hook)
334*810390e3Srobert break;
3353cab2bb3Spatrick hook(ptr);
3363cab2bb3Spatrick }
3373cab2bb3Spatrick }
3383cab2bb3Spatrick
InstallMallocFreeHooks(void (* malloc_hook)(const void *,uptr),void (* free_hook)(const void *))3393cab2bb3Spatrick static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
3403cab2bb3Spatrick void (*free_hook)(const void *)) {
3413cab2bb3Spatrick if (!malloc_hook || !free_hook) return 0;
3423cab2bb3Spatrick for (int i = 0; i < kMaxMallocFreeHooks; i++) {
3433cab2bb3Spatrick if (MFHooks[i].malloc_hook == nullptr) {
3443cab2bb3Spatrick MFHooks[i].malloc_hook = malloc_hook;
3453cab2bb3Spatrick MFHooks[i].free_hook = free_hook;
3463cab2bb3Spatrick return i + 1;
3473cab2bb3Spatrick }
3483cab2bb3Spatrick }
3493cab2bb3Spatrick return 0;
3503cab2bb3Spatrick }
3513cab2bb3Spatrick
internal_sleep(unsigned seconds)352d89ec533Spatrick void internal_sleep(unsigned seconds) {
353d89ec533Spatrick internal_usleep((u64)seconds * 1000 * 1000);
354d89ec533Spatrick }
SleepForSeconds(unsigned seconds)355d89ec533Spatrick void SleepForSeconds(unsigned seconds) {
356d89ec533Spatrick internal_usleep((u64)seconds * 1000 * 1000);
357d89ec533Spatrick }
SleepForMillis(unsigned millis)358d89ec533Spatrick void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }
359d89ec533Spatrick
WaitForDebugger(unsigned seconds,const char * label)360*810390e3Srobert void WaitForDebugger(unsigned seconds, const char *label) {
361*810390e3Srobert if (seconds) {
362*810390e3Srobert Report("Sleeping for %u second(s) %s\n", seconds, label);
363*810390e3Srobert SleepForSeconds(seconds);
364*810390e3Srobert }
365*810390e3Srobert }
366*810390e3Srobert
3673cab2bb3Spatrick } // namespace __sanitizer
3683cab2bb3Spatrick
3693cab2bb3Spatrick using namespace __sanitizer;
3703cab2bb3Spatrick
3713cab2bb3Spatrick extern "C" {
SANITIZER_INTERFACE_WEAK_DEF(void,__sanitizer_report_error_summary,const char * error_summary)3723cab2bb3Spatrick SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
3733cab2bb3Spatrick const char *error_summary) {
3743cab2bb3Spatrick Printf("%s\n", error_summary);
3753cab2bb3Spatrick }
3763cab2bb3Spatrick
3773cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_acquire_crash_state()3783cab2bb3Spatrick int __sanitizer_acquire_crash_state() {
3793cab2bb3Spatrick static atomic_uint8_t in_crash_state = {};
3803cab2bb3Spatrick return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);
3813cab2bb3Spatrick }
3823cab2bb3Spatrick
3833cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__sanitizer_install_malloc_and_free_hooks(void (* malloc_hook)(const void *,uptr),void (* free_hook)(const void *))3843cab2bb3Spatrick int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
3853cab2bb3Spatrick uptr),
3863cab2bb3Spatrick void (*free_hook)(const void *)) {
3873cab2bb3Spatrick return InstallMallocFreeHooks(malloc_hook, free_hook);
3883cab2bb3Spatrick }
389*810390e3Srobert
390*810390e3Srobert // Provide default (no-op) implementation of malloc hooks.
SANITIZER_INTERFACE_WEAK_DEF(void,__sanitizer_malloc_hook,void * ptr,uptr size)391*810390e3Srobert SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,
392*810390e3Srobert uptr size) {
393*810390e3Srobert (void)ptr;
394*810390e3Srobert (void)size;
395*810390e3Srobert }
396*810390e3Srobert
SANITIZER_INTERFACE_WEAK_DEF(void,__sanitizer_free_hook,void * ptr)397*810390e3Srobert SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
398*810390e3Srobert (void)ptr;
399*810390e3Srobert }
400*810390e3Srobert
4013cab2bb3Spatrick } // extern "C"
402