From dbdee7fa667b555d1174e46889b952cc81d3bdf7 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:29:22 +0200 Subject: [PATCH 01/58] Added thread local sanitizer class --- code/threadAllocInfo/ThreadAllocInfo.cpp | 28 +++++++++++++++ code/threadAllocInfo/ThreadAllocInfo.hpp | 45 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 code/threadAllocInfo/ThreadAllocInfo.cpp create mode 100644 code/threadAllocInfo/ThreadAllocInfo.hpp diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp new file mode 100644 index 0000000..056b2e8 --- /dev/null +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -0,0 +1,28 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#include "ThreadAllocInfo.hpp" + +ThreadAllocInfo::ThreadAllocInfo() { + // TODO: Register in the main class +} + +ThreadAllocInfo::~ThreadAllocInfo() { + // TODO: Unregister from the main class +} diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp new file mode 100644 index 0000000..4caa4f2 --- /dev/null +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -0,0 +1,45 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#ifndef ThreadAllocInfo_hpp +#define ThreadAllocInfo_hpp + +#include +#include + +#include "../MallocInfo.hpp" +#include "../Stats.hpp" + +class ThreadAllocInfo { + Stats stats; + std::recursive_mutex statsMutex; + std::map infos; + +public: + ThreadAllocInfo(); + ~ThreadAllocInfo(); + + ThreadAllocInfo(const ThreadAllocInfo &) = delete; + ThreadAllocInfo(ThreadAllocInfo &&) = delete; + + ThreadAllocInfo & operator=(const ThreadAllocInfo &) = delete; + ThreadAllocInfo & operator=(ThreadAllocInfo &&) = delete; +}; + +#endif /* ThreadAllocInfo_hpp */ From b942181acc79499c83d38bf1c0ae96a195f0df19 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:29:30 +0200 Subject: [PATCH 02/58] Updated Xcode settings --- LeakSanitizer.xcodeproj/project.pbxproj | 33 +++++++++++++++++-- .../xcschemes/LeakSanitizer.xcscheme | 2 +- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index b140361..f83e7b0 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -24,6 +24,10 @@ BF23A2DF289ECE6A00B17349 /* lsan_stats.h in Headers */ = {isa = PBXBuildFile; fileRef = BF23A2DD289ECE6A00B17349 /* lsan_stats.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF23A2E2289ED24200B17349 /* Stats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF23A2E0289ED24200B17349 /* Stats.cpp */; }; BF23A2E3289ED24200B17349 /* Stats.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF23A2E1289ED24200B17349 /* Stats.hpp */; }; + BF30D8592A7815E8001D4EBF /* ThreadAllocInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */; }; + BF30D85A2A7815E8001D4EBF /* ThreadAllocInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */; }; + BF30D85B2A7815E8001D4EBF /* ThreadAllocInfo.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */; }; + BF30D85C2A7815E8001D4EBF /* ThreadAllocInfo.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */; }; BF378F932919482E00A4DAA9 /* Stats.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF23A2E1289ED24200B17349 /* Stats.hpp */; }; BF378F962919483900A4DAA9 /* LeakSani.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF72C3C92885CB9E00C7AE5C /* LeakSani.hpp */; }; BF378F992919483B00A4DAA9 /* MallocInfo.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BFBF736428831FC200BC4208 /* MallocInfo.hpp */; }; @@ -64,6 +68,8 @@ BF23A2DD289ECE6A00B17349 /* lsan_stats.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lsan_stats.h; sourceTree = ""; }; BF23A2E0289ED24200B17349 /* Stats.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Stats.cpp; sourceTree = ""; }; BF23A2E1289ED24200B17349 /* Stats.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stats.hpp; sourceTree = ""; }; + BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadAllocInfo.cpp; sourceTree = ""; }; + BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ThreadAllocInfo.hpp; sourceTree = ""; }; BF378FB42919496000A4DAA9 /* libcallstack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcallstack.a; path = CallstackLibrary/libcallstack.a; sourceTree = ""; }; BF49A5D72899599300BC1FFD /* signalHandlers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = signalHandlers.cpp; sourceTree = ""; }; BF49A5D82899599300BC1FFD /* signalHandlers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = signalHandlers.hpp; sourceTree = ""; }; @@ -111,6 +117,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + BF30D8562A78159E001D4EBF /* threadAllocInfo */ = { + isa = PBXGroup; + children = ( + BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */, + BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */, + ); + path = threadAllocInfo; + sourceTree = ""; + }; BF378FB32919496000A4DAA9 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -156,6 +171,7 @@ BF9DD3A428A6761400AEBC17 /* code */ = { isa = PBXGroup; children = ( + BF30D8562A78159E001D4EBF /* threadAllocInfo */, BFAFADC428B4FDA40060076C /* Formatter.cpp */, BFAFADC528B4FDA40060076C /* Formatter.hpp */, BF621FE028A2B61E00414EE4 /* bytePrinter.cpp */, @@ -187,6 +203,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + BF30D85C2A7815E8001D4EBF /* ThreadAllocInfo.hpp in Headers */, BF378FA82919484A00A4DAA9 /* lsan_stats.h in Headers */, BF378FAE2919484E00A4DAA9 /* lsan_internals.h in Headers */, BF0F1353291947C9008F0FCD /* bytePrinter.hpp in Headers */, @@ -206,6 +223,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + BF30D85B2A7815E8001D4EBF /* ThreadAllocInfo.hpp in Headers */, BF23A2DF289ECE6A00B17349 /* lsan_stats.h in Headers */, BF621FDE28A291DE00414EE4 /* lsan_internals.h in Headers */, BFBF736E2883323100BC4208 /* crash.hpp in Headers */, @@ -264,7 +282,8 @@ BF97EB4E28831E5B00DAF1FE /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1160; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = mhahnFr; TargetAttributes = { BF0F131B29194652008F0FCD = { @@ -306,6 +325,7 @@ BF0F133B29194791008F0FCD /* LeakSani.cpp in Sources */, BF0F133E29194794008F0FCD /* Stats.cpp in Sources */, BF0F134129194797008F0FCD /* MallocInfo.cpp in Sources */, + BF30D85A2A7815E8001D4EBF /* ThreadAllocInfo.cpp in Sources */, BF0F1347291947A2008F0FCD /* wrap_malloc.cpp in Sources */, BF0F13442919479B008F0FCD /* warn.cpp in Sources */, BF0F134A291947A6008F0FCD /* crash.cpp in Sources */, @@ -324,6 +344,7 @@ BF23A2DE289ECE6A00B17349 /* lsan_stats.cpp in Sources */, BF621FDD28A291DE00414EE4 /* lsan_internals.cpp in Sources */, BFBF736528831FC200BC4208 /* MallocInfo.cpp in Sources */, + BF30D8592A7815E8001D4EBF /* ThreadAllocInfo.cpp in Sources */, BF72C3CE2885CB9E00C7AE5C /* LeakSani.cpp in Sources */, BFBF736828832C3300BC4208 /* wrap_malloc.cpp in Sources */, BFBF736D2883323100BC4208 /* crash.cpp in Sources */, @@ -340,6 +361,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; @@ -363,6 +385,7 @@ CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; EXECUTABLE_PREFIX = lib; @@ -407,6 +430,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -414,6 +438,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -465,6 +490,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -472,6 +498,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -495,6 +522,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = F9JP96DAHT; EXECUTABLE_PREFIX = lib; GCC_OPTIMIZATION_LEVEL = fast; @@ -512,6 +540,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = F9JP96DAHT; EXECUTABLE_PREFIX = lib; GCC_OPTIMIZATION_LEVEL = fast; diff --git a/LeakSanitizer.xcodeproj/xcshareddata/xcschemes/LeakSanitizer.xcscheme b/LeakSanitizer.xcodeproj/xcshareddata/xcschemes/LeakSanitizer.xcscheme index 35a2466..c4eae54 100644 --- a/LeakSanitizer.xcodeproj/xcshareddata/xcschemes/LeakSanitizer.xcscheme +++ b/LeakSanitizer.xcodeproj/xcshareddata/xcschemes/LeakSanitizer.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 31 Jul 2023 18:53:31 +0200 Subject: [PATCH 03/58] Implemented adding and removing allocations --- code/threadAllocInfo/ThreadAllocInfo.cpp | 31 ++++++++++++++++++++++++ code/threadAllocInfo/ThreadAllocInfo.hpp | 4 +++ 2 files changed, 35 insertions(+) diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 056b2e8..55b2094 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -19,6 +19,8 @@ #include "ThreadAllocInfo.hpp" +#include "../../include/lsan_internals.h" + ThreadAllocInfo::ThreadAllocInfo() { // TODO: Register in the main class } @@ -26,3 +28,32 @@ ThreadAllocInfo::ThreadAllocInfo() { ThreadAllocInfo::~ThreadAllocInfo() { // TODO: Unregister from the main class } + +void ThreadAllocInfo::addMalloc(MallocInfo && info) { + std::lock_guard lock(statsMutex); + + stats += info; + infos.insert_or_assign(info.getPointer(), info); +} + +// TODO: Change malloc + +auto ThreadAllocInfo::removeMalloc(const void * pointer) -> bool { + std::lock_guard lock(statsMutex); + + auto it = infos.find(pointer); + + if (it == infos.end()) { + // TODO: Maybe allocated in another thread? + return false; + } else if (it->second.isDeleted()) { + return false; + } + stats -= it->second; + if (__lsan_trackMemory) { + it->second.setDeleted(true); + } else { + infos.erase(it); + } + return true; +} diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 4caa4f2..70fbdbd 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -40,6 +40,10 @@ class ThreadAllocInfo { ThreadAllocInfo & operator=(const ThreadAllocInfo &) = delete; ThreadAllocInfo & operator=(ThreadAllocInfo &&) = delete; + + void addMalloc(MallocInfo && info); + void changeMalloc(const MallocInfo & info); + auto removeMalloc(const void * pointer) -> bool; }; #endif /* ThreadAllocInfo_hpp */ From 701d9b95668d7747c729edf15c21236f92b13225 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:06:14 +0200 Subject: [PATCH 04/58] Added registering skeleton --- code/LeakSani.hpp | 14 +++++++++++--- code/threadAllocInfo/ThreadAllocInfo.hpp | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index f4cab3f..f4f98a4 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr + * Copyright (C) 2022 - 2023 mhahnFr * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -20,11 +20,14 @@ #ifndef LeakSani_hpp #define LeakSani_hpp +#include #include -#include #include +#include + #include "MallocInfo.hpp" #include "Stats.hpp" +#include "threadAllocInfo/ThreadAllocInfo.hpp" /** * This class manages everything this sanitizer is capable to do. @@ -50,6 +53,8 @@ class LSan { /// Indicates whether the set callstack size had been exceeded during the printing. bool callstackSizeExceeded = false; + std::list threadInfos; + public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. LSan(); @@ -136,6 +141,9 @@ class LSan { */ void setCallstackSizeExceeded(bool exceeded); + void registerThreadAllocInfo(ThreadAllocInfo::CRef info); + void removeThreadAllocInfo(ThreadAllocInfo::CRef info); + /// A pointer to the real `malloc` function. static void * (*malloc) (size_t); /// A pointer to the real `calloc` function. diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 70fbdbd..83d7cd1 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -20,6 +20,7 @@ #ifndef ThreadAllocInfo_hpp #define ThreadAllocInfo_hpp +#include #include #include @@ -32,6 +33,9 @@ class ThreadAllocInfo { std::map infos; public: + using Ref = std::reference_wrapper; + using CRef = std::reference_wrapper; + ThreadAllocInfo(); ~ThreadAllocInfo(); From 5dd16b13ec0cc9f3234c1125affb2d80fc0da31a Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:40:37 +0200 Subject: [PATCH 05/58] Added possibility to summarize the stats --- code/Stats.cpp | 21 +++++++++++++++++++-- code/Stats.hpp | 6 ++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/code/Stats.cpp b/code/Stats.cpp index 4c333bb..1fa4b76 100644 --- a/code/Stats.cpp +++ b/code/Stats.cpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr + * Copyright (C) 2022 - 2023 mhahnFr * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -117,6 +117,23 @@ Stats & Stats::operator+=(const MallocInfo & mInfo) { return *this; } +auto Stats::operator+=(Stats & other) -> Stats & { + std::lock_guard lock(mutex); + std::lock_guard lock_other(other.mutex); + + currentMallocCount += other.currentMallocCount; + totalMallocCount += other.totalMallocCount; + peekMallocCount += other.peekMallocCount; + + currentBytes += other.currentBytes; + totalBytes += other.totalBytes; + peekBytes += other.peekBytes; + + freeCount += other.freeCount; + + return *this; +} + Stats Stats::operator-(const MallocInfo & mInfo) { Stats old = *this; old.addFree(mInfo); diff --git a/code/Stats.hpp b/code/Stats.hpp index 2348859..4efc822 100644 --- a/code/Stats.hpp +++ b/code/Stats.hpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr + * Copyright (C) 2022 - 2023 mhahnFr * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -23,6 +23,7 @@ #include #include #include + #include "MallocInfo.hpp" /// This class contains all statistics that this sanitizer produces. @@ -174,6 +175,7 @@ class Stats { * @return this instance */ auto operator+=(const MallocInfo & info) -> Stats &; + auto operator+=(Stats & other) -> Stats &; /** * Removes the given allocation record from a copy of this instance and returns From 287e76b129e7b255276d1adb927aa2e2f9b6dd04 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:43:04 +0200 Subject: [PATCH 06/58] Implemented registering and deregistering of the new allocation tracker --- code/LeakSani.cpp | 30 +++++++++++++++++++++--- code/LeakSani.hpp | 6 ++--- code/threadAllocInfo/ThreadAllocInfo.cpp | 6 +++-- code/threadAllocInfo/ThreadAllocInfo.hpp | 8 +++++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index dc7cece..4b756a1 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -1,5 +1,5 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * * Copyright (C) 2022 - 2023 mhahnFr and contributors * @@ -18,14 +18,18 @@ */ #include + #include #include + #include "LeakSani.hpp" + #include "Formatter.hpp" -#include "signalHandlers.hpp" #include "bytePrinter.hpp" -#include "../include/lsan_stats.h" +#include "signalHandlers.hpp" + #include "../include/lsan_internals.h" +#include "../include/lsan_stats.h" bool __lsan_printStatsOnExit = false; @@ -81,6 +85,26 @@ LSan::LSan() { stats = &realStats; } +void LSan::registerThreadAllocInfo(ThreadAllocInfo::CRef info) { + std::lock_guard lock(infoMutex); + + threadInfos.push_back(info); +} + +void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { + std::lock_guard lock(infoMutex); + + realStats += info.get().getStats(); + infos.merge(info.get().getInfos()); + + auto it = std::find_if(threadInfos.cbegin(), threadInfos.cend(), [&info] (const auto & elem) { + return std::addressof(elem.get()) == std::addressof(info.get()); + }); + if (it != threadInfos.end()) { + threadInfos.erase(it); + } +} + void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } void LSan::addMalloc(MallocInfo && mInfo) { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index f4f98a4..3e22749 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -20,10 +20,10 @@ #ifndef LeakSani_hpp #define LeakSani_hpp -#include #include #include #include +#include #include "MallocInfo.hpp" #include "Stats.hpp" @@ -53,7 +53,7 @@ class LSan { /// Indicates whether the set callstack size had been exceeded during the printing. bool callstackSizeExceeded = false; - std::list threadInfos; + std::vector threadInfos; public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. @@ -142,7 +142,7 @@ class LSan { void setCallstackSizeExceeded(bool exceeded); void registerThreadAllocInfo(ThreadAllocInfo::CRef info); - void removeThreadAllocInfo(ThreadAllocInfo::CRef info); + void removeThreadAllocInfo(ThreadAllocInfo::Ref info); /// A pointer to the real `malloc` function. static void * (*malloc) (size_t); diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 55b2094..200193e 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -19,14 +19,16 @@ #include "ThreadAllocInfo.hpp" +#include "../LeakSani.hpp" + #include "../../include/lsan_internals.h" ThreadAllocInfo::ThreadAllocInfo() { - // TODO: Register in the main class + LSan::getInstance().registerThreadAllocInfo(*this); } ThreadAllocInfo::~ThreadAllocInfo() { - // TODO: Unregister from the main class + LSan::getInstance().removeThreadAllocInfo(*this); } void ThreadAllocInfo::addMalloc(MallocInfo && info) { diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 83d7cd1..525e063 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -48,6 +48,14 @@ class ThreadAllocInfo { void addMalloc(MallocInfo && info); void changeMalloc(const MallocInfo & info); auto removeMalloc(const void * pointer) -> bool; + + constexpr inline auto getStats() -> Stats & { + return stats; + } + + constexpr inline auto getInfos() -> std::map & { + return infos; + } }; #endif /* ThreadAllocInfo_hpp */ From 3a7d760abf9f10db21dbcf5761f57c7699b3db2e Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:52:09 +0200 Subject: [PATCH 07/58] Removed unneeded methods, small improvements --- code/Stats.cpp | 34 +++++++++++++++++++--------------- code/Stats.hpp | 20 ++------------------ 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/code/Stats.cpp b/code/Stats.cpp index 1fa4b76..4252391 100644 --- a/code/Stats.cpp +++ b/code/Stats.cpp @@ -20,10 +20,26 @@ #include "Stats.hpp" Stats::Stats(const Stats & other) - : mutex(), currentMallocCount(other.currentMallocCount), totalMallocCount(other.totalMallocCount), peekMallocCount(other.peekMallocCount), currentBytes(other.currentBytes), totalBytes(other.totalBytes), peekBytes(other.peekBytes), freeCount(other.freeCount) {} + : mutex(), + currentMallocCount(other.currentMallocCount), + totalMallocCount(other.totalMallocCount), + peekMallocCount(other.peekMallocCount), + currentBytes(other.currentBytes), + totalBytes(other.totalBytes), + peekBytes(other.peekBytes), + freeCount(other.freeCount) +{} Stats::Stats(Stats && other) - : mutex(), currentMallocCount(std::move(other.currentMallocCount)), totalMallocCount(std::move(other.totalMallocCount)), peekMallocCount(std::move(other.peekMallocCount)), currentBytes(std::move(other.currentBytes)), totalBytes(std::move(other.totalBytes)), peekBytes(std::move(other.peekBytes)), freeCount(std::move(other.freeCount)) {} + : mutex(), + currentMallocCount(std::move(other.currentMallocCount)), + totalMallocCount(std::move(other.totalMallocCount)), + peekMallocCount(std::move(other.peekMallocCount)), + currentBytes(std::move(other.currentBytes)), + totalBytes(std::move(other.totalBytes)), + peekBytes(std::move(other.peekBytes)), + freeCount(std::move(other.freeCount)) +{} Stats & Stats::operator=(const Stats & other) { if (&other != this) { @@ -106,18 +122,12 @@ void Stats::addFree(size_t size) { currentBytes -= size; } -Stats Stats::operator+(const MallocInfo & minfo) { - Stats old = *this; - old.addMalloc(minfo); - return old; -} - Stats & Stats::operator+=(const MallocInfo & mInfo) { addMalloc(mInfo); return *this; } -auto Stats::operator+=(Stats & other) -> Stats & { +auto Stats::operator+=(const Stats & other) -> Stats & { std::lock_guard lock(mutex); std::lock_guard lock_other(other.mutex); @@ -134,12 +144,6 @@ auto Stats::operator+=(Stats & other) -> Stats & { return *this; } -Stats Stats::operator-(const MallocInfo & mInfo) { - Stats old = *this; - old.addFree(mInfo); - return old; -} - Stats & Stats::operator-=(const MallocInfo & mInfo) { addFree(mInfo); return *this; diff --git a/code/Stats.hpp b/code/Stats.hpp index 4efc822..4b23af4 100644 --- a/code/Stats.hpp +++ b/code/Stats.hpp @@ -29,7 +29,7 @@ /// This class contains all statistics that this sanitizer produces. class Stats { /// The mutex used to protect the statistics. - std::mutex mutex; + mutable std::mutex mutex; /// The count of currently active allocations. size_t currentMallocCount = 0, @@ -161,13 +161,6 @@ class Stats { */ void addFree(const MallocInfo & info); - /** - * Adds the given allocation record to a copy of this instance and returns that copy. - * - * @param info the allocation record to append to the copy - * @return the result of the calculation - */ - auto operator+ (const MallocInfo & info) -> Stats; /** * Adds the given allocation record to this instance and returns itself. * @@ -175,16 +168,7 @@ class Stats { * @return this instance */ auto operator+=(const MallocInfo & info) -> Stats &; - auto operator+=(Stats & other) -> Stats &; - - /** - * Removes the given allocation record from a copy of this instance and returns - * that copy. - * - * @param info the allocation record to substract from the copy - * @return the result of te calculation - */ - auto operator- (const MallocInfo & info) -> Stats; + auto operator+=(const Stats & other) -> Stats &; /** * Removes the given allocation record from this instance and returns itself. * From 5f9ba530087c6ba9b33b16852a07b7c5147542de Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:58:50 +0200 Subject: [PATCH 08/58] Added mutex protection in the stats getters --- code/Stats.cpp | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/code/Stats.cpp b/code/Stats.cpp index 4252391..1d52650 100644 --- a/code/Stats.cpp +++ b/code/Stats.cpp @@ -71,15 +71,47 @@ Stats & Stats::operator=(Stats && other) { return *this; } -size_t Stats::getCurrentMallocCount() const { return currentMallocCount; } -size_t Stats::getTotalMallocCount() const { return totalMallocCount; } -size_t Stats::getMallocPeek() const { return peekMallocCount; } +auto Stats::getCurrentMallocCount() const -> std::size_t { + std::lock_guard lock(mutex); + + return currentMallocCount; +} -size_t Stats::getCurrentBytes() const { return currentBytes; } -size_t Stats::getTotalBytes() const { return totalBytes; } -size_t Stats::getBytePeek() const { return peekBytes; } +auto Stats::getTotalMallocCount() const -> std::size_t { + std::lock_guard lock(mutex); + + return totalMallocCount; +} -size_t Stats::getTotalFreeCount() const { return freeCount; } +auto Stats::getMallocPeek() const -> std::size_t { + std::lock_guard lock(mutex); + + return peekMallocCount; +} + +auto Stats::getCurrentBytes() const -> std::size_t { + std::lock_guard lock(mutex); + + return currentBytes; +} + +auto Stats::getTotalBytes() const -> std::size_t { + std::lock_guard lock(mutex); + + return totalBytes; +} + +auto Stats::getBytePeek() const -> std::size_t { + std::lock_guard lock(mutex); + + return peekBytes; +} + +auto Stats::getTotalFreeCount() const -> std::size_t { + std::lock_guard lock(mutex); + + return freeCount; +} void Stats::addFree (const MallocInfo & mInfo) { addFree(mInfo.getSize()); } void Stats::addMalloc(const MallocInfo & mInfo) { addMalloc(mInfo.getSize()); } From 28aeab2a67a4fc3182ab2b2326e807eecccfe344 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:41:18 +0200 Subject: [PATCH 09/58] Making use of the std namespace for `size_t` --- code/Stats.cpp | 14 +++++++------- code/Stats.hpp | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/Stats.cpp b/code/Stats.cpp index 1d52650..ff5dbaf 100644 --- a/code/Stats.cpp +++ b/code/Stats.cpp @@ -116,8 +116,8 @@ auto Stats::getTotalFreeCount() const -> std::size_t { void Stats::addFree (const MallocInfo & mInfo) { addFree(mInfo.getSize()); } void Stats::addMalloc(const MallocInfo & mInfo) { addMalloc(mInfo.getSize()); } -void Stats::addMalloc(size_t size) { - std::lock_guard lock(mutex); +void Stats::addMalloc(std::size_t size) { + std::lock_guard lock(mutex); ++currentMallocCount; ++totalMallocCount; @@ -132,8 +132,8 @@ void Stats::addMalloc(size_t size) { } } -void Stats::replaceMalloc(size_t oldSize, size_t newSize) { - std::lock_guard lock(mutex); +void Stats::replaceMalloc(std::size_t oldSize, std::size_t newSize) { + std::lock_guard lock(mutex); currentBytes -= oldSize; currentBytes += newSize; @@ -145,8 +145,8 @@ void Stats::replaceMalloc(size_t oldSize, size_t newSize) { } } -void Stats::addFree(size_t size) { - std::lock_guard lock(mutex); +void Stats::addFree(std::size_t size) { + std::lock_guard lock(mutex); ++freeCount; @@ -165,7 +165,7 @@ auto Stats::operator+=(const Stats & other) -> Stats & { currentMallocCount += other.currentMallocCount; totalMallocCount += other.totalMallocCount; - peekMallocCount += other.peekMallocCount; + peekMallocCount += other.peekMallocCount; // FIXME: Revisit peek calculation! currentBytes += other.currentBytes; totalBytes += other.totalBytes; diff --git a/code/Stats.hpp b/code/Stats.hpp index 4b23af4..ce72974 100644 --- a/code/Stats.hpp +++ b/code/Stats.hpp @@ -32,21 +32,21 @@ class Stats { mutable std::mutex mutex; /// The count of currently active allocations. - size_t currentMallocCount = 0, + std::size_t currentMallocCount = 0, /// The total count of allocations tracked by this sanitizer. totalMallocCount = 0, /// The maximal count of active allocations at one time. peekMallocCount = 0; /// The count of currently allocated bytes. - size_t currentBytes = 0, + std::size_t currentBytes = 0, /// The total count of allocated bytes tracked by this sanitizer. totalBytes = 0, /// The maximal count of active allocated bytes at one time. peekBytes = 0; /// The count of deallocations tracked by this sanitizer. - size_t freeCount = 0; + std::size_t freeCount = 0; public: Stats() = default; @@ -83,45 +83,45 @@ class Stats { * * @return the count of currently active allocations */ - auto getCurrentMallocCount() const -> size_t; + auto getCurrentMallocCount() const -> std::size_t; /** * Returns the total count of tracked allocations. * * @return the total count of allocations */ - auto getTotalMallocCount() const -> size_t; + auto getTotalMallocCount() const -> std::size_t; /** * Returns the maximal count of allocations active at one time. * * @return the peek of allocations */ - auto getMallocPeek() const -> size_t; + auto getMallocPeek() const -> std::size_t; /** * Returns the count of currently allocated bytes. * * @return the amount of currently allocated bytes */ - auto getCurrentBytes() const -> size_t; + auto getCurrentBytes() const -> std::size_t; /** * Returns the total count of allocated bytes tracked by this sanitizer. * * @return the total count of tracked allocated bytes */ - auto getTotalBytes() const -> size_t; + auto getTotalBytes() const -> std::size_t; /** * Returns the maximal count of allocated bytes active at one time. * * @return the peek of allocated bytes at one time */ - auto getBytePeek() const -> size_t; + auto getBytePeek() const -> std::size_t; /** * Returns the total count of deallocations tracked by this sanitizer. * * @return the total count of deallocations */ - auto getTotalFreeCount() const -> size_t; + auto getTotalFreeCount() const -> std::size_t; /** * Adds the given size to the tracked allocations. @@ -130,7 +130,7 @@ class Stats { * * @param size the size of the allocated object */ - void addMalloc(size_t size); + void addMalloc(std::size_t size); /** * Adds the given allocation record to the tracked allocations. * @@ -144,7 +144,7 @@ class Stats { * @param oldSize the size to substract * @param newSize the size to add */ - void replaceMalloc(size_t oldSize, size_t newSize); + void replaceMalloc(std::size_t oldSize, std::size_t newSize); /** * Adds a deallocation to the statistics. @@ -153,7 +153,7 @@ class Stats { * * @param size the size to of the deallocated object */ - void addFree(size_t size); + void addFree(std::size_t size); /** * Adds a deallocation to the statistics. * From fd2147cf70a7677b3e7920b7747112c06ad7a423 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:43:11 +0200 Subject: [PATCH 10/58] Renamed the mutex --- code/threadAllocInfo/ThreadAllocInfo.cpp | 4 ++-- code/threadAllocInfo/ThreadAllocInfo.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 200193e..95088bd 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -32,7 +32,7 @@ ThreadAllocInfo::~ThreadAllocInfo() { } void ThreadAllocInfo::addMalloc(MallocInfo && info) { - std::lock_guard lock(statsMutex); + std::lock_guard lock(infosMutex); stats += info; infos.insert_or_assign(info.getPointer(), info); @@ -41,7 +41,7 @@ void ThreadAllocInfo::addMalloc(MallocInfo && info) { // TODO: Change malloc auto ThreadAllocInfo::removeMalloc(const void * pointer) -> bool { - std::lock_guard lock(statsMutex); + std::lock_guard lock(infosMutex); auto it = infos.find(pointer); diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 525e063..2a13a85 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -29,7 +29,7 @@ class ThreadAllocInfo { Stats stats; - std::recursive_mutex statsMutex; + std::recursive_mutex infosMutex; std::map infos; public: From 33f4849e96260973c77524edb81fc75a29d717fb Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:01:06 +0200 Subject: [PATCH 11/58] Added thread local ThreadAllocInfos, moved the ignoration flag --- code/LeakSani.cpp | 5 +++++ code/LeakSani.hpp | 1 + code/threadAllocInfo/ThreadAllocInfo.hpp | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 4b756a1..9a7097e 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -65,6 +65,11 @@ LSan & LSan::getInstance() { return *instance; } +auto LSan::getLocalInstance() -> ThreadAllocInfo & { + static thread_local ThreadAllocInfo localInfo; + return localInfo; +} + bool & LSan::getIgnoreMalloc() { static thread_local bool ignore = false; return ignore; diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 3e22749..766a1cc 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -161,6 +161,7 @@ class LSan { * @return the current instance */ static auto getInstance() -> LSan &; + static auto getLocalInstance() -> ThreadAllocInfo &; /** * Returns the current instance of the statitcs object. * diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 2a13a85..32939a8 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -31,6 +31,7 @@ class ThreadAllocInfo { Stats stats; std::recursive_mutex infosMutex; std::map infos; + bool ignoreMalloc; public: using Ref = std::reference_wrapper; @@ -49,6 +50,14 @@ class ThreadAllocInfo { void changeMalloc(const MallocInfo & info); auto removeMalloc(const void * pointer) -> bool; + constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { + this->ignoreMalloc = ignoreMalloc; + } + + constexpr inline auto getIgnoreMalloc() const -> bool { + return ignoreMalloc; + } + constexpr inline auto getStats() -> Stats & { return stats; } From 597a5be35576ac5bef0cd994cc8336c25997b44a Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:29:35 +0200 Subject: [PATCH 12/58] Replaced the memory tracker everywhere --- code/LeakSani.cpp | 2 +- code/lsan_stats.cpp | 22 +++-- code/signalHandlers.cpp | 13 ++- code/threadAllocInfo/ThreadAllocInfo.hpp | 4 + code/wrap_malloc.cpp | 117 +++++++++++++---------- 5 files changed, 95 insertions(+), 63 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 9a7097e..4e14e79 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -193,7 +193,7 @@ std::recursive_mutex & LSan::getInfoMutex() { return void LSan::__exit_hook() { using Formatter::Style; - setIgnoreMalloc(true); + getLocalInstance().setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl << Formatter::get(Style::GREEN) << "Exiting" << Formatter::clear(Style::GREEN) diff --git a/code/lsan_stats.cpp b/code/lsan_stats.cpp index 3db6417..a0f6d0d 100644 --- a/code/lsan_stats.cpp +++ b/code/lsan_stats.cpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr + * Copyright (C) 2022 - 2023 mhahnFr * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -298,8 +298,11 @@ static inline void __lsan_printFragmentationByteBar(size_t width, std::ostream & void __lsan_printFragmentationStatsWithWidth(size_t width) { using Formatter::Style; - bool ignore = LSan::ignoreMalloc(); - LSan::setIgnoreMalloc(true); + + auto & instance = LSan::getLocalInstance(); + + bool ignore = instance.getIgnoreMalloc(); + instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; if (__lsan_fragmentationStatsAvailable()) { __lsan_printStatsCore("memory fragmentation", width, out, @@ -318,14 +321,17 @@ void __lsan_printFragmentationStatsWithWidth(size_t width) { << Formatter::clearAll() << std::endl; } if (!ignore) { - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } } void __lsan_printStatsWithWidth(size_t width) { using Formatter::Style; - bool ignore = LSan::ignoreMalloc(); - LSan::setIgnoreMalloc(true); + + auto & instance = LSan::getLocalInstance(); + + bool ignore = instance.getIgnoreMalloc(); + instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; if (__lsan_statsAvailable()) { __lsan_printStatsCore("memory usage", width, out, @@ -338,6 +344,6 @@ void __lsan_printStatsWithWidth(size_t width) { << std::endl; } if (!ignore) { - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } } diff --git a/code/signalHandlers.cpp b/code/signalHandlers.cpp index d515408..d664467 100644 --- a/code/signalHandlers.cpp +++ b/code/signalHandlers.cpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr + * Copyright (C) 2022 - 2023 mhahnFr * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -65,8 +65,11 @@ static std::string signalString(int signal) { void callstackSignal(int) { using Formatter::Style; - bool ignore = LSan::ignoreMalloc(); - LSan::setIgnoreMalloc(true); + + auto & instance = LSan::getLocalInstance(); + bool ignore = instance.getIgnoreMalloc(); + + instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << Formatter::get(Style::ITALIC) << "The current callstack:" @@ -75,7 +78,7 @@ void callstackSignal(int) { MallocInfo::printCallstack(lcs::callstack(), out); out << std::endl; if (!ignore) { - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } } diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 32939a8..88a38e8 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -50,6 +50,10 @@ class ThreadAllocInfo { void changeMalloc(const MallocInfo & info); auto removeMalloc(const void * pointer) -> bool; + constexpr auto removeMalloc(MallocInfo && info) -> bool { + return removeMalloc(info.getPointer()); + } + constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { this->ignoreMalloc = ignoreMalloc; } diff --git a/code/wrap_malloc.cpp b/code/wrap_malloc.cpp index 230f71a..206a0cb 100644 --- a/code/wrap_malloc.cpp +++ b/code/wrap_malloc.cpp @@ -1,5 +1,5 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * * Copyright (C) 2022 - 2023 mhahnFr and contributors * @@ -17,14 +17,16 @@ * this library, see the file LICENSE. If not, see . */ +#include + #include "wrap_malloc.hpp" + #include "crash.hpp" #include "warn.hpp" #include "LeakSani.hpp" #include "Formatter.hpp" #include "../include/lsan_stats.h" #include "../include/lsan_internals.h" -#include #ifdef __GLIBC__ bool __lsan_glibc = true; @@ -32,10 +34,12 @@ bool __lsan_glibc = true; bool __lsan_glibc = false; #endif -void * __wrap_malloc(size_t size, const char * file, int line) { - void * ret = LSan::malloc(size); - if (ret != nullptr && !LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); +auto __wrap_malloc(std::size_t size, const char * file, int line) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ret = LSan::malloc(size); + + if (ret != nullptr && !instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (size == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", file, line, __builtin_return_address(0)); @@ -43,16 +47,18 @@ void * __wrap_malloc(size_t size, const char * file, int line) { crash("Invalid allocation of size 0", file, line, __builtin_return_address(0)); } } - LSan::getInstance().addMalloc(MallocInfo(ret, size, file, line, __builtin_return_address(0))); - LSan::setIgnoreMalloc(false); + instance.addMalloc(MallocInfo(ret, size, file, line, __builtin_return_address(0))); + instance.setIgnoreMalloc(false); } return ret; } -void * __wrap_calloc(size_t objectSize, size_t count, const char * file, int line) { - void * ret = LSan::calloc(objectSize, count); - if (ret != nullptr && !LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); +auto __wrap_calloc(std::size_t objectSize, std::size_t count, const char * file, int line) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ret = LSan::calloc(objectSize, count); + + if (ret != nullptr && !instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (objectSize * count == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", file, line, __builtin_return_address(0)); @@ -60,41 +66,44 @@ void * __wrap_calloc(size_t objectSize, size_t count, const char * file, int lin crash("Invalid allocation of size 0", file, line, __builtin_return_address(0)); } } - LSan::getInstance().addMalloc(MallocInfo(ret, objectSize * count, file, line, __builtin_return_address(0))); - LSan::setIgnoreMalloc(false); + instance.addMalloc(MallocInfo(ret, objectSize * count, file, line, __builtin_return_address(0))); + instance.setIgnoreMalloc(false); } return ret; } -void * __wrap_realloc(void * pointer, size_t size, const char * file, int line) { - bool ignored = LSan::ignoreMalloc(); +auto __wrap_realloc(void * pointer, std::size_t size, const char * file, int line) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ignored = instance.getIgnoreMalloc(); if (!ignored) { - LSan::setIgnoreMalloc(true); + instance.setIgnoreMalloc(true); } void * ptr = LSan::realloc(pointer, size); if (!ignored) { if (ptr != nullptr) { if (pointer != ptr) { if (pointer != nullptr) { - LSan::getInstance().removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); + instance.removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); } - LSan::getInstance().addMalloc(MallocInfo(ptr, size, file, line, __builtin_return_address(0))); + instance.addMalloc(MallocInfo(ptr, size, file, line, __builtin_return_address(0))); } else { - LSan::getInstance().changeMalloc(MallocInfo(ptr, size, file, line, __builtin_return_address(0))); + instance.changeMalloc(MallocInfo(ptr, size, file, line, __builtin_return_address(0))); } } - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } return ptr; } void __wrap_free(void * pointer, const char * file, int line) { - if (!LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); + auto & instance = LSan::getLocalInstance(); + + if (!instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (pointer == nullptr && __lsan_freeNull) { warn("Free of NULL", file, line, __builtin_return_address(0)); } - bool removed = LSan::getInstance().removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); + bool removed = instance.removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); if (__lsan_invalidFree && !removed) { if (__lsan_invalidCrash) { crash("Invalid free", file, line, __builtin_return_address(0)); @@ -102,14 +111,17 @@ void __wrap_free(void * pointer, const char * file, int line) { warn("Invalid free", file, line, __builtin_return_address(0)); } } - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } LSan::free(pointer); } [[ noreturn ]] void __wrap_exit(int code, const char * file, int line) { using Formatter::Style; - LSan::setIgnoreMalloc(true); + + auto & instance = LSan::getLocalInstance(); + + instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl << Formatter::get(Style::GREEN) << "Exiting" << Formatter::clear(Style::GREEN) << " at " @@ -126,10 +138,12 @@ void __wrap_free(void * pointer, const char * file, int line) { __builtin_unreachable(); } -void * malloc(size_t size) { - void * ptr = LSan::malloc(size); - if (ptr != nullptr && !LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); +auto malloc(std::size_t size) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ptr = LSan::malloc(size); + + if (ptr != nullptr && !instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (size == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", __builtin_return_address(0)); @@ -137,16 +151,18 @@ void * malloc(size_t size) { crash("Invalid allocation of size 0", __builtin_return_address(0)); } } - LSan::getInstance().addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); - LSan::setIgnoreMalloc(false); + instance.addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); + instance.setIgnoreMalloc(false); } return ptr; } -void * calloc(size_t objectSize, size_t count) { - void * ptr = LSan::calloc(objectSize, count); - if (ptr != nullptr && !LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); +auto calloc(std::size_t objectSize, std::size_t count) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ptr = LSan::calloc(objectSize, count); + + if (ptr != nullptr && !instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (objectSize * count == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", __builtin_return_address(0)); @@ -154,41 +170,44 @@ void * calloc(size_t objectSize, size_t count) { crash("Invalid allocation of size 0", __builtin_return_address(0)); } } - LSan::getInstance().addMalloc(MallocInfo(ptr, objectSize * count, __builtin_return_address(0))); - LSan::setIgnoreMalloc(false); + instance.addMalloc(MallocInfo(ptr, objectSize * count, __builtin_return_address(0))); + instance.setIgnoreMalloc(false); } return ptr; } -void * realloc(void * pointer, size_t size) { - bool ignored = LSan::ignoreMalloc(); +auto realloc(void * pointer, std::size_t size) -> void * { + auto & instance = LSan::getLocalInstance(); + auto ignored = instance.getIgnoreMalloc(); if (!ignored) { - LSan::setIgnoreMalloc(true); + instance.setIgnoreMalloc(true); } void * ptr = LSan::realloc(pointer, size); if (!ignored) { if (ptr != nullptr) { if (pointer != ptr) { if (pointer != nullptr) { - LSan::getInstance().removeMalloc(pointer); + instance.removeMalloc(pointer); } - LSan::getInstance().addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); + instance.addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); } else { - LSan::getInstance().changeMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); + instance.changeMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); } } - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } return ptr; } void free(void * pointer) { - if (!LSan::ignoreMalloc()) { - LSan::setIgnoreMalloc(true); + auto & instance = LSan::getLocalInstance(); + + if (!instance.getIgnoreMalloc()) { + instance.setIgnoreMalloc(true); if (pointer == nullptr && __lsan_freeNull) { warn("Free of NULL", __builtin_return_address(0)); } - bool removed = LSan::getInstance().removeMalloc(pointer); + bool removed = instance.removeMalloc(pointer); if (__lsan_invalidFree && !removed) { if (__lsan_invalidCrash) { crash("Invalid free", __builtin_return_address(0)); @@ -196,7 +215,7 @@ void free(void * pointer) { warn("Invalid free", __builtin_return_address(0)); } } - LSan::setIgnoreMalloc(false); + instance.setIgnoreMalloc(false); } LSan::free(pointer); } From 449198ff02a4d61a3e3a522620e9fbfe92651961 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:35:41 +0200 Subject: [PATCH 13/58] Implemented basic malloc changing --- code/threadAllocInfo/ThreadAllocInfo.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 95088bd..d474f86 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -38,7 +38,26 @@ void ThreadAllocInfo::addMalloc(MallocInfo && info) { infos.insert_or_assign(info.getPointer(), info); } -// TODO: Change malloc +void ThreadAllocInfo::changeMalloc(const MallocInfo & info) { + std::lock_guard lock(infosMutex); + + auto it = infos.find(info.getPointer()); + if (it == infos.end()) { + // TODO: Maybe allocated in another thread? + stats += info; + } else { + if (it->second.getPointer() != info.getPointer()) { + stats -= it->second; + stats += info; + } else { + stats.replaceMalloc(it->second.getSize(), info.getSize()); + } + if (__lsan_trackMemory) { + it->second.setDeleted(true); + } + infos.insert_or_assign(info.getPointer(), info); + } +} auto ThreadAllocInfo::removeMalloc(const void * pointer) -> bool { std::lock_guard lock(infosMutex); From ac96020a77dd4fa875a6a09bc9a62e634ad14a8a Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:41:01 +0200 Subject: [PATCH 14/58] Removed unneeded tracking methods --- code/LeakSani.cpp | 55 ----------------------------------------------- code/LeakSani.hpp | 54 ---------------------------------------------- 2 files changed, 109 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 4e14e79..54f0614 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -58,7 +58,6 @@ Stats * LSan::stats = nullptr; Stats & LSan::getStats() { return *LSan::stats; } bool LSan::hasStats() { return LSan::stats != nullptr; } -bool LSan::ignoreMalloc() { return LSan::getIgnoreMalloc(); } LSan & LSan::getInstance() { static LSan * instance = new LSan(); @@ -70,15 +69,6 @@ auto LSan::getLocalInstance() -> ThreadAllocInfo & { return localInfo; } -bool & LSan::getIgnoreMalloc() { - static thread_local bool ignore = false; - return ignore; -} - -void LSan::setIgnoreMalloc(bool ignore) { - LSan::getIgnoreMalloc() = ignore; -} - LSan::LSan() { atexit(reinterpret_cast(__exit_hook)); struct sigaction s{}; @@ -112,51 +102,6 @@ void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } -void LSan::addMalloc(MallocInfo && mInfo) { - std::lock_guard lock(infoMutex); - realStats += mInfo; - // TODO: Only replace if the new block is bigger than the potential old one. - infos.insert_or_assign(mInfo.getPointer(), mInfo); -} - -void LSan::changeMalloc(const MallocInfo & mInfo) { - std::lock_guard lock(infoMutex); - auto it = infos.find(mInfo.getPointer()); - if (it == infos.end()) { - realStats += mInfo; - } else { - if (it->second.getPointer() != mInfo.getPointer()) { - realStats -= it->second; - realStats += mInfo; - } else { - realStats.replaceMalloc(it->second.getSize(), mInfo.getSize()); - } - if (__lsan_trackMemory) { - it->second.setDeleted(true); - } - infos.insert_or_assign(mInfo.getPointer(), mInfo); - } -} - -bool LSan::removeMalloc(const void * pointer) { - std::lock_guard lock(infoMutex); - auto it = infos.find(pointer); - if (it == infos.end() || it->second.isDeleted()) { - return false; - } - realStats -= it->second; - if (__lsan_trackMemory) { - it->second.setDeleted(true); - } else { - infos.erase(it); - } - return true; -} - -bool LSan::removeMalloc(const MallocInfo & mInfo) { - return removeMalloc(mInfo.getPointer()); -} - size_t LSan::getTotalAllocatedBytes() { std::lock_guard lock(infoMutex); size_t ret = 0; diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 766a1cc..ecfec2a 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -36,14 +36,6 @@ class LSan { /// A pointer to the statistics instance held by each instance. static Stats * stats; - /** - * Statically holds a boolean value which idicates whether to track allocations - * or not at the moment of querying. - * - * @return a reference to the statically stored boolean value - */ - static auto getIgnoreMalloc() -> bool &; - /// A map containing all allocation records, sorted by their allocated pointers. std::map infos; /// The mutex used to protect the principal map. @@ -65,40 +57,6 @@ class LSan { LSan & operator=(const LSan &) = delete; LSan & operator=(const LSan &&) = delete; - /** - * Adds the given allocation record to the principle list and to the statistics. - * - * @param info the allocation record to add - */ - void addMalloc(MallocInfo && info); - /** - * Exchanges the allocation record associated with the pointer of the given allocation record - * by the given allocation record. - * - * @param info the allocation record to exchange - */ - void changeMalloc(const MallocInfo & info); - /** - * @brief Attempts to remove the given allocation record from the principal list. - * - * The allocation record is removed from the statistics and marked as deallocated. - * It is removed from the principal list if the fragmentation tracking is turned off. - * - * @param info the info to mark as deallocated - * @return whether the allocation record was found in the principal list - */ - auto removeMalloc(const MallocInfo & info) -> bool; - /** - * @brief Attempts to remove the allocation record associated with the given pointer. - * - * The allocation record is removed from the statistics and marked as deallocated if it - * was found. It is not removed from the principal list if the fragmentation tracking is enabled. - * - * @param pointer the pointer whose associated allocation record should be marked as deallocated - * @return whether an associated allocation record was found - */ - auto removeMalloc(const void * pointer) -> bool; - /** * Calculates and returns the total count of allocated bytes that are stored inside the * principal list containing the allocation records. @@ -174,19 +132,7 @@ class LSan { * @return whether the statistics are available */ static auto hasStats() -> bool; - /** - * Returns whether the allocations should be tracked at the time of querying. - * - * @return whether the allocations should be tracked at the moment - */ - static auto ignoreMalloc() -> bool; - /** - * Sets whether the next allocations should be tracked. - * - * @param ignore whether to ignore the next allocations - */ - static void setIgnoreMalloc(bool ignore); /** * Prints the informations of this sanitizer. */ From a748a46cadaa6526f392a6101f840d1e13757222 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 3 Aug 2023 16:57:27 +0200 Subject: [PATCH 15/58] Deprecated `__lsan_statsAvailable()` --- code/lsan_stats.cpp | 15 +++------------ include/lsan_stats.h | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/code/lsan_stats.cpp b/code/lsan_stats.cpp index a0f6d0d..fc37c19 100644 --- a/code/lsan_stats.cpp +++ b/code/lsan_stats.cpp @@ -36,8 +36,6 @@ size_t __lsan_getCurrentByteCount() { return LSan::getStats().getCurrentBytes( size_t __lsan_getMallocPeek() { return LSan::getStats().getMallocPeek(); } size_t __lsan_getBytePeek() { return LSan::getStats().getBytePeek(); } -bool __lsan_statsAvailable() { return LSan::hasStats(); } - bool __lsan_fStatsAvailable() { return __lsan_fragmentationStatsAvailable(); } bool __lsan_fragStatsAvailable() { return __lsan_fragmentationStatsAvailable(); } bool __lsan_fragmentationStatsAvailable() { return __lsan_trackMemory; } @@ -333,16 +331,9 @@ void __lsan_printStatsWithWidth(size_t width) { bool ignore = instance.getIgnoreMalloc(); instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; - if (__lsan_statsAvailable()) { - __lsan_printStatsCore("memory usage", width, out, - std::bind(__lsan_printBar, __lsan_getCurrentByteCount(), __lsan_getBytePeek(), std::placeholders::_1, bytesToString(__lsan_getBytePeek()), std::placeholders::_2), - std::bind(__lsan_printBar, __lsan_getCurrentMallocCount(), __lsan_getMallocPeek(), std::placeholders::_1, std::to_string(__lsan_getMallocPeek()) + " objects", std::placeholders::_2)); - } else { - out << Formatter::get(Style::ITALIC) << Formatter::get(Style::RED) - << "No memory statistics available at the moment!" - << Formatter::clear(Style::ITALIC) << Formatter::clear(Style::RED) - << std::endl; - } + __lsan_printStatsCore("memory usage", width, out, + std::bind(__lsan_printBar, __lsan_getCurrentByteCount(), __lsan_getBytePeek(), std::placeholders::_1, bytesToString(__lsan_getBytePeek()), std::placeholders::_2), + std::bind(__lsan_printBar, __lsan_getCurrentMallocCount(), __lsan_getMallocPeek(), std::placeholders::_1, std::to_string(__lsan_getMallocPeek()) + " objects", std::placeholders::_2)); if (!ignore) { instance.setIgnoreMalloc(false); } diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 5070871..40e55df 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -1,5 +1,5 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * * Copyright (C) 2022 - 2023 mhahnFr * @@ -20,6 +20,14 @@ #ifndef lsan_stats_h #define lsan_stats_h +#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(__STDC_VERSION__) && __STDC_VERSION >= 202311L) + #define DEPRECATED(message) [[ deprecated(message) ]] +#elif defined(__GNUC__) || defined(__clang__) + #define DEPRECATED(message) __attribute__((deprecated(message))) +#else + #define DEPRECATED(message) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -91,7 +99,9 @@ size_t __lsan_getBytePeek(); * @return Whether the memory statistics can savely be queried. * @since 1.1 */ -bool __lsan_statsAvailable(); +DEPRECATED("Always true since version 1.5") static inline bool __lsan_statsAvailable() { + return true; +} /** * @brief Returns whether the memory fragmentation statistics can be queried savely. From 1841ce6e8bc30d5f401aa19db9a1345d8590cd17 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:00:25 +0200 Subject: [PATCH 16/58] Reworked statistics querying --- code/LeakSani.cpp | 18 ++++++++++++------ code/LeakSani.hpp | 13 ++----------- code/threadAllocInfo/ThreadAllocInfo.hpp | 4 ++++ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 54f0614..c939b66 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -54,10 +54,17 @@ void (*LSan::free) (void *) = reinterpret_cast void (*LSan::exit)(int) = _Exit; -Stats * LSan::stats = nullptr; - -Stats & LSan::getStats() { return *LSan::stats; } -bool LSan::hasStats() { return LSan::stats != nullptr; } +auto LSan::getStats() -> Stats { + auto & instance = getInstance(); + + auto toReturn = instance.stats; + + for (const auto & localInstance : instance.threadInfos) { + toReturn += localInstance.get().getStats(); + } + + return toReturn; +} LSan & LSan::getInstance() { static LSan * instance = new LSan(); @@ -77,7 +84,6 @@ LSan::LSan() { sigaction(SIGBUS, &s, nullptr); signal(SIGUSR1, statsSignal); signal(SIGUSR2, callstackSignal); - stats = &realStats; } void LSan::registerThreadAllocInfo(ThreadAllocInfo::CRef info) { @@ -89,7 +95,7 @@ void LSan::registerThreadAllocInfo(ThreadAllocInfo::CRef info) { void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { std::lock_guard lock(infoMutex); - realStats += info.get().getStats(); + stats += info.get().getStats(); infos.merge(info.get().getInfos()); auto it = std::find_if(threadInfos.cbegin(), threadInfos.cend(), [&info] (const auto & elem) { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index ecfec2a..5386dba 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -33,15 +33,12 @@ * This class manages everything this sanitizer is capable to do. */ class LSan { - /// A pointer to the statistics instance held by each instance. - static Stats * stats; - /// A map containing all allocation records, sorted by their allocated pointers. std::map infos; /// The mutex used to protect the principal map. std::recursive_mutex infoMutex; /// An object holding all statistics. - Stats realStats; + Stats stats; /// Indicates whether the set callstack size had been exceeded during the printing. bool callstackSizeExceeded = false; @@ -125,13 +122,7 @@ class LSan { * * @return the current statistics instance */ - static auto getStats() -> Stats &; - /** - * Returns whether the statictics are available. - * - * @return whether the statistics are available - */ - static auto hasStats() -> bool; + static auto getStats() -> Stats; /** * Prints the informations of this sanitizer. diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 88a38e8..7c19c18 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -66,6 +66,10 @@ class ThreadAllocInfo { return stats; } + constexpr inline auto getStats() const -> const Stats & { + return stats; + } + constexpr inline auto getInfos() -> std::map & { return infos; } From 9da0016a91483783e5108d59825e0cb7c7f734fa Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:10:07 +0200 Subject: [PATCH 17/58] Reworked information gathering for the statistics --- code/LeakSani.cpp | 15 +++++++++++++-- code/LeakSani.hpp | 17 +++-------------- code/lsan_stats.cpp | 11 ++++++----- code/threadAllocInfo/ThreadAllocInfo.cpp | 8 ++++++++ code/threadAllocInfo/ThreadAllocInfo.hpp | 9 ++++++++- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index c939b66..8fe4561 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -139,8 +139,19 @@ size_t LSan::getTotalLeakedBytes() { return ret; } -const std::map & LSan::getInfos() const { return infos; } -std::recursive_mutex & LSan::getInfoMutex() { return infoMutex; } +auto LSan::getFragmentationInfos() const -> const std::map { + auto toReturn = std::map(); + + for (auto & localInstance : threadInfos) { + localInstance.get().lockMutex(); + toReturn.insert(localInstance.get().getInfos().cbegin(), localInstance.get().getInfos().cend()); + localInstance.get().unlockMutex(); + } + std::lock_guard lock(infoMutex); + toReturn.insert(infos.cbegin(), infos.cend()); + + return toReturn; +} void LSan::__exit_hook() { using Formatter::Style; diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 5386dba..ee396fb 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -36,7 +36,7 @@ class LSan { /// A map containing all allocation records, sorted by their allocated pointers. std::map infos; /// The mutex used to protect the principal map. - std::recursive_mutex infoMutex; + mutable std::recursive_mutex infoMutex; /// An object holding all statistics. Stats stats; /// Indicates whether the set callstack size had been exceeded during the printing. @@ -75,19 +75,8 @@ class LSan { * @return the total count of leaked objects */ auto getLeakCount() -> size_t; - /** - * Returns a reference to the mutex used to protect the principal list storing the - * allocation records. - * - * @return the mutex protecting the principal list - */ - auto getInfoMutex() -> std::recursive_mutex &; - /** - * Returns a reference to the principal list storing the allocation records. - * - * @return the principal list of allocation records - */ - auto getInfos() const -> const std::map &; + + auto getFragmentationInfos() const -> const std::map; /** * Sets whether the maximum callstack size has been exceeded during the printing. diff --git a/code/lsan_stats.cpp b/code/lsan_stats.cpp index fc37c19..41e6ec7 100644 --- a/code/lsan_stats.cpp +++ b/code/lsan_stats.cpp @@ -131,8 +131,7 @@ static inline void __lsan_printFragmentationObjectBar(size_t width, std::ostream << Formatter::clear(Style::BOLD) << Formatter::get(Style::GREYED) << Formatter::get(Style::UNDERLINED); - std::lock_guard(LSan::getInstance().getInfoMutex()); - const auto & infos = LSan::getInstance().getInfos(); + const auto & infos = LSan::getInstance().getFragmentationInfos(); auto it = infos.cbegin(); if (infos.size() < width) { const float step = static_cast(width) / infos.size(); @@ -211,14 +210,16 @@ static inline void __lsan_printFragmentationByteBar(size_t width, std::ostream & << Formatter::clear(Style::BOLD) << Formatter::get(Style::GREYED) << Formatter::get(Style::UNDERLINED); - std::lock_guard(LSan::getInstance().getInfoMutex()); - const auto & infos = LSan::getInstance().getInfos(); + const auto & infos = LSan::getInstance().getFragmentationInfos(); auto it = infos.cbegin(); size_t currentBlockBegin = 0, currentBlockEnd = it->second.getSize(), b = 0; - const size_t total = LSan::getInstance().getTotalAllocatedBytes(); + size_t total = 0; + for (const auto & [_, info] : infos) { + total += info.getSize(); + } if (total < width) { const size_t step = static_cast(static_cast(width) / total); diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index d474f86..0496f06 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -78,3 +78,11 @@ auto ThreadAllocInfo::removeMalloc(const void * pointer) -> bool { } return true; } + +void ThreadAllocInfo::lockMutex() const { + infosMutex.lock(); +} + +void ThreadAllocInfo::unlockMutex() const { + infosMutex.unlock(); +} diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 7c19c18..c614723 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -29,7 +29,7 @@ class ThreadAllocInfo { Stats stats; - std::recursive_mutex infosMutex; + mutable std::recursive_mutex infosMutex; std::map infos; bool ignoreMalloc; @@ -73,6 +73,13 @@ class ThreadAllocInfo { constexpr inline auto getInfos() -> std::map & { return infos; } + + constexpr inline auto getInfos() const -> const std::map & { + return infos; + } + + void lockMutex() const; + void unlockMutex() const; }; #endif /* ThreadAllocInfo_hpp */ From 9e3b15fd08ae055dc7b8d42e63a0142eb41116ce Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Fri, 4 Aug 2023 16:36:29 +0200 Subject: [PATCH 18/58] Implemented malloc removing across threads --- code/LeakSani.cpp | 32 +++++++++++++++++++++++- code/LeakSani.hpp | 8 ++++-- code/threadAllocInfo/ThreadAllocInfo.cpp | 5 ++-- code/threadAllocInfo/ThreadAllocInfo.hpp | 2 +- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 8fe4561..1716491 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -86,7 +86,7 @@ LSan::LSan() { signal(SIGUSR2, callstackSignal); } -void LSan::registerThreadAllocInfo(ThreadAllocInfo::CRef info) { +void LSan::registerThreadAllocInfo(ThreadAllocInfo::Ref info) { std::lock_guard lock(infoMutex); threadInfos.push_back(info); @@ -106,6 +106,36 @@ void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { } } +auto LSan::removeMallocHere(const void * pointer) -> bool { + std::lock_guard lock(infoMutex); + + auto it = infos.find(pointer); + if (it == infos.end()) { + return false; + } else if (it->second.isDeleted()) { + return true; + } + stats -= it->second; + if (__lsan_trackMemory) { + it->second.setDeleted(true); + } else { + infos.erase(it); + } + return true; +} + +auto LSan::removeMalloc(const void * pointer) -> bool { + if (removeMallocHere(pointer)) { + return true; + } + for (auto & localInstance : threadInfos) { + if (localInstance.get().removeMalloc(pointer, false)) { + return true; + } + } + return false; +} + void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } size_t LSan::getTotalAllocatedBytes() { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index ee396fb..597f0b0 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -42,7 +42,9 @@ class LSan { /// Indicates whether the set callstack size had been exceeded during the printing. bool callstackSizeExceeded = false; - std::vector threadInfos; + std::vector threadInfos; + + auto removeMallocHere(const void * pointer) -> bool; public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. @@ -54,6 +56,8 @@ class LSan { LSan & operator=(const LSan &) = delete; LSan & operator=(const LSan &&) = delete; + auto removeMalloc(const void * pointer) -> bool; + /** * Calculates and returns the total count of allocated bytes that are stored inside the * principal list containing the allocation records. @@ -85,7 +89,7 @@ class LSan { */ void setCallstackSizeExceeded(bool exceeded); - void registerThreadAllocInfo(ThreadAllocInfo::CRef info); + void registerThreadAllocInfo(ThreadAllocInfo::Ref info); void removeThreadAllocInfo(ThreadAllocInfo::Ref info); /// A pointer to the real `malloc` function. diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 0496f06..fc6d578 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -59,14 +59,13 @@ void ThreadAllocInfo::changeMalloc(const MallocInfo & info) { } } -auto ThreadAllocInfo::removeMalloc(const void * pointer) -> bool { +auto ThreadAllocInfo::removeMalloc(const void * pointer, bool search) -> bool { std::lock_guard lock(infosMutex); auto it = infos.find(pointer); if (it == infos.end()) { - // TODO: Maybe allocated in another thread? - return false; + return search ? LSan::getInstance().removeMalloc(pointer) : false; } else if (it->second.isDeleted()) { return false; } diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index c614723..f774c3a 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -48,7 +48,7 @@ class ThreadAllocInfo { void addMalloc(MallocInfo && info); void changeMalloc(const MallocInfo & info); - auto removeMalloc(const void * pointer) -> bool; + auto removeMalloc(const void * pointer, bool search = true) -> bool; constexpr auto removeMalloc(MallocInfo && info) -> bool { return removeMalloc(info.getPointer()); From a5141b15132d9bebbac968f8311bb9903748aeae Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:03:37 +0200 Subject: [PATCH 19/58] Implemented searching for the reallocated malloc across threads --- code/LeakSani.cpp | 32 ++++++++++++++++++++++++ code/LeakSani.hpp | 2 ++ code/threadAllocInfo/ThreadAllocInfo.cpp | 27 ++++++++++++-------- code/threadAllocInfo/ThreadAllocInfo.hpp | 2 +- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 1716491..047d3fc 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -124,6 +124,38 @@ auto LSan::removeMallocHere(const void * pointer) -> bool { return true; } +auto LSan::changeMallocHere(const MallocInfo & info) -> bool { + std::lock_guard lock(infoMutex); + + auto it = infos.find(info.getPointer()); + if (it == infos.end()) { + return false; + } + if (it->second.getPointer() != info.getPointer()) { + stats -= it->second; + stats += info; + } else { + stats.replaceMalloc(it->second.getSize(), info.getSize()); + } + if (__lsan_trackMemory) { + it->second.setDeleted(true); + } + infos.insert_or_assign(info.getPointer(), info); + return true; +} + +auto LSan::maybeChangeMalloc(const MallocInfo & info) -> bool { + if (changeMallocHere(info)) { + return true; + } + for (auto & localInstance : threadInfos) { + if (localInstance.get().changeMalloc(info, false)) { + return true; + } + } + return false; +} + auto LSan::removeMalloc(const void * pointer) -> bool { if (removeMallocHere(pointer)) { return true; diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 597f0b0..15f3b9a 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -45,6 +45,7 @@ class LSan { std::vector threadInfos; auto removeMallocHere(const void * pointer) -> bool; + auto changeMallocHere(const MallocInfo & info) -> bool; public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. @@ -56,6 +57,7 @@ class LSan { LSan & operator=(const LSan &) = delete; LSan & operator=(const LSan &&) = delete; + auto maybeChangeMalloc(const MallocInfo & info) -> bool; auto removeMalloc(const void * pointer) -> bool; /** diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index fc6d578..e1cf94f 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -38,25 +38,30 @@ void ThreadAllocInfo::addMalloc(MallocInfo && info) { infos.insert_or_assign(info.getPointer(), info); } -void ThreadAllocInfo::changeMalloc(const MallocInfo & info) { +auto ThreadAllocInfo::changeMalloc(const MallocInfo & info, bool search) -> bool { std::lock_guard lock(infosMutex); auto it = infos.find(info.getPointer()); if (it == infos.end()) { - // TODO: Maybe allocated in another thread? - stats += info; - } else { - if (it->second.getPointer() != info.getPointer()) { - stats -= it->second; + if (search && !LSan::getInstance().maybeChangeMalloc(info)) { + // FIXME: Register as new allocation! stats += info; + return true; } else { - stats.replaceMalloc(it->second.getSize(), info.getSize()); - } - if (__lsan_trackMemory) { - it->second.setDeleted(true); + return false; } - infos.insert_or_assign(info.getPointer(), info); } + if (it->second.getPointer() != info.getPointer()) { + stats -= it->second; + stats += info; + } else { + stats.replaceMalloc(it->second.getSize(), info.getSize()); + } + if (__lsan_trackMemory) { + it->second.setDeleted(true); + } + infos.insert_or_assign(info.getPointer(), info); + return true; } auto ThreadAllocInfo::removeMalloc(const void * pointer, bool search) -> bool { diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index f774c3a..186269e 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -47,7 +47,7 @@ class ThreadAllocInfo { ThreadAllocInfo & operator=(ThreadAllocInfo &&) = delete; void addMalloc(MallocInfo && info); - void changeMalloc(const MallocInfo & info); + auto changeMalloc(const MallocInfo & info, bool search = true) -> bool; auto removeMalloc(const void * pointer, bool search = true) -> bool; constexpr auto removeMalloc(MallocInfo && info) -> bool { From c263513345883cbef95b271bc822fb6967adeec8 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:24:55 +0200 Subject: [PATCH 20/58] Adding a reallocated allocation that was previously missed --- code/threadAllocInfo/ThreadAllocInfo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index e1cf94f..987d72f 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -44,8 +44,7 @@ auto ThreadAllocInfo::changeMalloc(const MallocInfo & info, bool search) -> bool auto it = infos.find(info.getPointer()); if (it == infos.end()) { if (search && !LSan::getInstance().maybeChangeMalloc(info)) { - // FIXME: Register as new allocation! - stats += info; + addMalloc(MallocInfo(info)); return true; } else { return false; From 335c560e4a26dfc0f9e7a9ba99bf3313213a39a0 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Sat, 5 Aug 2023 07:54:30 +0000 Subject: [PATCH 21/58] Removed misplaced constexpr --- code/threadAllocInfo/ThreadAllocInfo.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 186269e..495e423 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -50,7 +50,7 @@ class ThreadAllocInfo { auto changeMalloc(const MallocInfo & info, bool search = true) -> bool; auto removeMalloc(const void * pointer, bool search = true) -> bool; - constexpr auto removeMalloc(MallocInfo && info) -> bool { + auto removeMalloc(MallocInfo && info) -> bool { return removeMalloc(info.getPointer()); } From 22b4ac1abee8bd97c0823ee89582f8db13a51cab Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:50:12 +0200 Subject: [PATCH 22/58] Moved the statistic files into their own folder --- LeakSanitizer.xcodeproj/project.pbxproj | 14 +++++++++++--- code/LeakSani.hpp | 3 ++- code/{ => statistics}/Stats.cpp | 0 code/{ => statistics}/Stats.hpp | 2 +- code/{ => statistics}/lsan_stats.cpp | 12 +++++++----- code/threadAllocInfo/ThreadAllocInfo.hpp | 3 ++- 6 files changed, 23 insertions(+), 11 deletions(-) rename code/{ => statistics}/Stats.cpp (100%) rename code/{ => statistics}/Stats.hpp (99%) rename code/{ => statistics}/lsan_stats.cpp (98%) diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index f83e7b0..2ce6840 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -134,6 +134,16 @@ name = Frameworks; sourceTree = ""; }; + BF41CC5D2A813B4500EAA3A1 /* statistics */ = { + isa = PBXGroup; + children = ( + BF23A2DC289ECE6A00B17349 /* lsan_stats.cpp */, + BF23A2E0289ED24200B17349 /* Stats.cpp */, + BF23A2E1289ED24200B17349 /* Stats.hpp */, + ); + path = statistics; + sourceTree = ""; + }; BF643E5C28A40C970080DB21 /* include */ = { isa = PBXGroup; children = ( @@ -171,16 +181,14 @@ BF9DD3A428A6761400AEBC17 /* code */ = { isa = PBXGroup; children = ( + BF41CC5D2A813B4500EAA3A1 /* statistics */, BF30D8562A78159E001D4EBF /* threadAllocInfo */, BFAFADC428B4FDA40060076C /* Formatter.cpp */, BFAFADC528B4FDA40060076C /* Formatter.hpp */, BF621FE028A2B61E00414EE4 /* bytePrinter.cpp */, BF621FE128A2B61E00414EE4 /* bytePrinter.hpp */, - BF23A2DC289ECE6A00B17349 /* lsan_stats.cpp */, BF621FDB28A291DE00414EE4 /* lsan_internals.cpp */, BF72C3CA2885CB9E00C7AE5C /* LeakSani.cpp */, - BF23A2E0289ED24200B17349 /* Stats.cpp */, - BF23A2E1289ED24200B17349 /* Stats.hpp */, BF72C3C92885CB9E00C7AE5C /* LeakSani.hpp */, BFBF736328831FC200BC4208 /* MallocInfo.cpp */, BFBF736428831FC200BC4208 /* MallocInfo.hpp */, diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 15f3b9a..b4bd199 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -26,7 +26,8 @@ #include #include "MallocInfo.hpp" -#include "Stats.hpp" + +#include "statistics/Stats.hpp" #include "threadAllocInfo/ThreadAllocInfo.hpp" /** diff --git a/code/Stats.cpp b/code/statistics/Stats.cpp similarity index 100% rename from code/Stats.cpp rename to code/statistics/Stats.cpp diff --git a/code/Stats.hpp b/code/statistics/Stats.hpp similarity index 99% rename from code/Stats.hpp rename to code/statistics/Stats.hpp index ce72974..93fd92c 100644 --- a/code/Stats.hpp +++ b/code/statistics/Stats.hpp @@ -24,7 +24,7 @@ #include #include -#include "MallocInfo.hpp" +#include "../MallocInfo.hpp" /// This class contains all statistics that this sanitizer produces. class Stats { diff --git a/code/lsan_stats.cpp b/code/statistics/lsan_stats.cpp similarity index 98% rename from code/lsan_stats.cpp rename to code/statistics/lsan_stats.cpp index 41e6ec7..95c0c36 100644 --- a/code/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -20,11 +20,13 @@ #include #include #include -#include "LeakSani.hpp" -#include "Formatter.hpp" -#include "bytePrinter.hpp" -#include "../include/lsan_internals.h" -#include "../include/lsan_stats.h" + +#include "../Formatter.hpp" +#include "../bytePrinter.hpp" +#include "../LeakSani.hpp" + +#include "../../include/lsan_internals.h" +#include "../../include/lsan_stats.h" size_t __lsan_getTotalMallocs() { return LSan::getStats().getTotalMallocCount(); } size_t __lsan_getTotalBytes() { return LSan::getStats().getTotalBytes(); } diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 495e423..a4ba2d0 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -25,7 +25,8 @@ #include #include "../MallocInfo.hpp" -#include "../Stats.hpp" + +#include "../statistics/Stats.hpp" class ThreadAllocInfo { Stats stats; From edb66bc7051a8f043fc40d2357d190f2e2b1c3a6 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:06:35 +0200 Subject: [PATCH 23/58] Added a peaks class --- LeakSanitizer.xcodeproj/project.pbxproj | 12 ++++ code/statistics/Peaks.cpp | 76 +++++++++++++++++++++++++ code/statistics/Peaks.hpp | 48 ++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 code/statistics/Peaks.cpp create mode 100644 code/statistics/Peaks.hpp diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index 2ce6840..80afb74 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -40,6 +40,10 @@ BF378FAE2919484E00A4DAA9 /* lsan_internals.h in Headers */ = {isa = PBXBuildFile; fileRef = BF621FDC28A291DE00414EE4 /* lsan_internals.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF378FB52919496000A4DAA9 /* libcallstack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF378FB42919496000A4DAA9 /* libcallstack.a */; }; BF378FB8291949D700A4DAA9 /* libcallstack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF378FB42919496000A4DAA9 /* libcallstack.a */; }; + BF41CC602A813C5000EAA3A1 /* Peaks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */; }; + BF41CC612A813C5000EAA3A1 /* Peaks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */; }; + BF41CC622A813C5000EAA3A1 /* Peaks.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */; }; + BF41CC632A813C5000EAA3A1 /* Peaks.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */; }; BF49A5D92899599300BC1FFD /* signalHandlers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF49A5D72899599300BC1FFD /* signalHandlers.cpp */; }; BF49A5DA2899599300BC1FFD /* signalHandlers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF49A5D82899599300BC1FFD /* signalHandlers.hpp */; }; BF5FFC17289AAA6500006AC4 /* warn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF5FFC15289AAA6500006AC4 /* warn.cpp */; }; @@ -71,6 +75,8 @@ BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadAllocInfo.cpp; sourceTree = ""; }; BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ThreadAllocInfo.hpp; sourceTree = ""; }; BF378FB42919496000A4DAA9 /* libcallstack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcallstack.a; path = CallstackLibrary/libcallstack.a; sourceTree = ""; }; + BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Peaks.cpp; sourceTree = ""; }; + BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Peaks.hpp; sourceTree = ""; }; BF49A5D72899599300BC1FFD /* signalHandlers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = signalHandlers.cpp; sourceTree = ""; }; BF49A5D82899599300BC1FFD /* signalHandlers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = signalHandlers.hpp; sourceTree = ""; }; BF4C28E828B66033001EB53E /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; @@ -140,6 +146,8 @@ BF23A2DC289ECE6A00B17349 /* lsan_stats.cpp */, BF23A2E0289ED24200B17349 /* Stats.cpp */, BF23A2E1289ED24200B17349 /* Stats.hpp */, + BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */, + BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */, ); path = statistics; sourceTree = ""; @@ -218,6 +226,7 @@ BF0F1350291947C0008F0FCD /* Formatter.hpp in Headers */, BF378F962919483900A4DAA9 /* LeakSani.hpp in Headers */, BF378F932919482E00A4DAA9 /* Stats.hpp in Headers */, + BF41CC632A813C5000EAA3A1 /* Peaks.hpp in Headers */, BF378F9C2919483D00A4DAA9 /* warn.hpp in Headers */, BF378F992919483B00A4DAA9 /* MallocInfo.hpp in Headers */, BF378FA22919484500A4DAA9 /* crash.hpp in Headers */, @@ -238,6 +247,7 @@ BF72C3CF2885CB9E00C7AE5C /* leaksan.h in Headers */, BFBF736628831FC200BC4208 /* MallocInfo.hpp in Headers */, BF72C3CD2885CB9E00C7AE5C /* LeakSani.hpp in Headers */, + BF41CC622A813C5000EAA3A1 /* Peaks.hpp in Headers */, BF621FE328A2B61E00414EE4 /* bytePrinter.hpp in Headers */, BFBF736A28832F8100BC4208 /* wrap_malloc.hpp in Headers */, BF49A5DA2899599300BC1FFD /* signalHandlers.hpp in Headers */, @@ -329,6 +339,7 @@ BF0F132F29194783008F0FCD /* Formatter.cpp in Sources */, BF0F133229194786008F0FCD /* bytePrinter.cpp in Sources */, BF0F13382919478E008F0FCD /* lsan_internals.cpp in Sources */, + BF41CC612A813C5000EAA3A1 /* Peaks.cpp in Sources */, BF0F13352919478B008F0FCD /* lsan_stats.cpp in Sources */, BF0F133B29194791008F0FCD /* LeakSani.cpp in Sources */, BF0F133E29194794008F0FCD /* Stats.cpp in Sources */, @@ -348,6 +359,7 @@ BFAFADC628B4FDA40060076C /* Formatter.cpp in Sources */, BF49A5D92899599300BC1FFD /* signalHandlers.cpp in Sources */, BF23A2E2289ED24200B17349 /* Stats.cpp in Sources */, + BF41CC602A813C5000EAA3A1 /* Peaks.cpp in Sources */, BF621FE228A2B61E00414EE4 /* bytePrinter.cpp in Sources */, BF23A2DE289ECE6A00B17349 /* lsan_stats.cpp in Sources */, BF621FDD28A291DE00414EE4 /* lsan_internals.cpp in Sources */, diff --git a/code/statistics/Peaks.cpp b/code/statistics/Peaks.cpp new file mode 100644 index 0000000..2324994 --- /dev/null +++ b/code/statistics/Peaks.cpp @@ -0,0 +1,76 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#include "Peaks.hpp" + +Peaks::Peaks(Peaks && other): + mutex(), + peakMallocCount(std::move(other.peakByteCount)), + peakByteCount(std::move(other.peakByteCount)) +{} + +Peaks::Peaks(const Peaks & other): + mutex(), + peakMallocCount(other.peakMallocCount), + peakByteCount(other.peakByteCount) +{} + +auto Peaks::operator=(Peaks && other) -> Peaks & { + if (std::addressof(other) != this) { + std::lock_guard lock1(mutex), + lock2(other.mutex); + peakMallocCount = std::move(other.peakMallocCount); + peakByteCount = std::move(other.peakByteCount); + } + return *this; +} + +auto Peaks::operator=(const Peaks & other) -> Peaks & { + if (std::addressof(other) != this) { + std::lock_guard lock1(mutex), + lock2(other.mutex); + peakMallocCount = other.peakMallocCount; + peakByteCount = other.peakByteCount; + } + return *this; +} + +void Peaks::setPeakMallocCount(const std::size_t peakMallocCount) { + std::lock_guard lock(mutex); + + this->peakMallocCount = peakMallocCount; +} + +void Peaks::setPeakByteCount(const std::size_t peakByteCount) { + std::lock_guard lock(mutex); + + this->peakByteCount = peakByteCount; +} + +auto Peaks::getPeakMallocCount() const -> std::size_t { + std::lock_guard lock(mutex); + + return peakMallocCount; +} + +auto Peaks::getPeakByteCount() const -> std::size_t { + std::lock_guard lock(mutex); + + return peakByteCount; +} diff --git a/code/statistics/Peaks.hpp b/code/statistics/Peaks.hpp new file mode 100644 index 0000000..18a2cdc --- /dev/null +++ b/code/statistics/Peaks.hpp @@ -0,0 +1,48 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#ifndef Peaks_hpp +#define Peaks_hpp + +#include + +class Peaks { + mutable std::mutex mutex; + + std::size_t peakMallocCount; + std::size_t peakByteCount; + +public: + Peaks() = default; + ~Peaks() = default; + + Peaks(Peaks &&); + Peaks(const Peaks &); + + auto operator=(Peaks &&) -> Peaks &; + auto operator=(const Peaks &) -> Peaks &; + + void setPeakMallocCount(const std::size_t peakMallocCount); + void setPeakByteCount(const std::size_t peakByteCount); + + auto getPeakMallocCount() const -> std::size_t; + auto getPeakByteCount() const -> std::size_t; +}; + +#endif /* Peaks_hpp */ From b7236bc5ad3d0436e236cc259cdaa74e971f5c0e Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:38:57 +0200 Subject: [PATCH 24/58] Moved deprecation macros into its own header --- LeakSanitizer.xcodeproj/project.pbxproj | 2 ++ include/deprecation.h | 31 +++++++++++++++++++++++++ include/lsan_stats.h | 8 +------ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 include/deprecation.h diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index 80afb74..e2aa61e 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ BF23A2E1289ED24200B17349 /* Stats.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stats.hpp; sourceTree = ""; }; BF30D8572A7815E8001D4EBF /* ThreadAllocInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadAllocInfo.cpp; sourceTree = ""; }; BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ThreadAllocInfo.hpp; sourceTree = ""; }; + BF34157C2A8405AD00DEEF10 /* deprecation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = deprecation.h; sourceTree = ""; }; BF378FB42919496000A4DAA9 /* libcallstack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcallstack.a; path = CallstackLibrary/libcallstack.a; sourceTree = ""; }; BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Peaks.cpp; sourceTree = ""; }; BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Peaks.hpp; sourceTree = ""; }; @@ -159,6 +160,7 @@ BF72C3CB2885CB9E00C7AE5C /* leaksan.h */, BF621FDC28A291DE00414EE4 /* lsan_internals.h */, BF72C3CC2885CB9E00C7AE5C /* stdlib.h */, + BF34157C2A8405AD00DEEF10 /* deprecation.h */, ); path = include; sourceTree = ""; diff --git a/include/deprecation.h b/include/deprecation.h new file mode 100644 index 0000000..3636743 --- /dev/null +++ b/include/deprecation.h @@ -0,0 +1,31 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#ifndef deprecation_h +#define deprecation_h + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(__STDC_VERSION__) && __STDC_VERSION >= 202311L) + #define DEPRECATED(message) [[ deprecated(message) ]] +#elif defined(__GNUC__) || defined(__clang__) + #define DEPRECATED(message) __attribute__((deprecated(message))) +#else + #define DEPRECATED(message) +#endif + +#endif /* deprecation_h */ diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 40e55df..8b7e4f4 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -20,13 +20,7 @@ #ifndef lsan_stats_h #define lsan_stats_h -#if (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(__STDC_VERSION__) && __STDC_VERSION >= 202311L) - #define DEPRECATED(message) [[ deprecated(message) ]] -#elif defined(__GNUC__) || defined(__clang__) - #define DEPRECATED(message) __attribute__((deprecated(message))) -#else - #define DEPRECATED(message) -#endif +#include "deprecation.h" #ifdef __cplusplus extern "C" { From 18289c8af31f0a156ea8062eb6f959b22ec8e74d Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:45:24 +0200 Subject: [PATCH 25/58] Added statistics controlling bool --- code/lsan_internals.cpp | 5 +++-- include/lsan_internals.h | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/code/lsan_internals.cpp b/code/lsan_internals.cpp index 927bb13..fec4181 100644 --- a/code/lsan_internals.cpp +++ b/code/lsan_internals.cpp @@ -1,7 +1,7 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * - * Copyright (C) 2022 mhahnFr and contributors + * Copyright (C) 2022 - 2023 mhahnFr and contributors * * This file is part of the LeakSanitizer. This library is free software: * you can redistribute it and/or modify it under the terms of the @@ -41,6 +41,7 @@ bool __lsan_invalidFree = false; bool __lsan_freeNull = false; bool __lsan_trackMemory = false; +bool __lsan_statsActive = false; size_t __lsan_leakCount = 100; diff --git a/include/lsan_internals.h b/include/lsan_internals.h index 33dae32..9347e5e 100644 --- a/include/lsan_internals.h +++ b/include/lsan_internals.h @@ -1,5 +1,5 @@ /* - * LeakSanitizer - A small library showing informations about lost memory. + * LeakSanitizer - Small library showing information about lost memory. * * Copyright (C) 2022 - 2023 mhahnFr and contributors * @@ -20,6 +20,8 @@ #ifndef lsan_internals_hpp #define lsan_internals_hpp +#include "deprecation.h" + #ifdef __cplusplus extern "C" { #endif @@ -108,8 +110,11 @@ extern bool __lsan_freeNull; * * @since 1.2 */ +DEPRECATED("Since v1.5, fragmentation is tracked together with the statistics") extern bool __lsan_trackMemory; +extern bool __lsan_statsActive; + /** * @brief This value defines the count of leaks that are printed at the exit of the program. * From fdb0b837479e376daeb281ffa78d394539e38076 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:45:52 +0200 Subject: [PATCH 26/58] Deprecated the fragmentation stats available functions --- include/lsan_stats.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 8b7e4f4..f76c921 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -105,6 +105,7 @@ DEPRECATED("Always true since version 1.5") static inline bool __lsan_statsAva * @return Whether the memory fragmentation statistics are available. * @since 1.2 */ +DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") bool __lsan_fStatsAvailable(); /** @@ -115,6 +116,7 @@ bool __lsan_fStatsAvailable(); * @return Whether the memory fragmentation statisitcs are available. * @since 1.2 */ +DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") bool __lsan_fragStatsAvailable(); /** @@ -125,6 +127,7 @@ bool __lsan_fragStatsAvailable(); * @return Whether the memory fragmentation statisitcs are available. * @since 1.2 */ +DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") bool __lsan_fragmentationStatsAvailable(); /** From ca550e3205ab27b18bbedac26287cb2d65386c09 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:48:21 +0200 Subject: [PATCH 27/58] Removed the statistics from the thread local tracker --- code/LeakSani.cpp | 4 ++-- code/threadAllocInfo/ThreadAllocInfo.cpp | 17 +---------------- code/threadAllocInfo/ThreadAllocInfo.hpp | 9 --------- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 047d3fc..272b3b4 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -60,7 +60,7 @@ auto LSan::getStats() -> Stats { auto toReturn = instance.stats; for (const auto & localInstance : instance.threadInfos) { - toReturn += localInstance.get().getStats(); +// toReturn += localInstance.get().getStats(); } return toReturn; @@ -95,7 +95,7 @@ void LSan::registerThreadAllocInfo(ThreadAllocInfo::Ref info) { void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { std::lock_guard lock(infoMutex); - stats += info.get().getStats(); +// stats += info.get().getStats(); infos.merge(info.get().getInfos()); auto it = std::find_if(threadInfos.cbegin(), threadInfos.cend(), [&info] (const auto & elem) { diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index 987d72f..ad870d3 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -34,7 +34,6 @@ ThreadAllocInfo::~ThreadAllocInfo() { void ThreadAllocInfo::addMalloc(MallocInfo && info) { std::lock_guard lock(infosMutex); - stats += info; infos.insert_or_assign(info.getPointer(), info); } @@ -50,15 +49,6 @@ auto ThreadAllocInfo::changeMalloc(const MallocInfo & info, bool search) -> bool return false; } } - if (it->second.getPointer() != info.getPointer()) { - stats -= it->second; - stats += info; - } else { - stats.replaceMalloc(it->second.getSize(), info.getSize()); - } - if (__lsan_trackMemory) { - it->second.setDeleted(true); - } infos.insert_or_assign(info.getPointer(), info); return true; } @@ -73,12 +63,7 @@ auto ThreadAllocInfo::removeMalloc(const void * pointer, bool search) -> bool { } else if (it->second.isDeleted()) { return false; } - stats -= it->second; - if (__lsan_trackMemory) { - it->second.setDeleted(true); - } else { - infos.erase(it); - } + infos.erase(it); return true; } diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index a4ba2d0..ba9afaa 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -29,7 +29,6 @@ #include "../statistics/Stats.hpp" class ThreadAllocInfo { - Stats stats; mutable std::recursive_mutex infosMutex; std::map infos; bool ignoreMalloc; @@ -63,14 +62,6 @@ class ThreadAllocInfo { return ignoreMalloc; } - constexpr inline auto getStats() -> Stats & { - return stats; - } - - constexpr inline auto getStats() const -> const Stats & { - return stats; - } - constexpr inline auto getInfos() -> std::map & { return infos; } From 45f88c3467612c8e9b52acd6bafc7ec441d72c20 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:51:53 +0200 Subject: [PATCH 28/58] Removed statistic calculation form the main class --- code/LeakSani.cpp | 13 ------------- code/LeakSani.hpp | 4 +++- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 272b3b4..125d5fc 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -54,18 +54,6 @@ void (*LSan::free) (void *) = reinterpret_cast void (*LSan::exit)(int) = _Exit; -auto LSan::getStats() -> Stats { - auto & instance = getInstance(); - - auto toReturn = instance.stats; - - for (const auto & localInstance : instance.threadInfos) { -// toReturn += localInstance.get().getStats(); - } - - return toReturn; -} - LSan & LSan::getInstance() { static LSan * instance = new LSan(); return *instance; @@ -95,7 +83,6 @@ void LSan::registerThreadAllocInfo(ThreadAllocInfo::Ref info) { void LSan::removeThreadAllocInfo(ThreadAllocInfo::Ref info) { std::lock_guard lock(infoMutex); -// stats += info.get().getStats(); infos.merge(info.get().getInfos()); auto it = std::find_if(threadInfos.cbegin(), threadInfos.cend(), [&info] (const auto & elem) { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index b4bd199..126c557 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -118,7 +118,9 @@ class LSan { * * @return the current statistics instance */ - static auto getStats() -> Stats; + inline static auto getStats() -> const Stats & { + return getInstance().stats; + } /** * Prints the informations of this sanitizer. From 4232d9bab0f6adb03f9ec1394b60592adb071242 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 9 Aug 2023 19:55:05 +0200 Subject: [PATCH 29/58] Adapted deprecated function `statsAvailable()` --- include/lsan_stats.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/lsan_stats.h b/include/lsan_stats.h index f76c921..4caa65f 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -93,8 +93,9 @@ size_t __lsan_getBytePeek(); * @return Whether the memory statistics can savely be queried. * @since 1.1 */ -DEPRECATED("Always true since version 1.5") static inline bool __lsan_statsAvailable() { - return true; +DEPRECATED("Since v1.5, refer to __lsan_statsActive") +static inline bool __lsan_statsAvailable() { + return __lsan_statsActive; } /** From 3ef4b07936944806532b6b8b75e9e3a9d89fccfe Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 16:41:31 +0200 Subject: [PATCH 30/58] Redirecting the deprecated functions --- code/statistics/lsan_stats.cpp | 4 ---- include/lsan_stats.h | 20 ++++++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index 95c0c36..16f988d 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -38,10 +38,6 @@ size_t __lsan_getCurrentByteCount() { return LSan::getStats().getCurrentBytes( size_t __lsan_getMallocPeek() { return LSan::getStats().getMallocPeek(); } size_t __lsan_getBytePeek() { return LSan::getStats().getBytePeek(); } -bool __lsan_fStatsAvailable() { return __lsan_fragmentationStatsAvailable(); } -bool __lsan_fragStatsAvailable() { return __lsan_fragmentationStatsAvailable(); } -bool __lsan_fragmentationStatsAvailable() { return __lsan_trackMemory; } - void __lsan_printStats() { __lsan_printStatsWithWidth(100); } void __lsan_printFStats() { __lsan_printFragmentationStats(); } diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 4caa65f..14fe35c 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -22,6 +22,8 @@ #include "deprecation.h" +#include "lsan_internals.h" + #ifdef __cplusplus extern "C" { #endif @@ -106,8 +108,10 @@ static inline bool __lsan_statsAvailable() { * @return Whether the memory fragmentation statistics are available. * @since 1.2 */ -DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") -bool __lsan_fStatsAvailable(); +DEPRECATED("Since v1.5 replaced by __lsan_statsActive") +static inline bool __lsan_fStatsAvailable() { + return __lsan_statsActive; +} /** * @brief Returns whether the memory fragmentation statistics can be queried savely. @@ -117,8 +121,10 @@ bool __lsan_fStatsAvailable(); * @return Whether the memory fragmentation statisitcs are available. * @since 1.2 */ -DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") -bool __lsan_fragStatsAvailable(); +DEPRECATED("Since v1.5 replaced by __lsan_statsActive") +static inline bool __lsan_fragStatsAvailable() { + return __lsan_statsActive; +} /** * @brief Returns whether the memory fragmentation statistics can be queried savely. @@ -128,8 +134,10 @@ bool __lsan_fragStatsAvailable(); * @return Whether the memory fragmentation statisitcs are available. * @since 1.2 */ -DEPRECATED("Since v1.5 replaced by __lsan_statsAvailable") -bool __lsan_fragmentationStatsAvailable(); +DEPRECATED("Since v1.5 replaced by __lsan_statsActive") +static inline bool __lsan_fragmentationStatsAvailable() { + return __lsan_statsActive; +} /** * @brief Prints the statistics of the memory fragmentation. From 95a4bc8e14a26fbf8f6a4dc8de442a52603d47f0 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 17:46:53 +0200 Subject: [PATCH 31/58] Added tracking abstraction --- LeakSanitizer.xcodeproj/project.pbxproj | 2 ++ code/ATracker.h | 45 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 code/ATracker.h diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index e2aa61e..6ad4e9e 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -102,6 +102,7 @@ BFBF736928832F8100BC4208 /* wrap_malloc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wrap_malloc.hpp; sourceTree = ""; }; BFBF736B2883323100BC4208 /* crash.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crash.cpp; sourceTree = ""; }; BFBF736C2883323100BC4208 /* crash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = crash.hpp; sourceTree = ""; }; + BFC898552A8530BB00F7CB6D /* ATracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ATracker.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -210,6 +211,7 @@ BF49A5D82899599300BC1FFD /* signalHandlers.hpp */, BFBF736C2883323100BC4208 /* crash.hpp */, BFBF736928832F8100BC4208 /* wrap_malloc.hpp */, + BFC898552A8530BB00F7CB6D /* ATracker.h */, ); path = code; sourceTree = ""; diff --git a/code/ATracker.h b/code/ATracker.h new file mode 100644 index 0000000..eec6dcc --- /dev/null +++ b/code/ATracker.h @@ -0,0 +1,45 @@ +/* + * LeakSanitizer - Small library showing information about lost memory. + * + * Copyright (C) 2023 mhahnFr + * + * This file is part of the LeakSanitizer. This library is free software: + * you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this library, see the file LICENSE. If not, see . + */ + +#ifndef ATracker_h +#define ATracker_h + +#include "MallocInfo.hpp" + +class ATracker { + bool ignoreMalloc; + +public: + virtual ~ATracker {} + + virtual void addMalloc(MallocInfo && info) = 0; + virtual auto changeMalloc(const MallocInfo & info) -> bool = 0; + virtual auto removeMalloc(const void * pointer) -> bool = 0; + virtual auto removeMalloc(MallocInfo && info) -> bool = 0; + + constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { + this->ignoreMalloc = ignoreMalloc; + } + + constexpr inline auto getIgnoreMalloc() const -> bool { + return ignoreMalloc; + } +}; + +#endif /* ATracker_h */ From 34f01d43b732b9df8f7c518c8e729c8fb2f4ee52 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 17:56:19 +0200 Subject: [PATCH 32/58] Adapted the ThreadAllocInfo to inherit from `ATracker` --- code/ATracker.h | 2 +- code/threadAllocInfo/ThreadAllocInfo.hpp | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/code/ATracker.h b/code/ATracker.h index eec6dcc..c46f354 100644 --- a/code/ATracker.h +++ b/code/ATracker.h @@ -26,7 +26,7 @@ class ATracker { bool ignoreMalloc; public: - virtual ~ATracker {} + virtual ~ATracker() {} virtual void addMalloc(MallocInfo && info) = 0; virtual auto changeMalloc(const MallocInfo & info) -> bool = 0; diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index ba9afaa..8c8e7e1 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -24,14 +24,14 @@ #include #include +#include "../ATracker.h" #include "../MallocInfo.hpp" #include "../statistics/Stats.hpp" -class ThreadAllocInfo { +class ThreadAllocInfo: public ATracker { mutable std::recursive_mutex infosMutex; std::map infos; - bool ignoreMalloc; public: using Ref = std::reference_wrapper; @@ -46,20 +46,20 @@ class ThreadAllocInfo { ThreadAllocInfo & operator=(const ThreadAllocInfo &) = delete; ThreadAllocInfo & operator=(ThreadAllocInfo &&) = delete; - void addMalloc(MallocInfo && info); - auto changeMalloc(const MallocInfo & info, bool search = true) -> bool; - auto removeMalloc(const void * pointer, bool search = true) -> bool; + virtual void addMalloc(MallocInfo && info) override; + auto changeMalloc(const MallocInfo & info, bool search) -> bool; + auto removeMalloc(const void * pointer, bool search) -> bool; - auto removeMalloc(MallocInfo && info) -> bool { - return removeMalloc(info.getPointer()); + virtual inline auto changeMalloc(const MallocInfo & info) -> bool override { + return changeMalloc(info, true); } - constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { - this->ignoreMalloc = ignoreMalloc; + virtual inline auto removeMalloc(const void * pointer) -> bool override { + return removeMalloc(pointer, true); } - constexpr inline auto getIgnoreMalloc() const -> bool { - return ignoreMalloc; + virtual inline auto removeMalloc(MallocInfo && info) -> bool override { + return removeMalloc(info.getPointer()); } constexpr inline auto getInfos() -> std::map & { From 52ae01477d70fe289bae4b148daebd90c3738911 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:10:07 +0200 Subject: [PATCH 33/58] Removed dedicated fragmentation calculation --- code/LeakSani.cpp | 14 -------------- code/LeakSani.hpp | 4 +++- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 125d5fc..426dc2e 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -188,20 +188,6 @@ size_t LSan::getTotalLeakedBytes() { return ret; } -auto LSan::getFragmentationInfos() const -> const std::map { - auto toReturn = std::map(); - - for (auto & localInstance : threadInfos) { - localInstance.get().lockMutex(); - toReturn.insert(localInstance.get().getInfos().cbegin(), localInstance.get().getInfos().cend()); - localInstance.get().unlockMutex(); - } - std::lock_guard lock(infoMutex); - toReturn.insert(infos.cbegin(), infos.cend()); - - return toReturn; -} - void LSan::__exit_hook() { using Formatter::Style; getLocalInstance().setIgnoreMalloc(true); diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 126c557..8a5dd2a 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -83,7 +83,9 @@ class LSan { */ auto getLeakCount() -> size_t; - auto getFragmentationInfos() const -> const std::map; + inline auto getFragmentationInfos() const -> const std::map & { + return infos; + } /** * Sets whether the maximum callstack size has been exceeded during the printing. From 6293348abee66acf0eda05cd34a3f35d6955fe5b Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:15:52 +0200 Subject: [PATCH 34/58] Made ATracker more convenient --- code/ATracker.h | 9 +++++++-- code/threadAllocInfo/ThreadAllocInfo.hpp | 4 ---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/code/ATracker.h b/code/ATracker.h index c46f354..1dcb479 100644 --- a/code/ATracker.h +++ b/code/ATracker.h @@ -20,10 +20,12 @@ #ifndef ATracker_h #define ATracker_h +#include + #include "MallocInfo.hpp" class ATracker { - bool ignoreMalloc; + std::atomic_bool ignoreMalloc; public: virtual ~ATracker() {} @@ -31,7 +33,10 @@ class ATracker { virtual void addMalloc(MallocInfo && info) = 0; virtual auto changeMalloc(const MallocInfo & info) -> bool = 0; virtual auto removeMalloc(const void * pointer) -> bool = 0; - virtual auto removeMalloc(MallocInfo && info) -> bool = 0; + + inline auto removeMalloc(MallocInfo && info) -> bool { + return removeMalloc(info.getPointer()); + } constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { this->ignoreMalloc = ignoreMalloc; diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 8c8e7e1..dc0dcb3 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -58,10 +58,6 @@ class ThreadAllocInfo: public ATracker { return removeMalloc(pointer, true); } - virtual inline auto removeMalloc(MallocInfo && info) -> bool override { - return removeMalloc(info.getPointer()); - } - constexpr inline auto getInfos() -> std::map & { return infos; } From 1b33169990bdd4b7759674038c6aebd03e85ad6f Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:41:52 +0200 Subject: [PATCH 35/58] Made the main sanitizer class a leak tracker --- code/ATracker.h | 2 +- code/LeakSani.cpp | 11 +++++++++++ code/LeakSani.hpp | 12 ++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/code/ATracker.h b/code/ATracker.h index 1dcb479..6783fa1 100644 --- a/code/ATracker.h +++ b/code/ATracker.h @@ -25,7 +25,7 @@ #include "MallocInfo.hpp" class ATracker { - std::atomic_bool ignoreMalloc; + std::atomic_bool ignoreMalloc = false; public: virtual ~ATracker() {} diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 426dc2e..45b1cd6 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -155,6 +155,17 @@ auto LSan::removeMalloc(const void * pointer) -> bool { return false; } +void LSan::addMalloc(MallocInfo && info) { + std::lock_guard lock(infoMutex); + + stats += info; // No need to check __lsan_statsActive here, + // since allocations are only added globally + // if the __lsan_statsActive is true. + // - mhahnFr + + infos.insert_or_assign(info.getPointer(), info); +} + void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } size_t LSan::getTotalAllocatedBytes() { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 8a5dd2a..0360b04 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -25,6 +25,7 @@ #include #include +#include "ATracker.h" #include "MallocInfo.hpp" #include "statistics/Stats.hpp" @@ -33,7 +34,7 @@ /** * This class manages everything this sanitizer is capable to do. */ -class LSan { +class LSan: public ATracker { /// A map containing all allocation records, sorted by their allocated pointers. std::map infos; /// The mutex used to protect the principal map. @@ -59,7 +60,14 @@ class LSan { LSan & operator=(const LSan &&) = delete; auto maybeChangeMalloc(const MallocInfo & info) -> bool; - auto removeMalloc(const void * pointer) -> bool; + + virtual auto removeMalloc(const void * pointer) -> bool override; + + virtual void addMalloc(MallocInfo && info) override; + + virtual inline auto changeMalloc(const MallocInfo & info) -> bool override { + return maybeChangeMalloc(info); + } /** * Calculates and returns the total count of allocated bytes that are stored inside the From 14529b663d663c491e9d5e4a0458cd0d964fa4eb Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:42:39 +0200 Subject: [PATCH 36/58] Switching to the global tracker if stats are activated --- code/LeakSani.cpp | 22 +++++++++++----------- code/LeakSani.hpp | 9 +++++++++ code/signalHandlers.cpp | 2 +- code/statistics/lsan_stats.cpp | 6 +++--- code/wrap_malloc.cpp | 18 +++++++++--------- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 45b1cd6..9712aee 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -102,8 +102,8 @@ auto LSan::removeMallocHere(const void * pointer) -> bool { } else if (it->second.isDeleted()) { return true; } - stats -= it->second; - if (__lsan_trackMemory) { + if (__lsan_statsActive) { + stats -= it->second; it->second.setDeleted(true); } else { infos.erase(it); @@ -118,13 +118,13 @@ auto LSan::changeMallocHere(const MallocInfo & info) -> bool { if (it == infos.end()) { return false; } - if (it->second.getPointer() != info.getPointer()) { - stats -= it->second; - stats += info; - } else { - stats.replaceMalloc(it->second.getSize(), info.getSize()); - } - if (__lsan_trackMemory) { + if (__lsan_statsActive) { + if (it->second.getPointer() != info.getPointer()) { + stats -= it->second; + stats += info; + } else { + stats.replaceMalloc(it->second.getSize(), info.getSize()); + } it->second.setDeleted(true); } infos.insert_or_assign(info.getPointer(), info); @@ -179,7 +179,7 @@ size_t LSan::getTotalAllocatedBytes() { size_t LSan::getLeakCount() { std::lock_guard lock(infoMutex); - if (__lsan_trackMemory) { + if (__lsan_statsActive) { return static_cast(std::count_if(infos.cbegin(), infos.cend(), [] (auto & elem) -> bool { return !elem.second.isDeleted(); })); @@ -201,7 +201,7 @@ size_t LSan::getTotalLeakedBytes() { void LSan::__exit_hook() { using Formatter::Style; - getLocalInstance().setIgnoreMalloc(true); + getTracker().setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl << Formatter::get(Style::GREEN) << "Exiting" << Formatter::clear(Style::GREEN) diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 0360b04..2dbb60c 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -31,6 +31,8 @@ #include "statistics/Stats.hpp" #include "threadAllocInfo/ThreadAllocInfo.hpp" +#include "../include/lsan_internals.h" + /** * This class manages everything this sanitizer is capable to do. */ @@ -123,6 +125,13 @@ class LSan: public ATracker { */ static auto getInstance() -> LSan &; static auto getLocalInstance() -> ThreadAllocInfo &; + + static inline auto getTracker() -> ATracker & { + if (__lsan_statsActive) { + return getInstance(); + } + return getLocalInstance(); + } /** * Returns the current instance of the statitcs object. * diff --git a/code/signalHandlers.cpp b/code/signalHandlers.cpp index d664467..23e7dd0 100644 --- a/code/signalHandlers.cpp +++ b/code/signalHandlers.cpp @@ -66,7 +66,7 @@ static std::string signalString(int signal) { void callstackSignal(int) { using Formatter::Style; - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); bool ignore = instance.getIgnoreMalloc(); instance.setIgnoreMalloc(true); diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index 16f988d..5e181ea 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -296,12 +296,12 @@ static inline void __lsan_printFragmentationByteBar(size_t width, std::ostream & void __lsan_printFragmentationStatsWithWidth(size_t width) { using Formatter::Style; - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); bool ignore = instance.getIgnoreMalloc(); instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; - if (__lsan_fragmentationStatsAvailable()) { + if (__lsan_statsActive) { __lsan_printStatsCore("memory fragmentation", width, out, __lsan_printFragmentationByteBar, __lsan_printFragmentationObjectBar); @@ -325,7 +325,7 @@ void __lsan_printFragmentationStatsWithWidth(size_t width) { void __lsan_printStatsWithWidth(size_t width) { using Formatter::Style; - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); bool ignore = instance.getIgnoreMalloc(); instance.setIgnoreMalloc(true); diff --git a/code/wrap_malloc.cpp b/code/wrap_malloc.cpp index 206a0cb..2b3e9e2 100644 --- a/code/wrap_malloc.cpp +++ b/code/wrap_malloc.cpp @@ -35,7 +35,7 @@ bool __lsan_glibc = false; #endif auto __wrap_malloc(std::size_t size, const char * file, int line) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ret = LSan::malloc(size); if (ret != nullptr && !instance.getIgnoreMalloc()) { @@ -54,7 +54,7 @@ auto __wrap_malloc(std::size_t size, const char * file, int line) -> void * { } auto __wrap_calloc(std::size_t objectSize, std::size_t count, const char * file, int line) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ret = LSan::calloc(objectSize, count); if (ret != nullptr && !instance.getIgnoreMalloc()) { @@ -73,7 +73,7 @@ auto __wrap_calloc(std::size_t objectSize, std::size_t count, const char * file, } auto __wrap_realloc(void * pointer, std::size_t size, const char * file, int line) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ignored = instance.getIgnoreMalloc(); if (!ignored) { instance.setIgnoreMalloc(true); @@ -96,7 +96,7 @@ auto __wrap_realloc(void * pointer, std::size_t size, const char * file, int lin } void __wrap_free(void * pointer, const char * file, int line) { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); if (!instance.getIgnoreMalloc()) { instance.setIgnoreMalloc(true); @@ -119,7 +119,7 @@ void __wrap_free(void * pointer, const char * file, int line) { [[ noreturn ]] void __wrap_exit(int code, const char * file, int line) { using Formatter::Style; - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; @@ -139,7 +139,7 @@ void __wrap_free(void * pointer, const char * file, int line) { } auto malloc(std::size_t size) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ptr = LSan::malloc(size); if (ptr != nullptr && !instance.getIgnoreMalloc()) { @@ -158,7 +158,7 @@ auto malloc(std::size_t size) -> void * { } auto calloc(std::size_t objectSize, std::size_t count) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ptr = LSan::calloc(objectSize, count); if (ptr != nullptr && !instance.getIgnoreMalloc()) { @@ -177,7 +177,7 @@ auto calloc(std::size_t objectSize, std::size_t count) -> void * { } auto realloc(void * pointer, std::size_t size) -> void * { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); auto ignored = instance.getIgnoreMalloc(); if (!ignored) { instance.setIgnoreMalloc(true); @@ -200,7 +200,7 @@ auto realloc(void * pointer, std::size_t size) -> void * { } void free(void * pointer) { - auto & instance = LSan::getLocalInstance(); + auto & instance = LSan::getTracker(); if (!instance.getIgnoreMalloc()) { instance.setIgnoreMalloc(true); From 576a8be0632435495443d2ac72882e94c16730d2 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:43:50 +0200 Subject: [PATCH 37/58] Removed unneeded method --- code/statistics/Stats.cpp | 17 ----------------- code/statistics/Stats.hpp | 1 - 2 files changed, 18 deletions(-) diff --git a/code/statistics/Stats.cpp b/code/statistics/Stats.cpp index ff5dbaf..5a6ebe1 100644 --- a/code/statistics/Stats.cpp +++ b/code/statistics/Stats.cpp @@ -159,23 +159,6 @@ Stats & Stats::operator+=(const MallocInfo & mInfo) { return *this; } -auto Stats::operator+=(const Stats & other) -> Stats & { - std::lock_guard lock(mutex); - std::lock_guard lock_other(other.mutex); - - currentMallocCount += other.currentMallocCount; - totalMallocCount += other.totalMallocCount; - peekMallocCount += other.peekMallocCount; // FIXME: Revisit peek calculation! - - currentBytes += other.currentBytes; - totalBytes += other.totalBytes; - peekBytes += other.peekBytes; - - freeCount += other.freeCount; - - return *this; -} - Stats & Stats::operator-=(const MallocInfo & mInfo) { addFree(mInfo); return *this; diff --git a/code/statistics/Stats.hpp b/code/statistics/Stats.hpp index 4050cf6..acc022a 100644 --- a/code/statistics/Stats.hpp +++ b/code/statistics/Stats.hpp @@ -168,7 +168,6 @@ class Stats { * @return this instance */ auto operator+=(const MallocInfo & info) -> Stats &; - auto operator+=(const Stats & other) -> Stats &; /** * Removes the given allocation record from this instance and returns itself. * From b653c04e9023859ed76e6b8ad2ac5e02d9ba6d3c Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:51:41 +0200 Subject: [PATCH 38/58] Deactivated printing unavailable statistics --- code/statistics/lsan_stats.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index 5e181ea..e736b66 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -330,9 +330,22 @@ void __lsan_printStatsWithWidth(size_t width) { bool ignore = instance.getIgnoreMalloc(); instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; - __lsan_printStatsCore("memory usage", width, out, - std::bind(__lsan_printBar, __lsan_getCurrentByteCount(), __lsan_getBytePeek(), std::placeholders::_1, bytesToString(__lsan_getBytePeek()), std::placeholders::_2), - std::bind(__lsan_printBar, __lsan_getCurrentMallocCount(), __lsan_getMallocPeek(), std::placeholders::_1, std::to_string(__lsan_getMallocPeek()) + " objects", std::placeholders::_2)); + if (__lsan_statsActive) { + __lsan_printStatsCore("memory usage", width, out, + std::bind(__lsan_printBar, __lsan_getCurrentByteCount(), __lsan_getBytePeek(), std::placeholders::_1, bytesToString(__lsan_getBytePeek()), std::placeholders::_2), + std::bind(__lsan_printBar, __lsan_getCurrentMallocCount(), __lsan_getMallocPeek(), std::placeholders::_1, std::to_string(__lsan_getMallocPeek()) + " objects", std::placeholders::_2)); + } else { + out << Formatter::get(Style::BOLD) << Formatter::get(Style::RED) + << "No memory statistics available at the moment!" << std::endl + << Formatter::clear(Style::BOLD) << Formatter::get(Style::ITALIC) + << "Hint: Did you set " + << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) + << "__lsan_statsActive" + << Formatter::get(Style::ITALIC) << Formatter::get(Style::RED) << " to " + << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) + << "true" << Formatter::get(Style::RED) << Formatter::get(Style::ITALIC) << "?" + << Formatter::clearAll() << std::endl; + } if (!ignore) { instance.setIgnoreMalloc(false); } From cec5b099bee2058d69d51054758f4b249a8258b6 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 19:02:38 +0200 Subject: [PATCH 39/58] Removed unneeded class --- LeakSanitizer.xcodeproj/project.pbxproj | 12 ---- code/statistics/Peaks.cpp | 76 ------------------------- code/statistics/Peaks.hpp | 48 ---------------- 3 files changed, 136 deletions(-) delete mode 100644 code/statistics/Peaks.cpp delete mode 100644 code/statistics/Peaks.hpp diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index 6ad4e9e..b4224b5 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -40,10 +40,6 @@ BF378FAE2919484E00A4DAA9 /* lsan_internals.h in Headers */ = {isa = PBXBuildFile; fileRef = BF621FDC28A291DE00414EE4 /* lsan_internals.h */; settings = {ATTRIBUTES = (Public, ); }; }; BF378FB52919496000A4DAA9 /* libcallstack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF378FB42919496000A4DAA9 /* libcallstack.a */; }; BF378FB8291949D700A4DAA9 /* libcallstack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF378FB42919496000A4DAA9 /* libcallstack.a */; }; - BF41CC602A813C5000EAA3A1 /* Peaks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */; }; - BF41CC612A813C5000EAA3A1 /* Peaks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */; }; - BF41CC622A813C5000EAA3A1 /* Peaks.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */; }; - BF41CC632A813C5000EAA3A1 /* Peaks.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */; }; BF49A5D92899599300BC1FFD /* signalHandlers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF49A5D72899599300BC1FFD /* signalHandlers.cpp */; }; BF49A5DA2899599300BC1FFD /* signalHandlers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BF49A5D82899599300BC1FFD /* signalHandlers.hpp */; }; BF5FFC17289AAA6500006AC4 /* warn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BF5FFC15289AAA6500006AC4 /* warn.cpp */; }; @@ -76,8 +72,6 @@ BF30D8582A7815E8001D4EBF /* ThreadAllocInfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ThreadAllocInfo.hpp; sourceTree = ""; }; BF34157C2A8405AD00DEEF10 /* deprecation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = deprecation.h; sourceTree = ""; }; BF378FB42919496000A4DAA9 /* libcallstack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcallstack.a; path = CallstackLibrary/libcallstack.a; sourceTree = ""; }; - BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Peaks.cpp; sourceTree = ""; }; - BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Peaks.hpp; sourceTree = ""; }; BF49A5D72899599300BC1FFD /* signalHandlers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = signalHandlers.cpp; sourceTree = ""; }; BF49A5D82899599300BC1FFD /* signalHandlers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = signalHandlers.hpp; sourceTree = ""; }; BF4C28E828B66033001EB53E /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; @@ -148,8 +142,6 @@ BF23A2DC289ECE6A00B17349 /* lsan_stats.cpp */, BF23A2E0289ED24200B17349 /* Stats.cpp */, BF23A2E1289ED24200B17349 /* Stats.hpp */, - BF41CC5E2A813C5000EAA3A1 /* Peaks.cpp */, - BF41CC5F2A813C5000EAA3A1 /* Peaks.hpp */, ); path = statistics; sourceTree = ""; @@ -230,7 +222,6 @@ BF0F1350291947C0008F0FCD /* Formatter.hpp in Headers */, BF378F962919483900A4DAA9 /* LeakSani.hpp in Headers */, BF378F932919482E00A4DAA9 /* Stats.hpp in Headers */, - BF41CC632A813C5000EAA3A1 /* Peaks.hpp in Headers */, BF378F9C2919483D00A4DAA9 /* warn.hpp in Headers */, BF378F992919483B00A4DAA9 /* MallocInfo.hpp in Headers */, BF378FA22919484500A4DAA9 /* crash.hpp in Headers */, @@ -251,7 +242,6 @@ BF72C3CF2885CB9E00C7AE5C /* leaksan.h in Headers */, BFBF736628831FC200BC4208 /* MallocInfo.hpp in Headers */, BF72C3CD2885CB9E00C7AE5C /* LeakSani.hpp in Headers */, - BF41CC622A813C5000EAA3A1 /* Peaks.hpp in Headers */, BF621FE328A2B61E00414EE4 /* bytePrinter.hpp in Headers */, BFBF736A28832F8100BC4208 /* wrap_malloc.hpp in Headers */, BF49A5DA2899599300BC1FFD /* signalHandlers.hpp in Headers */, @@ -343,7 +333,6 @@ BF0F132F29194783008F0FCD /* Formatter.cpp in Sources */, BF0F133229194786008F0FCD /* bytePrinter.cpp in Sources */, BF0F13382919478E008F0FCD /* lsan_internals.cpp in Sources */, - BF41CC612A813C5000EAA3A1 /* Peaks.cpp in Sources */, BF0F13352919478B008F0FCD /* lsan_stats.cpp in Sources */, BF0F133B29194791008F0FCD /* LeakSani.cpp in Sources */, BF0F133E29194794008F0FCD /* Stats.cpp in Sources */, @@ -363,7 +352,6 @@ BFAFADC628B4FDA40060076C /* Formatter.cpp in Sources */, BF49A5D92899599300BC1FFD /* signalHandlers.cpp in Sources */, BF23A2E2289ED24200B17349 /* Stats.cpp in Sources */, - BF41CC602A813C5000EAA3A1 /* Peaks.cpp in Sources */, BF621FE228A2B61E00414EE4 /* bytePrinter.cpp in Sources */, BF23A2DE289ECE6A00B17349 /* lsan_stats.cpp in Sources */, BF621FDD28A291DE00414EE4 /* lsan_internals.cpp in Sources */, diff --git a/code/statistics/Peaks.cpp b/code/statistics/Peaks.cpp deleted file mode 100644 index 2324994..0000000 --- a/code/statistics/Peaks.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * LeakSanitizer - Small library showing information about lost memory. - * - * Copyright (C) 2023 mhahnFr - * - * This file is part of the LeakSanitizer. This library is free software: - * you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this library, see the file LICENSE. If not, see . - */ - -#include "Peaks.hpp" - -Peaks::Peaks(Peaks && other): - mutex(), - peakMallocCount(std::move(other.peakByteCount)), - peakByteCount(std::move(other.peakByteCount)) -{} - -Peaks::Peaks(const Peaks & other): - mutex(), - peakMallocCount(other.peakMallocCount), - peakByteCount(other.peakByteCount) -{} - -auto Peaks::operator=(Peaks && other) -> Peaks & { - if (std::addressof(other) != this) { - std::lock_guard lock1(mutex), - lock2(other.mutex); - peakMallocCount = std::move(other.peakMallocCount); - peakByteCount = std::move(other.peakByteCount); - } - return *this; -} - -auto Peaks::operator=(const Peaks & other) -> Peaks & { - if (std::addressof(other) != this) { - std::lock_guard lock1(mutex), - lock2(other.mutex); - peakMallocCount = other.peakMallocCount; - peakByteCount = other.peakByteCount; - } - return *this; -} - -void Peaks::setPeakMallocCount(const std::size_t peakMallocCount) { - std::lock_guard lock(mutex); - - this->peakMallocCount = peakMallocCount; -} - -void Peaks::setPeakByteCount(const std::size_t peakByteCount) { - std::lock_guard lock(mutex); - - this->peakByteCount = peakByteCount; -} - -auto Peaks::getPeakMallocCount() const -> std::size_t { - std::lock_guard lock(mutex); - - return peakMallocCount; -} - -auto Peaks::getPeakByteCount() const -> std::size_t { - std::lock_guard lock(mutex); - - return peakByteCount; -} diff --git a/code/statistics/Peaks.hpp b/code/statistics/Peaks.hpp deleted file mode 100644 index 18a2cdc..0000000 --- a/code/statistics/Peaks.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * LeakSanitizer - Small library showing information about lost memory. - * - * Copyright (C) 2023 mhahnFr - * - * This file is part of the LeakSanitizer. This library is free software: - * you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * this library, see the file LICENSE. If not, see . - */ - -#ifndef Peaks_hpp -#define Peaks_hpp - -#include - -class Peaks { - mutable std::mutex mutex; - - std::size_t peakMallocCount; - std::size_t peakByteCount; - -public: - Peaks() = default; - ~Peaks() = default; - - Peaks(Peaks &&); - Peaks(const Peaks &); - - auto operator=(Peaks &&) -> Peaks &; - auto operator=(const Peaks &) -> Peaks &; - - void setPeakMallocCount(const std::size_t peakMallocCount); - void setPeakByteCount(const std::size_t peakByteCount); - - auto getPeakMallocCount() const -> std::size_t; - auto getPeakByteCount() const -> std::size_t; -}; - -#endif /* Peaks_hpp */ From 8fad6ddd9a17623a46b5d1788584d98528e894c9 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Thu, 10 Aug 2023 19:02:51 +0200 Subject: [PATCH 40/58] Made error printing prettier --- code/statistics/lsan_stats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index e736b66..bdf314a 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -315,7 +315,7 @@ void __lsan_printFragmentationStatsWithWidth(size_t width) { << Formatter::get(Style::ITALIC) << Formatter::get(Style::RED) << " to " << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) << "true" << Formatter::get(Style::RED) << Formatter::get(Style::ITALIC) << "?" - << Formatter::clearAll() << std::endl; + << Formatter::clearAll() << std::endl << std::endl; } if (!ignore) { instance.setIgnoreMalloc(false); @@ -344,7 +344,7 @@ void __lsan_printStatsWithWidth(size_t width) { << Formatter::get(Style::ITALIC) << Formatter::get(Style::RED) << " to " << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) << "true" << Formatter::get(Style::RED) << Formatter::get(Style::ITALIC) << "?" - << Formatter::clearAll() << std::endl; + << Formatter::clearAll() << std::endl << std::endl; } if (!ignore) { instance.setIgnoreMalloc(false); From 0ea2289a89a3ffea27d5dba9b27c533c95060b7b Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:58:22 +0200 Subject: [PATCH 41/58] Renamed `ATracker.h` -> `ATracker.hpp` --- LeakSanitizer.xcodeproj/project.pbxproj | 4 ++-- code/{ATracker.h => ATracker.hpp} | 6 +++--- code/LeakSani.hpp | 2 +- code/threadAllocInfo/ThreadAllocInfo.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) rename code/{ATracker.h => ATracker.hpp} (95%) diff --git a/LeakSanitizer.xcodeproj/project.pbxproj b/LeakSanitizer.xcodeproj/project.pbxproj index b4224b5..beab4fd 100644 --- a/LeakSanitizer.xcodeproj/project.pbxproj +++ b/LeakSanitizer.xcodeproj/project.pbxproj @@ -96,7 +96,7 @@ BFBF736928832F8100BC4208 /* wrap_malloc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = wrap_malloc.hpp; sourceTree = ""; }; BFBF736B2883323100BC4208 /* crash.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crash.cpp; sourceTree = ""; }; BFBF736C2883323100BC4208 /* crash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = crash.hpp; sourceTree = ""; }; - BFC898552A8530BB00F7CB6D /* ATracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ATracker.h; sourceTree = ""; }; + BFC898552A8530BB00F7CB6D /* ATracker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ATracker.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -203,7 +203,7 @@ BF49A5D82899599300BC1FFD /* signalHandlers.hpp */, BFBF736C2883323100BC4208 /* crash.hpp */, BFBF736928832F8100BC4208 /* wrap_malloc.hpp */, - BFC898552A8530BB00F7CB6D /* ATracker.h */, + BFC898552A8530BB00F7CB6D /* ATracker.hpp */, ); path = code; sourceTree = ""; diff --git a/code/ATracker.h b/code/ATracker.hpp similarity index 95% rename from code/ATracker.h rename to code/ATracker.hpp index 6783fa1..f9aa065 100644 --- a/code/ATracker.h +++ b/code/ATracker.hpp @@ -17,8 +17,8 @@ * this library, see the file LICENSE. If not, see . */ -#ifndef ATracker_h -#define ATracker_h +#ifndef ATracker_hpp +#define ATracker_hpp #include @@ -47,4 +47,4 @@ class ATracker { } }; -#endif /* ATracker_h */ +#endif /* ATracker_hpp */ diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 2dbb60c..21b3dac 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -25,7 +25,7 @@ #include #include -#include "ATracker.h" +#include "ATracker.hpp" #include "MallocInfo.hpp" #include "statistics/Stats.hpp" diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index dc0dcb3..48166d5 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -24,7 +24,7 @@ #include #include -#include "../ATracker.h" +#include "../ATracker.hpp" #include "../MallocInfo.hpp" #include "../statistics/Stats.hpp" From d2536cdc66bb166da08c42378fb3a398f5a9adf0 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:59:12 +0200 Subject: [PATCH 42/58] Managing the allocation ignoration flag individually --- code/ATracker.hpp | 10 ++-------- code/LeakSani.cpp | 13 +++++++++++++ code/LeakSani.hpp | 5 +++++ code/threadAllocInfo/ThreadAllocInfo.hpp | 9 +++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/code/ATracker.hpp b/code/ATracker.hpp index f9aa065..d3aaf5b 100644 --- a/code/ATracker.hpp +++ b/code/ATracker.hpp @@ -25,8 +25,6 @@ #include "MallocInfo.hpp" class ATracker { - std::atomic_bool ignoreMalloc = false; - public: virtual ~ATracker() {} @@ -38,13 +36,9 @@ class ATracker { return removeMalloc(info.getPointer()); } - constexpr inline void setIgnoreMalloc(const bool ignoreMalloc) { - this->ignoreMalloc = ignoreMalloc; - } + virtual void setIgnoreMalloc(const bool ignoreMalloc) = 0; - constexpr inline auto getIgnoreMalloc() const -> bool { - return ignoreMalloc; - } + virtual auto getIgnoreMalloc() const -> bool = 0; }; #endif /* ATracker_hpp */ diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 9712aee..2ec3841 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -166,6 +166,19 @@ void LSan::addMalloc(MallocInfo && info) { infos.insert_or_assign(info.getPointer(), info); } +auto LSan::getLocalIgnoreMalloc() const -> bool & { + static thread_local bool ignoreMalloc = false; + return ignoreMalloc; +} + +void LSan::setIgnoreMalloc(const bool ignoreMalloc) { + getLocalIgnoreMalloc() = ignoreMalloc; +} + +auto LSan::getIgnoreMalloc() const -> bool { + return getLocalIgnoreMalloc(); +} + void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } size_t LSan::getTotalAllocatedBytes() { diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 21b3dac..de0367f 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -51,6 +51,8 @@ class LSan: public ATracker { auto removeMallocHere(const void * pointer) -> bool; auto changeMallocHere(const MallocInfo & info) -> bool; + auto getLocalIgnoreMalloc() const -> bool &; + public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. LSan(); @@ -71,6 +73,9 @@ class LSan: public ATracker { return maybeChangeMalloc(info); } + virtual void setIgnoreMalloc(const bool ignoreMalloc) override; + virtual auto getIgnoreMalloc() const -> bool override; + /** * Calculates and returns the total count of allocated bytes that are stored inside the * principal list containing the allocation records. diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 48166d5..c8a6ac6 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -32,6 +32,7 @@ class ThreadAllocInfo: public ATracker { mutable std::recursive_mutex infosMutex; std::map infos; + bool ignoreMalloc = false; public: using Ref = std::reference_wrapper; @@ -58,6 +59,14 @@ class ThreadAllocInfo: public ATracker { return removeMalloc(pointer, true); } + virtual inline void setIgnoreMalloc(const bool ignoreMalloc) override { + this->ignoreMalloc = ignoreMalloc; + } + + virtual inline auto getIgnoreMalloc() const -> bool override { + return ignoreMalloc; + } + constexpr inline auto getInfos() -> std::map & { return infos; } From da63302c155d9ade9cc154bbcfcca30f6a1310bc Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:09:45 +0200 Subject: [PATCH 43/58] Corrected user guides --- code/statistics/lsan_stats.cpp | 2 +- include/lsan_internals.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index bdf314a..ff390d6 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -311,7 +311,7 @@ void __lsan_printFragmentationStatsWithWidth(size_t width) { << Formatter::clear(Style::BOLD) << Formatter::get(Style::ITALIC) << "Hint: Did you set " << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) - << "__lsan_trackMemory" + << "__lsan_statsActive" << Formatter::get(Style::ITALIC) << Formatter::get(Style::RED) << " to " << Formatter::clear(Style::RED) << Formatter::clear(Style::ITALIC) << "true" << Formatter::get(Style::RED) << Formatter::get(Style::ITALIC) << "?" diff --git a/include/lsan_internals.h b/include/lsan_internals.h index 9347e5e..26c5d3f 100644 --- a/include/lsan_internals.h +++ b/include/lsan_internals.h @@ -110,7 +110,7 @@ extern bool __lsan_freeNull; * * @since 1.2 */ -DEPRECATED("Since v1.5, fragmentation is tracked together with the statistics") +DEPRECATED("Since v1.5, replaced by __lsan_statsActive") extern bool __lsan_trackMemory; extern bool __lsan_statsActive; @@ -131,7 +131,7 @@ extern size_t __lsan_leakCount; * * If there are more functions in such a callstack, the top most functions are printed * and a message about the truncation is printed. - * Defaults to 20`. + * Defaults to `20`. * * @since 1.3 */ From 6c4275cc72b7b3fd664224c444888a806677a9e8 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:20:19 +0200 Subject: [PATCH 44/58] Updated the documentation --- include/lsan_internals.h | 10 +++++++++- include/lsan_stats.h | 32 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/include/lsan_internals.h b/include/lsan_internals.h index 26c5d3f..45241ae 100644 --- a/include/lsan_internals.h +++ b/include/lsan_internals.h @@ -60,7 +60,7 @@ extern bool __lsan_printFormatted; * @brief If this value is set to `true`, the license informations are printed upon normal termination * of the program. * - * Defaults to `true`. + * Defaults value is set by the Makefile. * * @since 1.1 */ @@ -113,6 +113,14 @@ extern bool __lsan_freeNull; DEPRECATED("Since v1.5, replaced by __lsan_statsActive") extern bool __lsan_trackMemory; +/** + * @brief If this value is set to `true`, the memory allocation statistics can be analyzed. + * + * It should be set at the very beginning of the program in order to get realistic results. + * Defaults `false`. + * + * @since 1.5 + */ extern bool __lsan_statsActive; /** diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 14fe35c..0354456 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -145,8 +145,8 @@ static inline bool __lsan_fragmentationStatsAvailable() { * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using the function - * `__lsan_fStatsAvailable()` and guarantees to not crash the program, even in the case the memory + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive` and guarantees to not crash the program, even in the case the memory * fragmentation statistics are unavailable. * * @since 1.2 @@ -159,8 +159,8 @@ void __lsan_printFStats(); * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using the function - * `__lsan_fragStatsAvailable()` and guarantees to not crash the program, even in the case the memory + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive` and guarantees to not crash the program, even in the case the memory * fragmentation statistics are unavailable. * * @since 1.2 @@ -173,8 +173,8 @@ void __lsan_printFragStats(); * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragmentationStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using the function - * `__lsan_fragmentationStatsAvailable()` and guarantees to not crash the program, even in the case the + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive` and guarantees to not crash the program, even in the case the * memory fragmentation statistics are unavailable. * * @since 1.2 @@ -186,8 +186,8 @@ void __lsan_printFragmentationStats(); * * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory fragmentation statistics using the - * function `__lsan_fStatsAvailable()`, and guarantees to not crash the program, even in the case the + * This function already checks for the availability of the memory fragmentation statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the * memory fragmentation statistics are unavailable. * * @param width The width in characters the printed bar should have. @@ -200,8 +200,8 @@ void __lsan_printFStatsWithWidth(size_t width); * * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory fragmentation statistics using the - * function `__lsan_fragStatsAvailable()`, and guarantees to not crash the program, even in the case the + * This function already checks for the availability of the memory fragmentation statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the * memory fragmentation statistics are unavailable. * * @param width The width in characters the printed bar should have. @@ -214,8 +214,8 @@ void __lsan_printFragStatsWithWidth(size_t width); * * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory fragmentation statistics using the - * function `__lsan_fragmentationStatsAvailable()`, and guarantees to not crash the program, even in + * This function already checks for the availability of the memory fragmentation statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in * the case the memory fragmentation statistics are unavailable. * * @param width The width in characters the printed bar should have. @@ -229,8 +229,8 @@ void __lsan_printFragmentationStatsWithWidth(size_t width); * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using the function - * `__lsan_statsAvailable()`, and guarantees to not crash the program, even in the case the memory + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the memory * statistics are unavailable. */ void __lsan_printStats(); @@ -240,8 +240,8 @@ void __lsan_printStats(); * * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using the function - * `__lsan_statsAvailable()`, and guarantees to not crash the program, even in the case the memory + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the memory * statistics are unavailable. * * @param width The width in characters the printed bar should have. From 99b6872b8b8467832d1860f92661b351990a9261 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:15:18 +0200 Subject: [PATCH 45/58] Moved `__lsan_printStatsOnExit` into the internals --- code/LeakSani.cpp | 2 -- code/lsan_internals.cpp | 30 ++++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 2ec3841..fa027f9 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -31,8 +31,6 @@ #include "../include/lsan_internals.h" #include "../include/lsan_stats.h" -bool __lsan_printStatsOnExit = false; - #ifdef __GLIBC__ extern "C" void * __libc_malloc (size_t); extern "C" void * __libc_calloc (size_t, size_t); diff --git a/code/lsan_internals.cpp b/code/lsan_internals.cpp index fec4181..4b327aa 100644 --- a/code/lsan_internals.cpp +++ b/code/lsan_internals.cpp @@ -19,30 +19,32 @@ #include "../include/lsan_internals.h" -bool __lsan_humanPrint = true; -bool __lsan_printCout = false; -bool __lsan_printFormatted = true; +bool __lsan_humanPrint = true; +bool __lsan_printCout = false; +bool __lsan_printFormatted = true; #ifdef NO_LICENSE -bool __lsan_printLicense = false; +bool __lsan_printLicense = false; #else -bool __lsan_printLicense = true; +bool __lsan_printLicense = true; #endif #ifdef NO_WEBSITE -bool __lsan_printWebsite = false; +bool __lsan_printWebsite = false; #else -bool __lsan_printWebsite = true; +bool __lsan_printWebsite = true; #endif -bool __lsan_invalidCrash = true; +bool __lsan_invalidCrash = true; -bool __lsan_invalidFree = false; -bool __lsan_freeNull = false; +bool __lsan_invalidFree = false; +bool __lsan_freeNull = false; -bool __lsan_trackMemory = false; -bool __lsan_statsActive = false; +bool __lsan_trackMemory = false; +bool __lsan_statsActive = false; -size_t __lsan_leakCount = 100; +bool __lsan_printStatsOnExit = false; -size_t __lsan_callstackSize = 20; +size_t __lsan_leakCount = 100; + +size_t __lsan_callstackSize = 20; From 1863e8f4703c5db29eecc3d3ba65b6a31c0423f3 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:31:30 +0200 Subject: [PATCH 46/58] Inlining wrapper functions now --- code/statistics/lsan_stats.cpp | 9 ---- include/lsan_stats.h | 84 +++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index ff390d6..1618ca4 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -38,15 +38,6 @@ size_t __lsan_getCurrentByteCount() { return LSan::getStats().getCurrentBytes( size_t __lsan_getMallocPeek() { return LSan::getStats().getMallocPeek(); } size_t __lsan_getBytePeek() { return LSan::getStats().getBytePeek(); } -void __lsan_printStats() { __lsan_printStatsWithWidth(100); } - -void __lsan_printFStats() { __lsan_printFragmentationStats(); } -void __lsan_printFragStats() { __lsan_printFragmentationStats(); } -void __lsan_printFragmentationStats() { __lsan_printFragmentationStatsWithWidth(100); } - -void __lsan_printFStatsWithWidth (size_t width) { __lsan_printFragmentationStatsWithWidth(width); } -void __lsan_printFragStatsWithWidth(size_t width) { __lsan_printFragmentationStatsWithWidth(width); } - /** * @brief Prints the statistics using the given parameters. * diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 0354456..86a2b74 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -96,7 +96,7 @@ size_t __lsan_getBytePeek(); * @since 1.1 */ DEPRECATED("Since v1.5, refer to __lsan_statsActive") -static inline bool __lsan_statsAvailable() { +static inline bool __lsan_statsAvailable() { return __lsan_statsActive; } @@ -109,7 +109,7 @@ static inline bool __lsan_statsAvailable() { * @since 1.2 */ DEPRECATED("Since v1.5 replaced by __lsan_statsActive") -static inline bool __lsan_fStatsAvailable() { +static inline bool __lsan_fStatsAvailable() { return __lsan_statsActive; } @@ -122,7 +122,7 @@ static inline bool __lsan_fStatsAvailable() { * @since 1.2 */ DEPRECATED("Since v1.5 replaced by __lsan_statsActive") -static inline bool __lsan_fragStatsAvailable() { +static inline bool __lsan_fragStatsAvailable() { return __lsan_statsActive; } @@ -135,28 +135,44 @@ static inline bool __lsan_fragStatsAvailable() { * @since 1.2 */ DEPRECATED("Since v1.5 replaced by __lsan_statsActive") -static inline bool __lsan_fragmentationStatsAvailable() { +static inline bool __lsan_fragmentationStatsAvailable() { return __lsan_statsActive; } /** * @brief Prints the statistics of the memory fragmentation. * - * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFStatsWithWidth(size_t)`. + * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` + * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. + * This function already checks for the availability of the memory fragmentation statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in + * the case the memory fragmentation statistics are unavailable. + * + * @param width The width in characters the printed bar should have. + * @since 1.2 + */ +void __lsan_printFragmentationStatsWithWidth(size_t width); + +/** + * @brief Prints the statistics of the memory fragmentation. + * + * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragmentationStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. * This function already checks for the availability of the memory statistics using - * `__lsan_statsActive` and guarantees to not crash the program, even in the case the memory - * fragmentation statistics are unavailable. + * `__lsan_statsActive` and guarantees to not crash the program, even in the case the + * memory fragmentation statistics are unavailable. * * @since 1.2 */ -void __lsan_printFStats(); +static inline void __lsan_printFragmentationStats() { + __lsan_printFragmentationStatsWithWidth(100); +} /** * @brief Prints the statistics of the memory fragmentation. * - * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragStatsWithWidth(size_t)`. + * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. * This function already checks for the availability of the memory statistics using @@ -165,21 +181,25 @@ void __lsan_printFStats(); * * @since 1.2 */ -void __lsan_printFragStats(); +static inline void __lsan_printFStats() { + __lsan_printFragmentationStats(); +} /** * @brief Prints the statistics of the memory fragmentation. * - * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragmentationStatsWithWidth(size_t)`. + * The bar has a size of 100 characters, it can be adjusted by using `__lsan_printFragStatsWithWidth(size_t)`. * The output stream defined by `__lsan_printCout` is used for the printing. The byte amounts are printed * human readable if `__lsan_humanPrint` is set to true. * This function already checks for the availability of the memory statistics using - * `__lsan_statsActive` and guarantees to not crash the program, even in the case the - * memory fragmentation statistics are unavailable. + * `__lsan_statsActive` and guarantees to not crash the program, even in the case the memory + * fragmentation statistics are unavailable. * * @since 1.2 */ -void __lsan_printFragmentationStats(); +static inline void __lsan_printFragStats() { + __lsan_printFragmentationStats(); +} /** * @brief Prints the statistics of the memory fragmentation. @@ -193,7 +213,9 @@ void __lsan_printFragmentationStats(); * @param width The width in characters the printed bar should have. * @since 1.2 */ -void __lsan_printFStatsWithWidth(size_t width); +static inline void __lsan_printFStatsWithWidth(size_t width) { + __lsan_printFragmentationStatsWithWidth(width); +} /** * @brief Prints the statistics of the memory fragmentation. @@ -207,21 +229,22 @@ void __lsan_printFStatsWithWidth(size_t width); * @param width The width in characters the printed bar should have. * @since 1.2 */ -void __lsan_printFragStatsWithWidth(size_t width); +static inline void __lsan_printFragStatsWithWidth(size_t width) { + __lsan_printFragmentationStatsWithWidth(width); +} /** - * @brief Prints the statistics of the memory fragmentation. + * @brief Prints the statistics of the allocations. * * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory fragmentation statistics using - * `__lsan_statsActive`, and guarantees to not crash the program, even in - * the case the memory fragmentation statistics are unavailable. + * This function already checks for the availability of the memory statistics using + * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the memory + * statistics are unavailable. * * @param width The width in characters the printed bar should have. - * @since 1.2 */ -void __lsan_printFragmentationStatsWithWidth(size_t width); +void __lsan_printStatsWithWidth(size_t width); /** * @brief Prints the statistics of the allocations. @@ -233,20 +256,9 @@ void __lsan_printFragmentationStatsWithWidth(size_t width); * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the memory * statistics are unavailable. */ -void __lsan_printStats(); - -/** - * @brief Prints the statistics of the allocations. - * - * The size of the bar is specified by the given argument. The output stream defined by `__lsan_printCout` - * is used for the printing. The byte amounts are printed human readable if `__lsan_humanPrint` is set to true. - * This function already checks for the availability of the memory statistics using - * `__lsan_statsActive`, and guarantees to not crash the program, even in the case the memory - * statistics are unavailable. - * - * @param width The width in characters the printed bar should have. - */ -void __lsan_printStatsWithWidth(size_t width); +static inline void __lsan_printStats() { + __lsan_printStatsWithWidth(100); +} #ifdef __cplusplus } // extern "C" From d36fe58d265301e975ec1e43fa95fc218e61641c Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:38:21 +0200 Subject: [PATCH 47/58] Removed unneeded header --- code/statistics/Stats.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/code/statistics/Stats.hpp b/code/statistics/Stats.hpp index acc022a..76560dc 100644 --- a/code/statistics/Stats.hpp +++ b/code/statistics/Stats.hpp @@ -22,7 +22,6 @@ #include #include -#include #include "../MallocInfo.hpp" From d799c2a8458eb9c31f7bb023b8fcfb4935428365 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:42:46 +0200 Subject: [PATCH 48/58] Removed unneeded left-overs --- code/threadAllocInfo/ThreadAllocInfo.cpp | 10 ---------- code/threadAllocInfo/ThreadAllocInfo.hpp | 7 +------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.cpp b/code/threadAllocInfo/ThreadAllocInfo.cpp index ad870d3..a3ad7b9 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.cpp +++ b/code/threadAllocInfo/ThreadAllocInfo.cpp @@ -21,8 +21,6 @@ #include "../LeakSani.hpp" -#include "../../include/lsan_internals.h" - ThreadAllocInfo::ThreadAllocInfo() { LSan::getInstance().registerThreadAllocInfo(*this); } @@ -66,11 +64,3 @@ auto ThreadAllocInfo::removeMalloc(const void * pointer, bool search) -> bool { infos.erase(it); return true; } - -void ThreadAllocInfo::lockMutex() const { - infosMutex.lock(); -} - -void ThreadAllocInfo::unlockMutex() const { - infosMutex.unlock(); -} diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index c8a6ac6..a1efff2 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -27,10 +27,8 @@ #include "../ATracker.hpp" #include "../MallocInfo.hpp" -#include "../statistics/Stats.hpp" - class ThreadAllocInfo: public ATracker { - mutable std::recursive_mutex infosMutex; + std::recursive_mutex infosMutex; std::map infos; bool ignoreMalloc = false; @@ -74,9 +72,6 @@ class ThreadAllocInfo: public ATracker { constexpr inline auto getInfos() const -> const std::map & { return infos; } - - void lockMutex() const; - void unlockMutex() const; }; #endif /* ThreadAllocInfo_hpp */ From e861e7e1aa444bc93c82104c9a91b0d4263598e0 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 22:57:50 +0200 Subject: [PATCH 49/58] Documented the new ThreadAllocInfo class --- code/threadAllocInfo/ThreadAllocInfo.hpp | 37 +++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index a1efff2..2dd3af9 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -27,13 +27,22 @@ #include "../ATracker.hpp" #include "../MallocInfo.hpp" +/** + * This class represents a thread local allocation tracker. + */ class ThreadAllocInfo: public ATracker { - std::recursive_mutex infosMutex; + /** The mutex used to protect the allocation infos. */ + std::recursive_mutex infosMutex; + /** The map containing the allocation infos. */ std::map infos; + + /** Indicates whether the allocations should be tracked at the moment. */ bool ignoreMalloc = false; public: + /** The reference wrapper type. */ using Ref = std::reference_wrapper; + /** The constant reference wrapper type. */ using CRef = std::reference_wrapper; ThreadAllocInfo(); @@ -46,7 +55,23 @@ class ThreadAllocInfo: public ATracker { ThreadAllocInfo & operator=(ThreadAllocInfo &&) = delete; virtual void addMalloc(MallocInfo && info) override; + + /** + * Exchanges the MallocInfo associated with the pointer of the given info + * by the given MallocInfo. + * + * @param info the info to be exchanged + * @param search indicates whether to search globally if not found here + * @return whether the info was exchanged + */ auto changeMalloc(const MallocInfo & info, bool search) -> bool; + /** + * Removes the MallocInfo associated with the given pointer. + * + * @param pointer the deallocated pointer + * @param search indicates whether to search globally if not found here + * @return whether the info was removed + */ auto removeMalloc(const void * pointer, bool search) -> bool; virtual inline auto changeMalloc(const MallocInfo & info) -> bool override { @@ -65,10 +90,20 @@ class ThreadAllocInfo: public ATracker { return ignoreMalloc; } + /** + * Returns a reference to the stored allocation infos. + * + * @return the stored allocation infos + */ constexpr inline auto getInfos() -> std::map & { return infos; } + /** + * Returns a reference to the stored allocation infos. + * + * @return the stored allocation infos + */ constexpr inline auto getInfos() const -> const std::map & { return infos; } From 84810979eaeb9267734eb9ae2b808d8f44029b60 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:19:33 +0200 Subject: [PATCH 50/58] Minor improvements and clean up --- code/LeakSani.cpp | 40 +++++++++++++++++++--------------------- code/LeakSani.hpp | 24 ++++++++++++++++-------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index fa027f9..ae2dd27 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -169,27 +169,19 @@ auto LSan::getLocalIgnoreMalloc() const -> bool & { return ignoreMalloc; } -void LSan::setIgnoreMalloc(const bool ignoreMalloc) { - getLocalIgnoreMalloc() = ignoreMalloc; -} - -auto LSan::getIgnoreMalloc() const -> bool { - return getLocalIgnoreMalloc(); -} - -void LSan::setCallstackSizeExceeded(bool exceeded) { callstackSizeExceeded = exceeded; } - -size_t LSan::getTotalAllocatedBytes() { - std::lock_guard lock(infoMutex); - size_t ret = 0; +auto LSan::getTotalAllocatedBytes() -> std::size_t { + std::lock_guard lock(infoMutex); + + std::size_t ret = 0; std::for_each(infos.cbegin(), infos.cend(), [&ret] (auto & elem) { ret += elem.second.getSize(); }); return ret; } -size_t LSan::getLeakCount() { - std::lock_guard lock(infoMutex); +auto LSan::getLeakCount() -> std::size_t { + std::lock_guard lock(infoMutex); + if (__lsan_statsActive) { return static_cast(std::count_if(infos.cbegin(), infos.cend(), [] (auto & elem) -> bool { return !elem.second.isDeleted(); @@ -199,9 +191,10 @@ size_t LSan::getLeakCount() { } } -size_t LSan::getTotalLeakedBytes() { - std::lock_guard lock(infoMutex); - size_t ret = 0; +auto LSan::getTotalLeakedBytes() -> std::size_t { + std::lock_guard lock(infoMutex); + + std::size_t ret = 0; for (const auto & elem : infos) { if (!elem.second.isDeleted()) { ret += elem.second.getSize(); @@ -212,6 +205,7 @@ size_t LSan::getTotalLeakedBytes() { void LSan::__exit_hook() { using Formatter::Style; + getTracker().setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl @@ -231,6 +225,7 @@ void internalCleanUp() { void LSan::printInformations(){ using Formatter::Style; + std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << "Report by " << Formatter::get(Style::BOLD) << "LeakSanitizer " << Formatter::clear(Style::BOLD) << Formatter::get(Style::ITALIC) << VERSION << Formatter::clear(Style::ITALIC) @@ -255,6 +250,7 @@ void LSan::printLicense() { void LSan::printWebsite() { using Formatter::Style; + std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << Formatter::get(Style::ITALIC) << "For more information, visit " @@ -266,12 +262,14 @@ void LSan::printWebsite() { std::ostream & operator<<(std::ostream & stream, LSan & self) { using Formatter::Style; - std::lock_guard lock(self.infoMutex); + + std::lock_guard lock(self.infoMutex); + if (!self.infos.empty()) { stream << Formatter::get(Style::ITALIC); - const size_t totalLeaks = self.getLeakCount(); + const std::size_t totalLeaks = self.getLeakCount(); stream << totalLeaks << " leaks total, " << bytesToString(self.getTotalLeakedBytes()) << " total" << std::endl << std::endl; - size_t i = 0; + std::size_t i = 0; for (const auto & leak : self.infos) { if (!leak.second.isDeleted()) { stream << leak.second << std::endl; diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index de0367f..d27da89 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -40,7 +40,7 @@ class LSan: public ATracker { /// A map containing all allocation records, sorted by their allocated pointers. std::map infos; /// The mutex used to protect the principal map. - mutable std::recursive_mutex infoMutex; + std::recursive_mutex infoMutex; /// An object holding all statistics. Stats stats; /// Indicates whether the set callstack size had been exceeded during the printing. @@ -73,8 +73,13 @@ class LSan: public ATracker { return maybeChangeMalloc(info); } - virtual void setIgnoreMalloc(const bool ignoreMalloc) override; - virtual auto getIgnoreMalloc() const -> bool override; + virtual inline void setIgnoreMalloc(const bool ignoreMalloc) override { + getLocalIgnoreMalloc() = ignoreMalloc; + } + + virtual inline auto getIgnoreMalloc() const -> bool override { + return getLocalIgnoreMalloc(); + } /** * Calculates and returns the total count of allocated bytes that are stored inside the @@ -82,23 +87,24 @@ class LSan: public ATracker { * * @return the total count of bytes found in the principal list */ - auto getTotalAllocatedBytes() -> size_t; + auto getTotalAllocatedBytes() -> std::size_t; /** * Calculates and returns the total count of bytes that are stored inside the principal * list and not marked as deallocated. * * @return the total count of leaked bytes */ - auto getTotalLeakedBytes() -> size_t; + auto getTotalLeakedBytes() -> std::size_t; /** * Calculates and returns the count of allocation records stored in the principal list * that are not marked as deallocated. * * @return the total count of leaked objects */ - auto getLeakCount() -> size_t; + auto getLeakCount() -> std::size_t; - inline auto getFragmentationInfos() const -> const std::map & { + constexpr inline auto getFragmentationInfos() const -> const std::map & { + // FIXME: Mutex anyone? return infos; } @@ -107,7 +113,9 @@ class LSan: public ATracker { * * @param exceeded whether the maximum callstack size has been exceeded */ - void setCallstackSizeExceeded(bool exceeded); + constexpr inline void setCallstackSizeExceeded(bool exceeded) { + callstackSizeExceeded = exceeded; + } void registerThreadAllocInfo(ThreadAllocInfo::Ref info); void removeThreadAllocInfo(ThreadAllocInfo::Ref info); From c220f3e950d4b2c6386363074299ef1f2791b14e Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:32:29 +0200 Subject: [PATCH 51/58] Documented the new functionality of the main class --- code/LeakSani.cpp | 4 +-- code/LeakSani.hpp | 64 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index ae2dd27..68c15b4 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -158,13 +158,13 @@ void LSan::addMalloc(MallocInfo && info) { stats += info; // No need to check __lsan_statsActive here, // since allocations are only added globally - // if the __lsan_statsActive is true. + // if __lsan_statsActive is true. // - mhahnFr infos.insert_or_assign(info.getPointer(), info); } -auto LSan::getLocalIgnoreMalloc() const -> bool & { +auto LSan::getLocalIgnoreMalloc() -> bool & { static thread_local bool ignoreMalloc = false; return ignoreMalloc; } diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index d27da89..b16f5b2 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -45,13 +45,32 @@ class LSan: public ATracker { Stats stats; /// Indicates whether the set callstack size had been exceeded during the printing. bool callstackSizeExceeded = false; + /** A vector holding the thread local tracker instances. */ + std::vector threadInfos; - std::vector threadInfos; - - auto removeMallocHere(const void * pointer) -> bool; + /** + * Attempts to remove an allocation in this instance. + * + * @param pointer the deallocated pointer + * @return whether an alloaction info was removed + */ + auto removeMallocHere(const void * pointer) -> bool; + /** + * Attempts to exchange the allocation record associated with the given + * allocation info by the given allocation record. + * + * @param info the allocation record + * @return whether an allocation record was replaced + */ auto changeMallocHere(const MallocInfo & info) -> bool; - auto getLocalIgnoreMalloc() const -> bool &; + /** + * Returns a reference to a thread local boolean value indicating + * whether to ignore allocations. + * + * @return the ignoration flag + */ + static auto getLocalIgnoreMalloc() -> bool &; public: /// Constructs the sanitizer manager. Initializes all variables and sets up the hooks and signal handlers. @@ -63,6 +82,15 @@ class LSan: public ATracker { LSan & operator=(const LSan &) = delete; LSan & operator=(const LSan &&) = delete; + /** + * @brief Attempts to exchange the allocation record associated with the given + * allocation record by the given allocation record. + * + * The allocation record is searched for globally and in all running threads. + * + * @param info the allocation record to be exchanged + * @return whether an allocation record was exchanged + */ auto maybeChangeMalloc(const MallocInfo & info) -> bool; virtual auto removeMalloc(const void * pointer) -> bool override; @@ -103,6 +131,11 @@ class LSan: public ATracker { */ auto getLeakCount() -> std::size_t; + /** + * Returns the globally tracked allocations. + * + * @return the globally tracked allocations + */ constexpr inline auto getFragmentationInfos() const -> const std::map & { // FIXME: Mutex anyone? return infos; @@ -117,7 +150,17 @@ class LSan: public ATracker { callstackSizeExceeded = exceeded; } + /** + * Registers the given thread local allocation tracker instance. + * + * @param info the tracker to be registered + */ void registerThreadAllocInfo(ThreadAllocInfo::Ref info); + /** + * Removes the given thread local allocation tracker instance. + * + * @param info the tracker to be removed + */ void removeThreadAllocInfo(ThreadAllocInfo::Ref info); /// A pointer to the real `malloc` function. @@ -136,9 +179,20 @@ class LSan: public ATracker { * * @return the current instance */ - static auto getInstance() -> LSan &; + static auto getInstance() -> LSan &; + /** + * Returns the thread local allocation tracker instance. + * + * @return the allocation tracker associated with the calling thread + */ static auto getLocalInstance() -> ThreadAllocInfo &; + /** + * Returns a reference to the tracker used to track allocations + * for the calling thread. + * + * @return the appropriate tracker + */ static inline auto getTracker() -> ATracker & { if (__lsan_statsActive) { return getInstance(); From fafe66faf8883107043d164dc77cb52f5deeaa05 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:50:48 +0200 Subject: [PATCH 52/58] Documented `ATracker` --- code/ATracker.hpp | 53 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/code/ATracker.hpp b/code/ATracker.hpp index d3aaf5b..9823f1e 100644 --- a/code/ATracker.hpp +++ b/code/ATracker.hpp @@ -20,25 +20,68 @@ #ifndef ATracker_hpp #define ATracker_hpp -#include - #include "MallocInfo.hpp" +/** + * This class defines the functionality of an allocation tracker. + */ class ATracker { public: virtual ~ATracker() {} + /** + * Adds the given allocation record to the tracked allocations. + * + * @param info the allocation record to be added + */ virtual void addMalloc(MallocInfo && info) = 0; + /** + * Attempts to exchange the allocation record associated with the given + * allocation record by the given allocation record. + * + * Implementors note: the record should be searched for globally if it is not + * found in this instance. + * + * @param info the allocation record to be exchanged + * @return whether the record was replaced + */ virtual auto changeMalloc(const MallocInfo & info) -> bool = 0; - virtual auto removeMalloc(const void * pointer) -> bool = 0; + /** + * Attempts to remove the allocation record associated with the given pointer. + * + * Implementors note: the record should be searched for globally if it is not + * found in this instance. + * + * @param pointer the deallocated pointer + * @return whether the record was removed + */ + virtual auto removeMalloc(const void * pointer) -> bool = 0; + /** + * Attempts to remove the allocation record associated with the given record. + * + * Implementors note: the record should be searched for globally if it is not + * found in this instance. + * + * @param info the allocation record + * @return whether the record was removed + */ inline auto removeMalloc(MallocInfo && info) -> bool { return removeMalloc(info.getPointer()); } + /** + * Sets whether upcoming allocations should be ignored. + * + * @param ignoreMalloc whether to ignore upcoming allocations + */ virtual void setIgnoreMalloc(const bool ignoreMalloc) = 0; - - virtual auto getIgnoreMalloc() const -> bool = 0; + /** + * Returns whether upcoming allocations should be ignored. + * + * @return whether to ignore upcoming allocations + */ + virtual auto getIgnoreMalloc() const -> bool = 0; }; #endif /* ATracker_hpp */ From b20704ca89a8e1303afb6176bfc428d06ec2a68b Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:55:54 +0200 Subject: [PATCH 53/58] Improved ignoring files of the CallstackLibrary in the makefile --- Makefile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0867560..e73f9da 100644 --- a/Makefile +++ b/Makefile @@ -23,11 +23,6 @@ LIB_NAME = $(CORE_NAME).a SHARED_L = $(CORE_NAME).so DYLIB_NA = $(CORE_NAME).dylib -SRC = $(shell find . -name \*.cpp \! -path \*CallstackLibrary\*) - -OBJS = $(patsubst %.cpp, %.o, $(SRC)) -DEPS = $(patsubst %.cpp, %.d, $(SRC)) - LIBCALLSTACK_NAME = libcallstack LIBCALLSTACK_DIR = ./CallstackLibrary LIBCALLSTACK_A = $(LIBCALLSTACK_DIR)/$(LIBCALLSTACK_NAME).a @@ -36,6 +31,10 @@ LIBCALLSTACK_DY = $(LIBCALLSTACK_DIR)/$(LIBCALLSTACK_NAME).dylib LIBCALLSTACK_EXTR = tmpLibCallstack LIBCALLSTACK_FLAG = 'CXX_DEMANGLER=true' +SRC = $(shell find . -name \*.cpp \! -path $(LIBCALLSTACK_DIR)\*) +OBJS = $(patsubst %.cpp, %.o, $(SRC)) +DEPS = $(patsubst %.cpp, %.d, $(SRC)) + LDFLAGS = -ldl -L$(LIBCALLSTACK_DIR) -lcallstack CXXFLAGS = -std=c++17 -Wall -pedantic -fPIC -Ofast From 4c1ed396c3f52eba93b62d0b8a0c8f356c0346ea Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:16:59 +0200 Subject: [PATCH 54/58] Fixed a possible data race --- code/LeakSani.hpp | 10 +++++++++- code/statistics/lsan_stats.cpp | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index b16f5b2..520d326 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -137,10 +137,18 @@ class LSan: public ATracker { * @return the globally tracked allocations */ constexpr inline auto getFragmentationInfos() const -> const std::map & { - // FIXME: Mutex anyone? return infos; } + /** + * Returns the mutex used to protect the global allocation container. + * + * @return the mutex + */ + constexpr inline auto getFragmentationInfoMutex() -> std::recursive_mutex & { + return infoMutex; + } + /** * Sets whether the maximum callstack size has been exceeded during the printing. * diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index 1618ca4..014a3d9 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -121,6 +121,7 @@ static inline void __lsan_printFragmentationObjectBar(size_t width, std::ostream << Formatter::get(Style::GREYED) << Formatter::get(Style::UNDERLINED); const auto & infos = LSan::getInstance().getFragmentationInfos(); + std::lock_guard lock(LSan::getInstance().getFragmentationInfoMutex()); auto it = infos.cbegin(); if (infos.size() < width) { const float step = static_cast(width) / infos.size(); @@ -200,6 +201,7 @@ static inline void __lsan_printFragmentationByteBar(size_t width, std::ostream & << Formatter::get(Style::GREYED) << Formatter::get(Style::UNDERLINED); const auto & infos = LSan::getInstance().getFragmentationInfos(); + std::lock_guard lock(LSan::getInstance().getFragmentationInfoMutex()); auto it = infos.cbegin(); size_t currentBlockBegin = 0, currentBlockEnd = it->second.getSize(), From 963657e8cd5f1a83494787651bb8c7a7640d85da Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 16 Aug 2023 14:28:57 +0200 Subject: [PATCH 55/58] Added deprecation documentation --- include/lsan_internals.h | 2 ++ include/lsan_stats.h | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/include/lsan_internals.h b/include/lsan_internals.h index 45241ae..f549c79 100644 --- a/include/lsan_internals.h +++ b/include/lsan_internals.h @@ -103,6 +103,8 @@ extern bool __lsan_invalidFree; extern bool __lsan_freeNull; /** + * @deprecated Since 1.5, replaced by `__lsan_statsActive`. Will be removed in v2. + * * @brief If this value is set to `true`, the memory fragmentation can be analyzed. * * It should be set at the very beginning of the program in order to get realistic results. diff --git a/include/lsan_stats.h b/include/lsan_stats.h index 86a2b74..33dae15 100644 --- a/include/lsan_stats.h +++ b/include/lsan_stats.h @@ -88,6 +88,8 @@ size_t __lsan_getMallocPeek(); size_t __lsan_getBytePeek(); /** + * @deprecated Since 1.5, refer to `__lsan_statsActive`. Will be removed in v2. + * * @brief Returns whether the memory statistics can savely be queried. * * If it returns `false`, but the memory statistics are queried regardless, the library might crash! @@ -101,6 +103,8 @@ static inline bool __lsan_statsAvailable() { } /** + * @deprecated Since 1.5, replaced by `__lsan_statsActive`. Will be removed in v2. + * * @brief Returns whether the memory fragmentation statistics can be queried savely. * * If it returns `false`, the statistics can be queried regardless without crash, but they might be wrong. @@ -114,6 +118,8 @@ static inline bool __lsan_fStatsAvailable() { } /** + * @deprecated Since 1.5, replaced by `__lsan_statsActive`. Will be removed in v2. + * * @brief Returns whether the memory fragmentation statistics can be queried savely. * * If it returns `false`, the statistics can be queried regardless without crash, but they might be wrong. @@ -127,6 +133,8 @@ static inline bool __lsan_fragStatsAvailable() { } /** + * @deprecated Since 1.5 replaced by `__lsan_statsActive`. Will be removed in v2. + * * @brief Returns whether the memory fragmentation statistics can be queried savely. * * If it returns `false`, the statistics can be queried regardless without crash, but they might be wrong. From 62cc417293e8cde3e626bd11b01334d1ac0e609b Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:07:42 +0200 Subject: [PATCH 56/58] Fixed documentation --- include/lsan_internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lsan_internals.h b/include/lsan_internals.h index f549c79..cecb625 100644 --- a/include/lsan_internals.h +++ b/include/lsan_internals.h @@ -40,7 +40,7 @@ extern bool __lsan_humanPrint; * @brief If this value is set to `true`, normal messages are printed to the standard output stream. * * Otherwise the standard error stream is also used for normal messages. - * Defaults to `true`. + * Defaults to `false`. * * @since 1.1 */ From a1793be93595972532d45b8a69386b420a90d44d Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:43:14 +0200 Subject: [PATCH 57/58] Removed instance based allocation tracking flag --- code/ATracker.hpp | 13 ------------- code/LeakSani.hpp | 4 ++-- code/threadAllocInfo/ThreadAllocInfo.hpp | 11 ----------- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/code/ATracker.hpp b/code/ATracker.hpp index 9823f1e..3690c74 100644 --- a/code/ATracker.hpp +++ b/code/ATracker.hpp @@ -69,19 +69,6 @@ class ATracker { inline auto removeMalloc(MallocInfo && info) -> bool { return removeMalloc(info.getPointer()); } - - /** - * Sets whether upcoming allocations should be ignored. - * - * @param ignoreMalloc whether to ignore upcoming allocations - */ - virtual void setIgnoreMalloc(const bool ignoreMalloc) = 0; - /** - * Returns whether upcoming allocations should be ignored. - * - * @return whether to ignore upcoming allocations - */ - virtual auto getIgnoreMalloc() const -> bool = 0; }; #endif /* ATracker_hpp */ diff --git a/code/LeakSani.hpp b/code/LeakSani.hpp index 520d326..a3e6c62 100644 --- a/code/LeakSani.hpp +++ b/code/LeakSani.hpp @@ -101,11 +101,11 @@ class LSan: public ATracker { return maybeChangeMalloc(info); } - virtual inline void setIgnoreMalloc(const bool ignoreMalloc) override { + static inline void setIgnoreMalloc(const bool ignoreMalloc) { getLocalIgnoreMalloc() = ignoreMalloc; } - virtual inline auto getIgnoreMalloc() const -> bool override { + static inline auto getIgnoreMalloc() -> bool { return getLocalIgnoreMalloc(); } diff --git a/code/threadAllocInfo/ThreadAllocInfo.hpp b/code/threadAllocInfo/ThreadAllocInfo.hpp index 2dd3af9..5ee0f08 100644 --- a/code/threadAllocInfo/ThreadAllocInfo.hpp +++ b/code/threadAllocInfo/ThreadAllocInfo.hpp @@ -36,9 +36,6 @@ class ThreadAllocInfo: public ATracker { /** The map containing the allocation infos. */ std::map infos; - /** Indicates whether the allocations should be tracked at the moment. */ - bool ignoreMalloc = false; - public: /** The reference wrapper type. */ using Ref = std::reference_wrapper; @@ -82,14 +79,6 @@ class ThreadAllocInfo: public ATracker { return removeMalloc(pointer, true); } - virtual inline void setIgnoreMalloc(const bool ignoreMalloc) override { - this->ignoreMalloc = ignoreMalloc; - } - - virtual inline auto getIgnoreMalloc() const -> bool override { - return ignoreMalloc; - } - /** * Returns a reference to the stored allocation infos. * From f399ea0690f00a9051b99f4a0c78531e4dbd33e9 Mon Sep 17 00:00:00 2001 From: mhahnFr <83553794+mhahnFr@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:43:31 +0200 Subject: [PATCH 58/58] Replaced instance based allocation tracking flag by global one --- code/LeakSani.cpp | 2 +- code/signalHandlers.cpp | 7 ++- code/statistics/lsan_stats.cpp | 16 +++---- code/wrap_malloc.cpp | 88 +++++++++++++++------------------- 4 files changed, 49 insertions(+), 64 deletions(-) diff --git a/code/LeakSani.cpp b/code/LeakSani.cpp index 68c15b4..fd3f946 100644 --- a/code/LeakSani.cpp +++ b/code/LeakSani.cpp @@ -206,7 +206,7 @@ auto LSan::getTotalLeakedBytes() -> std::size_t { void LSan::__exit_hook() { using Formatter::Style; - getTracker().setIgnoreMalloc(true); + setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl << Formatter::get(Style::GREEN) << "Exiting" << Formatter::clear(Style::GREEN) diff --git a/code/signalHandlers.cpp b/code/signalHandlers.cpp index 23e7dd0..71c7b2d 100644 --- a/code/signalHandlers.cpp +++ b/code/signalHandlers.cpp @@ -66,10 +66,9 @@ static std::string signalString(int signal) { void callstackSignal(int) { using Formatter::Style; - auto & instance = LSan::getTracker(); - bool ignore = instance.getIgnoreMalloc(); + bool ignore = LSan::getIgnoreMalloc(); + LSan::setIgnoreMalloc(true); - instance.setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << Formatter::get(Style::ITALIC) << "The current callstack:" @@ -78,7 +77,7 @@ void callstackSignal(int) { MallocInfo::printCallstack(lcs::callstack(), out); out << std::endl; if (!ignore) { - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } } diff --git a/code/statistics/lsan_stats.cpp b/code/statistics/lsan_stats.cpp index 014a3d9..3d40c95 100644 --- a/code/statistics/lsan_stats.cpp +++ b/code/statistics/lsan_stats.cpp @@ -289,10 +289,8 @@ static inline void __lsan_printFragmentationByteBar(size_t width, std::ostream & void __lsan_printFragmentationStatsWithWidth(size_t width) { using Formatter::Style; - auto & instance = LSan::getTracker(); - - bool ignore = instance.getIgnoreMalloc(); - instance.setIgnoreMalloc(true); + bool ignore = LSan::getIgnoreMalloc(); + LSan::setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; if (__lsan_statsActive) { __lsan_printStatsCore("memory fragmentation", width, out, @@ -311,17 +309,15 @@ void __lsan_printFragmentationStatsWithWidth(size_t width) { << Formatter::clearAll() << std::endl << std::endl; } if (!ignore) { - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } } void __lsan_printStatsWithWidth(size_t width) { using Formatter::Style; - auto & instance = LSan::getTracker(); - - bool ignore = instance.getIgnoreMalloc(); - instance.setIgnoreMalloc(true); + bool ignore = LSan::getIgnoreMalloc(); + LSan::setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; if (__lsan_statsActive) { __lsan_printStatsCore("memory usage", width, out, @@ -340,6 +336,6 @@ void __lsan_printStatsWithWidth(size_t width) { << Formatter::clearAll() << std::endl << std::endl; } if (!ignore) { - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } } diff --git a/code/wrap_malloc.cpp b/code/wrap_malloc.cpp index 2b3e9e2..90aece7 100644 --- a/code/wrap_malloc.cpp +++ b/code/wrap_malloc.cpp @@ -35,11 +35,10 @@ bool __lsan_glibc = false; #endif auto __wrap_malloc(std::size_t size, const char * file, int line) -> void * { - auto & instance = LSan::getTracker(); - auto ret = LSan::malloc(size); + auto ret = LSan::malloc(size); - if (ret != nullptr && !instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (ret != nullptr && !LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (size == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", file, line, __builtin_return_address(0)); @@ -47,18 +46,17 @@ auto __wrap_malloc(std::size_t size, const char * file, int line) -> void * { crash("Invalid allocation of size 0", file, line, __builtin_return_address(0)); } } - instance.addMalloc(MallocInfo(ret, size, file, line, __builtin_return_address(0))); - instance.setIgnoreMalloc(false); + LSan::getTracker().addMalloc(MallocInfo(ret, size, file, line, __builtin_return_address(0))); + LSan::setIgnoreMalloc(false); } return ret; } auto __wrap_calloc(std::size_t objectSize, std::size_t count, const char * file, int line) -> void * { - auto & instance = LSan::getTracker(); - auto ret = LSan::calloc(objectSize, count); + auto ret = LSan::calloc(objectSize, count); - if (ret != nullptr && !instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (ret != nullptr && !LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (objectSize * count == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", file, line, __builtin_return_address(0)); @@ -66,19 +64,19 @@ auto __wrap_calloc(std::size_t objectSize, std::size_t count, const char * file, crash("Invalid allocation of size 0", file, line, __builtin_return_address(0)); } } - instance.addMalloc(MallocInfo(ret, objectSize * count, file, line, __builtin_return_address(0))); - instance.setIgnoreMalloc(false); + LSan::getTracker().addMalloc(MallocInfo(ret, objectSize * count, file, line, __builtin_return_address(0))); + LSan::setIgnoreMalloc(false); } return ret; } auto __wrap_realloc(void * pointer, std::size_t size, const char * file, int line) -> void * { - auto & instance = LSan::getTracker(); - auto ignored = instance.getIgnoreMalloc(); + auto ignored = LSan::getIgnoreMalloc(); if (!ignored) { - instance.setIgnoreMalloc(true); + LSan::setIgnoreMalloc(true); } - void * ptr = LSan::realloc(pointer, size); + auto & instance = LSan::getTracker(); + void * ptr = LSan::realloc(pointer, size); if (!ignored) { if (ptr != nullptr) { if (pointer != ptr) { @@ -90,20 +88,18 @@ auto __wrap_realloc(void * pointer, std::size_t size, const char * file, int lin instance.changeMalloc(MallocInfo(ptr, size, file, line, __builtin_return_address(0))); } } - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } return ptr; } void __wrap_free(void * pointer, const char * file, int line) { - auto & instance = LSan::getTracker(); - - if (!instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (!LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (pointer == nullptr && __lsan_freeNull) { warn("Free of NULL", file, line, __builtin_return_address(0)); } - bool removed = instance.removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); + bool removed = LSan::getTracker().removeMalloc(MallocInfo(pointer, 0, file, line, __builtin_return_address(0))); if (__lsan_invalidFree && !removed) { if (__lsan_invalidCrash) { crash("Invalid free", file, line, __builtin_return_address(0)); @@ -111,7 +107,7 @@ void __wrap_free(void * pointer, const char * file, int line) { warn("Invalid free", file, line, __builtin_return_address(0)); } } - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } LSan::free(pointer); } @@ -119,9 +115,7 @@ void __wrap_free(void * pointer, const char * file, int line) { [[ noreturn ]] void __wrap_exit(int code, const char * file, int line) { using Formatter::Style; - auto & instance = LSan::getTracker(); - - instance.setIgnoreMalloc(true); + LSan::setIgnoreMalloc(true); std::ostream & out = __lsan_printCout ? std::cout : std::cerr; out << std::endl << Formatter::get(Style::GREEN) << "Exiting" << Formatter::clear(Style::GREEN) << " at " @@ -139,11 +133,10 @@ void __wrap_free(void * pointer, const char * file, int line) { } auto malloc(std::size_t size) -> void * { - auto & instance = LSan::getTracker(); - auto ptr = LSan::malloc(size); + auto ptr = LSan::malloc(size); - if (ptr != nullptr && !instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (ptr != nullptr && !LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (size == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", __builtin_return_address(0)); @@ -151,18 +144,17 @@ auto malloc(std::size_t size) -> void * { crash("Invalid allocation of size 0", __builtin_return_address(0)); } } - instance.addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); - instance.setIgnoreMalloc(false); + LSan::getTracker().addMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); + LSan::setIgnoreMalloc(false); } return ptr; } auto calloc(std::size_t objectSize, std::size_t count) -> void * { - auto & instance = LSan::getTracker(); - auto ptr = LSan::calloc(objectSize, count); + auto ptr = LSan::calloc(objectSize, count); - if (ptr != nullptr && !instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (ptr != nullptr && !LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (objectSize * count == 0) { if (!__lsan_invalidCrash || __lsan_glibc) { warn("Invalid allocation of size 0", __builtin_return_address(0)); @@ -170,19 +162,19 @@ auto calloc(std::size_t objectSize, std::size_t count) -> void * { crash("Invalid allocation of size 0", __builtin_return_address(0)); } } - instance.addMalloc(MallocInfo(ptr, objectSize * count, __builtin_return_address(0))); - instance.setIgnoreMalloc(false); + LSan::getTracker().addMalloc(MallocInfo(ptr, objectSize * count, __builtin_return_address(0))); + LSan::setIgnoreMalloc(false); } return ptr; } auto realloc(void * pointer, std::size_t size) -> void * { - auto & instance = LSan::getTracker(); - auto ignored = instance.getIgnoreMalloc(); + auto ignored = LSan::getIgnoreMalloc(); if (!ignored) { - instance.setIgnoreMalloc(true); + LSan::setIgnoreMalloc(true); } - void * ptr = LSan::realloc(pointer, size); + auto & instance = LSan::getTracker(); + void * ptr = LSan::realloc(pointer, size); if (!ignored) { if (ptr != nullptr) { if (pointer != ptr) { @@ -194,20 +186,18 @@ auto realloc(void * pointer, std::size_t size) -> void * { instance.changeMalloc(MallocInfo(ptr, size, __builtin_return_address(0))); } } - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } return ptr; } void free(void * pointer) { - auto & instance = LSan::getTracker(); - - if (!instance.getIgnoreMalloc()) { - instance.setIgnoreMalloc(true); + if (!LSan::getIgnoreMalloc()) { + LSan::setIgnoreMalloc(true); if (pointer == nullptr && __lsan_freeNull) { warn("Free of NULL", __builtin_return_address(0)); } - bool removed = instance.removeMalloc(pointer); + bool removed = LSan::getTracker().removeMalloc(pointer); if (__lsan_invalidFree && !removed) { if (__lsan_invalidCrash) { crash("Invalid free", __builtin_return_address(0)); @@ -215,7 +205,7 @@ void free(void * pointer) { warn("Invalid free", __builtin_return_address(0)); } } - instance.setIgnoreMalloc(false); + LSan::setIgnoreMalloc(false); } LSan::free(pointer); }