#include "lsan_common.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flag_parser.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#if CAN_SANITIZE_LEAKS
# if SANITIZER_APPLE
# if SANITIZER_IOS && !SANITIZER_IOSSIM
#define OBJC_DATA_MASK …
# else
#define OBJC_DATA_MASK …
# endif
# endif
namespace __lsan {
static Mutex global_mutex;
void LockGlobal() SANITIZER_ACQUIRE(global_mutex) { … }
void UnlockGlobal() SANITIZER_RELEASE(global_mutex) { … }
Flags lsan_flags;
void DisableCounterUnderflow() { … }
void Flags::SetDefaults() { … }
void RegisterLsanFlags(FlagParser *parser, Flags *f) { … }
#define LOG_POINTERS(...) …
#define LOG_THREADS(...) …
class LeakSuppressionContext { … };
alignas(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
static LeakSuppressionContext *suppression_ctx = …;
static const char kSuppressionLeak[] = …;
static const char *kSuppressionTypes[] = …;
static const char kStdSuppressions[] = …
"leak:*pthread_exit*\n"
# endif
# if SANITIZER_APPLE
"leak:*_os_trace*\n"
# endif
"leak:*tls_get_addr*\n";
void InitializeSuppressions() { … }
void LeakSuppressionContext::LazyInit() { … }
Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) { … }
static uptr GetCallerPC(const StackTrace &stack) { … }
# if SANITIZER_APPLE
static inline void *TransformPointer(void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
return reinterpret_cast<void *>(ptr & OBJC_DATA_MASK);
}
# endif
bool LeakSuppressionContext::SuppressInvalid(const StackTrace &stack) { … }
bool LeakSuppressionContext::SuppressByRule(const StackTrace &stack,
uptr hit_count, uptr total_size) { … }
bool LeakSuppressionContext::Suppress(u32 stack_trace_id, uptr hit_count,
uptr total_size) { … }
static LeakSuppressionContext *GetSuppressionContext() { … }
void InitCommonLsan() { … }
class Decorator : public __sanitizer::SanitizerCommonDecorator { … };
static inline bool MaybeUserPointer(uptr p) { … }
void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
const char *region_type, ChunkTag tag) { … }
void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) { … }
void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
Frontier *frontier) { … }
# if SANITIZER_FUCHSIA
static void ProcessThreads(SuspendedThreadsList const &, Frontier *, tid_t,
uptr) {}
# else
# if SANITIZER_ANDROID
extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
pid_t, void (*cb)(void *, void *, uptr, void *), void *);
# endif
static void ProcessThreadRegistry(Frontier *frontier) { … }
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier, tid_t caller_tid,
uptr caller_sp) { … }
# endif
RootRegions;
static RootRegions &GetRootRegionsLocked() { … }
bool HasRootRegions() { … }
void ScanRootRegions(Frontier *frontier,
const InternalMmapVectorNoCtor<Region> &mapped_regions) { … }
static void ProcessRootRegions(Frontier *frontier) { … }
static void FloodFillTag(Frontier *frontier, ChunkTag tag) { … }
static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) { … }
static void IgnoredSuppressedCb(uptr chunk, void *arg) { … }
static void CollectIgnoredCb(uptr chunk, void *arg) { … }
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
Frontier *frontier, tid_t caller_tid,
uptr caller_sp) { … }
static void ResetTagsCb(uptr chunk, void *arg) { … }
static void CollectLeaksCb(uptr chunk, void *arg) { … }
void LeakSuppressionContext::PrintMatchedSuppressions() { … }
# if SANITIZER_FUCHSIA
static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
# else
static void ReportUnsuspendedThreads(
const SuspendedThreadsList &suspended_threads) { … }
# endif
static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
void *arg) { … }
static bool PrintResults(LeakReport &report) { … }
static bool CheckForLeaks() { … }
static bool has_reported_leaks = …;
bool HasReportedLeaks() { … }
void DoLeakCheck() { … }
static int DoRecoverableLeakCheck() { … }
void DoRecoverableLeakCheckVoid() { … }
const uptr kMaxLeaksConsidered = …;
void LeakReport::AddLeakedChunks(const LeakedChunks &chunks) { … }
static bool LeakComparator(const Leak &leak1, const Leak &leak2) { … }
void LeakReport::ReportTopLeaks(uptr num_leaks_to_report) { … }
void LeakReport::PrintReportForLeak(uptr index) { … }
void LeakReport::PrintLeakedObjectsForLeak(uptr index) { … }
void LeakReport::PrintSummary() { … }
uptr LeakReport::ApplySuppressions() { … }
uptr LeakReport::UnsuppressedLeakCount() { … }
uptr LeakReport::IndirectUnsuppressedLeakCount() { … }
}
#else
namespace __lsan {
void InitCommonLsan() {}
void DoLeakCheck() {}
void DoRecoverableLeakCheckVoid() {}
void DisableInThisThread() {}
void EnableInThisThread() {}
}
#endif
usingnamespace__lsan;
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_ignore_object(const void *p) { … }
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_register_root_region(const void *begin, uptr size) { … }
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_unregister_root_region(const void *begin, uptr size) { … }
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_disable() { … }
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_enable() { … }
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_do_leak_check() { … }
SANITIZER_INTERFACE_ATTRIBUTE
int __lsan_do_recoverable_leak_check() { … }
SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_options, void) { … }
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_INTERFACE_WEAK_DEF(int, __lsan_is_turned_off, void) {
return 0;
}
SANITIZER_INTERFACE_WEAK_DEF(const char *, __lsan_default_suppressions, void) {
return "";
}
#endif
}