#include "lsan_common.h"
#include "lsan_thread.h"
#include "sanitizer_common/sanitizer_platform.h"
#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
#include <zircon/sanitizer.h>
#include "lsan_allocator.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#pragma comment(lib, "zircon")
namespace __lsan {
void InitializePlatformSpecificModules() {}
LoadedModule *GetLinker() { return nullptr; }
__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
bool DisabledInThisThread() { return disable_counter > 0; }
void DisableInThisThread() { disable_counter++; }
void EnableInThisThread() {
if (disable_counter == 0) {
DisableCounterUnderflow();
}
disable_counter--;
}
void ProcessGlobalRegions(Frontier *frontier) {}
void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
void HandleLeaks() {}
bool UseExitcodeOnLeak();
int ExitHook(int status) {
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
if (UseExitcodeOnLeak())
DoLeakCheck();
else
DoRecoverableLeakCheckVoid();
}
return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
}
void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
CheckForLeaksParam *argument) {
ScopedStopTheWorldLock lock;
struct Params {
InternalMmapVector<uptr> allocator_caches;
StopTheWorldCallback callback;
CheckForLeaksParam *argument;
} params = {{}, callback, argument};
auto globals = +[](void *chunk, size_t size, void *data) {
auto params = static_cast<const Params *>(data);
uptr begin = reinterpret_cast<uptr>(chunk);
uptr end = begin + size;
ScanGlobalRange(begin, end, ¶ms->argument->frontier);
};
auto stacks = +[](void *chunk, size_t size, void *data) {
auto params = static_cast<const Params *>(data);
uptr begin = reinterpret_cast<uptr>(chunk);
uptr end = begin + size;
ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "STACK",
kReachable);
};
auto registers = +[](void *chunk, size_t size, void *data) {
auto params = static_cast<const Params *>(data);
uptr begin = reinterpret_cast<uptr>(chunk);
uptr end = begin + size;
ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "REGISTERS",
kReachable);
};
if (flags()->use_tls) {
GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches);
__sanitizer::Sort(params.allocator_caches.data(),
params.allocator_caches.size());
}
auto tls = +[](void *chunk, size_t size, void *data) {
auto params = static_cast<const Params *>(data);
uptr begin = reinterpret_cast<uptr>(chunk);
uptr end = begin + size;
auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
if (i < params->allocator_caches.size() &&
params->allocator_caches[i] >= begin &&
params->allocator_caches[i] <= end &&
end - params->allocator_caches[i] >= sizeof(AllocatorCache)) {
ScanRangeForPointers(begin, params->allocator_caches[i],
¶ms->argument->frontier, "TLS", kReachable);
uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
ScanRangeForPointers(begin2, end, ¶ms->argument->frontier, "TLS",
kReachable);
} else {
ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "TLS",
kReachable);
}
};
__sanitizer_memory_snapshot(
flags()->use_globals ? globals : nullptr,
flags()->use_stacks ? stacks : nullptr,
flags()->use_registers ? registers : nullptr,
flags()->use_tls ? tls : nullptr,
[](zx_status_t, void *data) {
auto params = static_cast<const Params *>(data);
if (flags()->use_stacks) {
InternalMmapVector<Range> ranges;
GetThreadExtraStackRangesLocked(&ranges);
ScanExtraStackRanges(ranges, ¶ms->argument->frontier);
}
params->callback(SuspendedThreadsListFuchsia(), params->argument);
},
¶ms);
}
}
int __sanitizer_process_exit_hook(int status) {
return __lsan::ExitHook(status);
}
#endif