Skip to content

Commit bc8bb89

Browse files
committed
[feat] fixes CoverageTool memory leaks
- adds destructors for classes and respective calls for them - provides a certain background for implementing test project collection in the future akjs akflsakfm [fixup] [asgs
1 parent 06bbd4b commit bc8bb89

23 files changed

+367
-432
lines changed

VSharp.CoverageInstrumenter/profiler/ILRewriter.cpp

Lines changed: 8 additions & 295 deletions
Large diffs are not rendered by default.

VSharp.CoverageInstrumenter/profiler/ILRewriter.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
#include "corprof.h"
77
#include <stdexcept>
88
#include "probes.h"
9+
#include "memory.h"
910

1011
#undef IfFailRet
11-
#define IfFailRet(EXPR) do { HRESULT hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
12+
#define IfFailRet(EXPR) do { if (std::atomic_load(&vsharp::shutdownInOrder)) { return S_OK; } HRESULT hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
1213

1314
#undef IfNullRet
14-
#define IfNullRet(EXPR) do { if ((EXPR) == NULL) return E_OUTOFMEMORY; } while (0)
15+
#define IfNullRet(EXPR) do { if (std::atomic_load(&vsharp::shutdownInOrder)) { return S_OK; } if ((EXPR) == NULL) return E_OUTOFMEMORY; } while (0)
1516

1617
struct ILInstr
1718
{

VSharp.CoverageInstrumenter/profiler/api.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <vector>
99

1010
using namespace vsharp;
11+
1112
extern "C" void SetEntryMain(char* assemblyName, int assemblyNameLength, char* moduleName, int moduleNameLength, int methodToken) {
1213
profilerState->setEntryMain(assemblyName, assemblyNameLength, moduleName, moduleNameLength, methodToken);
1314
LOG(tout << "received entry main" << std::endl);
@@ -18,9 +19,9 @@ extern "C" void GetHistory(UINT_PTR size, UINT_PTR bytes) {
1819

1920
std::atomic_fetch_add(&shutdownBlockingRequestsCount, 1);
2021
size_t tmpSize;
21-
auto tmpBytes = profilerState->coverageTracker->serializeCoverageReport(&tmpSize);
22+
historyBuffer = profilerState->coverageTracker->serializeCoverageReport(&tmpSize);
2223
*(ULONG*)size = tmpSize;
23-
*(char**)bytes = tmpBytes;
24+
*(char**)bytes = historyBuffer;
2425

2526
profilerState->coverageTracker->clear();
2627
profilerState->threadTracker->clear();
@@ -29,6 +30,11 @@ extern "C" void GetHistory(UINT_PTR size, UINT_PTR bytes) {
2930
LOG(tout << "GetHistory request handled!");
3031
}
3132

33+
extern "C" void ClearHistory() {
34+
delete historyBuffer;
35+
historyBuffer = nullptr;
36+
}
37+
3238
extern "C" void SetCurrentThreadId(int mapId) {
3339
LOG(tout << "Map current thread to: " << mapId);
3440
vsharp::profilerState->threadTracker->mapCurrentThread(mapId);

VSharp.CoverageInstrumenter/profiler/api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@
1212
extern "C" IMAGEHANDLER_API void SetEntryMain(char* assemblyName, int assemblyNameLength, char* moduleName, int moduleNameLength, int methodToken);
1313
extern "C" IMAGEHANDLER_API void GetHistory(UINT_PTR size, UINT_PTR bytes);
1414
extern "C" IMAGEHANDLER_API void SetCurrentThreadId(int mapId);
15+
extern "C" IMAGEHANDLER_API void ClearHistory();
16+
17+
static char* historyBuffer = nullptr;
1518

1619
#endif //VSHARP_COVERAGEINSTRUMENTER_API_H

VSharp.CoverageInstrumenter/profiler/corProfiler.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ CorProfiler::~CorProfiler()
3131

3232
HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown *pICorProfilerInfoUnk)
3333
{
34+
setbuf(stdout, NULL);
35+
36+
printf("PROFILER INITIALIZATION\n");
3437
const char* waitDebuggerAttached = std::getenv("COVERAGE_TOOL_WAIT_DEBUGGER_ATTACHED");
3538
volatile int done = waitDebuggerAttached == nullptr ? 1 : 0;
3639
while (!done) OS::sleepSeconds(1);
@@ -53,7 +56,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown *pICorProfilerInfoUnk
5356

5457
// TMP Windows fix
5558
#undef IfFailRet
56-
#define IfFailRet(EXPR) do { HRESULT hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
59+
#define IfFailRet(EXPR) do { if (std::atomic_load(&shutdownInOrder)) return S_OK; HRESULT hr = (EXPR); if(FAILED(hr)) { return (hr); } } while (0)
5760
IfFailRet(this->corProfilerInfo->SetEventMask(eventMask));
5861

5962
profilerState = new ProfilerState((ICorProfilerInfo8*)this);
@@ -64,27 +67,36 @@ HRESULT STDMETHODCALLTYPE CorProfiler::Initialize(IUnknown *pICorProfilerInfoUnk
6467

6568
HRESULT STDMETHODCALLTYPE CorProfiler::Shutdown()
6669
{
67-
profilerState->isFinished = true;
70+
printf("PROFILER SHUTDOWN\n");
71+
std::atomic_store(&shutdownInOrder, true);
6872

6973
// waiting until all current requests are resolved
7074
while (std::atomic_load(&shutdownBlockingRequestsCount) > 0) {}
7175

7276
LOG(tout << "SHUTDOWN");
7377
if (profilerState->isPassiveRun) {
78+
printf("serializing information\n");
7479

7580
size_t tmpSize;
76-
auto tmpBytes = profilerState->coverageTracker->serializeCoverageReport(&tmpSize);;
81+
auto tmpBytes = profilerState->coverageTracker->serializeCoverageReport(&tmpSize);
82+
83+
printf("saving to %s\n", profilerState->passiveResultPath);
7784

7885
std::ofstream fout;
7986
fout.open(profilerState->passiveResultPath, std::ios::out|std::ios::binary);
80-
fout.write(tmpBytes, static_cast<long>(tmpSize));
87+
if (!fout.write(tmpBytes, static_cast<long>(tmpSize)))
88+
printf("failure while saving the file\n");
8189
fout.close();
90+
91+
delete tmpBytes;
8292
}
8393

8494
#ifdef _LOGGING
8595
close_log();
8696
#endif
8797

98+
delete profilerState;
99+
88100
if (this->corProfilerInfo != nullptr)
89101
{
90102
this->corProfilerInfo->Release();
@@ -214,7 +226,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::FunctionUnloadStarted(FunctionID function
214226
HRESULT STDMETHODCALLTYPE CorProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock)
215227
{
216228
// the process was finished, ignoring all firther requests
217-
if (profilerState->isFinished) return S_OK;
229+
if (std::atomic_load(&shutdownInOrder)) return S_OK;
218230

219231
std::atomic_fetch_add(&shutdownBlockingRequestsCount, 1);
220232

@@ -421,6 +433,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::RootReferences(ULONG cRootRefs, ObjectID
421433

422434
HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionThrown(ObjectID thrownObjectId)
423435
{
436+
if (std::atomic_load(&shutdownInOrder)) return S_OK;
424437
auto exceptionName = GetObjectTypeName(thrownObjectId);
425438
LOG(
426439
if(profilerState->threadTracker->hasMapping()) {
@@ -454,7 +467,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFunctionLeave()
454467

455468
HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFilterEnter(FunctionID functionId)
456469
{
457-
if (profilerState->isFinished || !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
470+
if (std::atomic_load(&shutdownInOrder) || !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
458471
LOG(tout << "EXCEPTION Search filter enter");
459472
profilerState->threadTracker->filterEnter();
460473
UNUSED(functionId);
@@ -463,7 +476,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFilterEnter(FunctionID fun
463476

464477
HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionSearchFilterLeave()
465478
{
466-
if (profilerState->isFinished || !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
479+
if (std::atomic_load(&shutdownInOrder) || !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
467480
LOG(tout << "EXCEPTION Search filter leave");
468481
profilerState->threadTracker->filterLeave();
469482
return S_OK;
@@ -502,7 +515,8 @@ HRESULT STDMETHODCALLTYPE CorProfiler::ExceptionUnwindFunctionLeave()
502515
{
503516
LOG(tout << "EXCEPTION UNWIND FUNCTION LEAVE");
504517
// the process was finished, ignoring all further requests
505-
if (profilerState->isFinished || !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
518+
if (std::atomic_load(&shutdownInOrder)
519+
|| !profilerState->threadTracker->isCurrentThreadTracked()) return S_OK;
506520
profilerState->threadTracker->unwindFunctionLeave();
507521
return S_OK;
508522
}
@@ -719,6 +733,7 @@ HRESULT STDMETHODCALLTYPE CorProfiler::DynamicMethodJITCompilationFinished(Funct
719733
}
720734

721735
std::string CorProfiler::GetObjectTypeName(ObjectID objectId) {
736+
if (std::atomic_load(&shutdownInOrder)) return "";
722737
ClassID classId;
723738
corProfilerInfo->GetClassFromObject(objectId, &classId);
724739

@@ -739,6 +754,7 @@ std::string CorProfiler::GetObjectTypeName(ObjectID objectId) {
739754
}
740755

741756
std::string CorProfiler::GetFunctionName(FunctionID functionId) {
757+
if (std::atomic_load(&shutdownInOrder)) return "";
742758
ClassID classId;
743759
ModuleID moduleId;
744760
mdToken token;

VSharp.CoverageInstrumenter/profiler/coverageTracker.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ void MethodInfo::serialize(std::vector<char>& buffer) const {
1313
serializePrimitive(moduleNameLength, buffer);
1414
serializePrimitiveArray(moduleName, moduleNameLength, buffer);
1515
}
16+
17+
void MethodInfo::Dispose() {
18+
delete moduleName;
19+
delete assemblyName;
20+
}
1621
//endregion
1722

1823
//region CoverageRecord
@@ -21,27 +26,31 @@ void CoverageRecord::serialize(std::vector<char>& buffer) const {
2126
serializePrimitive(event, buffer);
2227
serializePrimitive(methodId, buffer);
2328
serializePrimitive(thread, buffer);
29+
serializePrimitive(timestamp, buffer);
2430
}
2531
//endregion
2632

33+
auto GetMicrosecondTime() {
34+
using namespace std::chrono;
35+
return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
36+
}
37+
2738
//region CoverageHistory
2839
CoverageHistory::CoverageHistory(OFFSET offset, int methodId) {
2940
auto insertResult = visitedMethods.insert(methodId);
30-
LOG(if (insertResult.second) {
31-
tout << "Visit method: " << methodId;
32-
});
33-
auto record = new CoverageRecord({offset, EnterMain, profilerState->threadInfo->getCurrentThread(), methodId});
41+
if (insertResult.second) {
42+
LOG(tout << "Visit method: " << methodId);
43+
}
44+
auto record = new CoverageRecord({offset, EnterMain, profilerState->threadInfo->getCurrentThread(), methodId, GetMicrosecondTime()});
3445
records.push_back(record);
3546
}
3647

3748
void CoverageHistory::addCoverage(OFFSET offset, CoverageEvent event, int methodId) {
3849
auto insertResult = visitedMethods.insert(methodId);
39-
LOG(
4050
if (insertResult.second) {
41-
tout << "Visit method: " << methodId;
51+
LOG(tout << "Visit method: " << methodId);
4252
}
43-
);
44-
auto record = new CoverageRecord({offset, event, profilerState->threadInfo->getCurrentThread(), methodId});
53+
auto record = new CoverageRecord({offset, event, profilerState->threadInfo->getCurrentThread(), methodId, GetMicrosecondTime()});
4554
records.push_back(record);
4655
}
4756

@@ -54,6 +63,8 @@ void CoverageHistory::serialize(std::vector<char>& buffer) const {
5463
}
5564

5665
CoverageHistory::~CoverageHistory() {
66+
for (auto r : records)
67+
delete r;
5768
records.clear();
5869
}
5970
//endregion
@@ -99,6 +110,7 @@ void CoverageTracker::invocationFinished() {
99110
coverage->serialize(buffer);
100111
}
101112

113+
delete coverage;
102114
trackedCoverage->remove();
103115

104116
serializedCoverageMutex.lock();
@@ -110,6 +122,7 @@ void CoverageTracker::invocationFinished() {
110122
char* CoverageTracker::serializeCoverageReport(size_t* size) {
111123
collectedMethodsMutex.lock();
112124
serializedCoverageMutex.lock();
125+
printf("got locks, converting info\n");
113126

114127
auto buffer = std::vector<char>();
115128
auto methodsToSerialize = std::vector<std::pair<int, MethodInfo>>();
@@ -126,6 +139,7 @@ char* CoverageTracker::serializeCoverageReport(size_t* size) {
126139
serializePrimitive(el.first, buffer);
127140
el.second.serialize(buffer);
128141
}
142+
printf("converted methods: %lld\n", buffer.size());
129143

130144
auto threadMapping = profilerState->threadTracker->getMapping();
131145
for (auto mapping: threadMapping) {
@@ -148,16 +162,25 @@ char* CoverageTracker::serializeCoverageReport(size_t* size) {
148162
serializePrimitiveArray(&serializedCoverage[i][0], serializedCoverage[i].size(), buffer);
149163
}
150164

165+
printf("converted reports: %lld\n", buffer.size());
166+
167+
for (auto cov : trackedCoverage->items())
168+
delete cov.second;
151169
trackedCoverage->clear();
152170
serializedCoverage.clear();
153171
methodsToSerialize.clear();
154172

155173
serializedCoverageMutex.unlock();
156174
collectedMethodsMutex.unlock();
157175

176+
printf("cleared and unlocked data\n");
177+
158178
*size = buffer.size();
159179
char* array = new char[*size];
180+
printf("successfully allocated\n");
160181
std::memcpy(array, &buffer[0], *size);
182+
183+
printf("total bytes: %lld", *size);
161184
return array;
162185
}
163186

@@ -179,9 +202,15 @@ void CoverageTracker::clear() {
179202

180203
CoverageTracker::~CoverageTracker(){
181204
clear();
205+
for (int i = 0; i < collectedMethods.size(); i++)
206+
collectedMethods[i].Dispose();
207+
collectedMethods.clear();
208+
delete trackedCoverage;
182209
}
183210

184211
void CoverageTracker::invocationAborted() {
212+
auto abortedCov = trackedCoverage->load();
213+
delete abortedCov;
185214
trackedCoverage->update([](CoverageHistory *cov) {
186215
return (CoverageHistory*) nullptr;
187216
});

VSharp.CoverageInstrumenter/profiler/coverageTracker.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ enum CoverageEvent {
1919
Call,
2020
Tailcall,
2121
TrackCoverage,
22-
StsfldHit
22+
StsfldHit,
23+
ThrowLeave,
2324
};
2425

2526
struct MethodInfo {
@@ -31,13 +32,17 @@ struct MethodInfo {
3132
std::string methodName;
3233

3334
void serialize(std::vector<char>& buffer) const;
35+
36+
// frees previously allocated resources for it; the object is not supposed to be used afterwards
37+
void Dispose();
3438
};
3539

3640
struct CoverageRecord {
3741
OFFSET offset;
3842
CoverageEvent event;
3943
ThreadID thread;
4044
int methodId;
45+
long long timestamp;
4146

4247
void serialize(std::vector<char>& buffer) const;
4348
};
@@ -63,9 +68,9 @@ class CoverageTracker {
6368
ThreadStorage<CoverageHistory*>* trackedCoverage;
6469
ThreadTracker* threadTracker;
6570
std::mutex serializedCoverageMutex;
66-
std::vector<std::vector<char>> serializedCoverage;
6771
std::vector<int> serializedCoverageThreadIds;
6872
public:
73+
std::vector<std::vector<char>> serializedCoverage;
6974
std::mutex collectedMethodsMutex;
7075
std::vector<MethodInfo> collectedMethods;
7176
explicit CoverageTracker(ThreadTracker* threadTracker, ThreadInfo* threadInfo, bool collectMainOnly);

0 commit comments

Comments
 (0)