• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thetic / cpputest / 19415582192

17 Nov 2025 01:31AM UTC coverage: 96.394% (-2.9%) from 99.281%
19415582192

push

github

thetic
Use the affirmative form in CMake options

6362 of 6600 relevant lines covered (96.39%)

44262.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.77
/src/CppUTest/MemoryLeakDetector.cpp
1
/*
2
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *     * Redistributions of source code must retain the above copyright
8
 *       notice, this list of conditions and the following disclaimer.
9
 *     * Redistributions in binary form must reproduce the above copyright
10
 *       notice, this list of conditions and the following disclaimer in the
11
 *       documentation and/or other materials provided with the distribution.
12
 *     * Neither the name of the <organization> nor the
13
 *       names of its contributors may be used to endorse or promote products
14
 *       derived from this software without specific prior written permission.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ''AS IS'' AND ANY
17
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
#include "CppUTest/TestHarness.h"
28
#include "CppUTest/MemoryLeakDetector.h"
29
#include "CppUTest/TestMemoryAllocator.h"
30
#include "CppUTest/PlatformSpecificFunctions.h"
31
#include "CppUTest/SimpleMutex.h"
32

33
static const char* UNKNOWN = "<unknown>";
34

35
static const char GuardBytes[] = {'B','A','S'};
36

37
SimpleStringBuffer::SimpleStringBuffer() :
137✔
38
    positions_filled_(0), write_limit_(SIMPLE_STRING_BUFFER_LEN-1)
137✔
39
{
40
    buffer_[0] = '\0';
137✔
41
}
137✔
42

43
void SimpleStringBuffer::clear()
1,345✔
44
{
45
    positions_filled_ = 0;
1,345✔
46
    buffer_[0] = '\0';
1,345✔
47
}
1,345✔
48

49
void SimpleStringBuffer::add(const char* format, ...)
26,270✔
50
{
51
    const size_t positions_left = write_limit_ - positions_filled_;
26,270✔
52
    if (positions_left == 0) return;
26,270✔
53

54
    va_list arguments;
55
    va_start(arguments, format);
11,459✔
56
    const int count = PlatformSpecificVSNprintf(buffer_ + positions_filled_, positions_left+1, format, arguments);
11,459✔
57
    if (count > 0) positions_filled_ += (size_t) count;
11,459✔
58
    if (positions_filled_ > write_limit_) positions_filled_ = write_limit_;
11,459✔
59
    va_end(arguments);
11,459✔
60
}
61

62
void SimpleStringBuffer::addMemoryDump(const void* memory, size_t memorySize)
124✔
63
{
64
    const unsigned char* byteMemory = (const unsigned char*)memory;
124✔
65
    const size_t maxLineBytes = 16;
124✔
66
    size_t currentPos = 0;
124✔
67
    size_t p;
68

69
    while (currentPos < memorySize) {
322✔
70
        add("    %04lx: ", (unsigned long) currentPos);
198✔
71
        size_t bytesInLine = memorySize - currentPos;
198✔
72
        if (bytesInLine > maxLineBytes) {
198✔
73
            bytesInLine = maxLineBytes;
75✔
74
        }
75
        const size_t leftoverBytes = maxLineBytes - bytesInLine;
198✔
76

77
        for (p = 0; p < bytesInLine; p++) {
1,848✔
78
            add("%02hx ", (unsigned short) byteMemory[currentPos + p]);
1,650✔
79
            if (p == ((maxLineBytes / 2) - 1)) {
1,650✔
80
                add(" ");
85✔
81
            }
82
        }
83
        for (p = 0; p < leftoverBytes; p++) {
1,716✔
84
            add("   ");
1,518✔
85
        }
86
        if (leftoverBytes > (maxLineBytes/2)) {
198✔
87
            add(" ");
113✔
88
        }
89

90
        add("|");
198✔
91
        for (p = 0; p < bytesInLine; p++) {
1,848✔
92
            char toAdd = (char)byteMemory[currentPos + p];
1,650✔
93
            if (toAdd < ' ' || toAdd > '~') {
1,650✔
94
                toAdd = '.';
1,450✔
95
            }
96
            add("%c", (int)toAdd);
1,650✔
97
        }
98
        add("|\n");
198✔
99
        currentPos += bytesInLine;
198✔
100
    }
101
}
124✔
102

103
char* SimpleStringBuffer::toString()
34✔
104
{
105
    return buffer_;
34✔
106
}
107

108
void SimpleStringBuffer::setWriteLimit(size_t write_limit)
21✔
109
{
110
    write_limit_ = write_limit;
21✔
111
    if (write_limit_ > SIMPLE_STRING_BUFFER_LEN-1)
21✔
112
        write_limit_ = SIMPLE_STRING_BUFFER_LEN-1;
1✔
113
}
21✔
114
void SimpleStringBuffer::resetWriteLimit()
15✔
115
{
116
    write_limit_ = SIMPLE_STRING_BUFFER_LEN-1;
15✔
117
}
15✔
118

119
bool SimpleStringBuffer::reachedItsCapacity()
14✔
120
{
121
    return positions_filled_ >= write_limit_;
14✔
122
}
123

124
////////////////////////
125

126
#define MEM_LEAK_TOO_MUCH "\netc etc etc etc. !!!! Too many memory leaks to report. Bailing out\n"
127
#define MEM_LEAK_FOOTER "Total number of leaks: "
128
#define MEM_LEAK_ADDITION_MALLOC_WARNING "NOTE:\n" \
129
                                         "\tMemory leak reports about malloc and free can be caused by allocating using the cpputest version of malloc,\n" \
130
                                         "\tbut deallocate using the standard free.\n" \
131
                                         "\tIf this is the case, check whether your malloc/free replacements are working (#define malloc cpputest_malloc etc).\n"
132

133
MemoryLeakOutputStringBuffer::MemoryLeakOutputStringBuffer()
125✔
134
    : total_leaks_(0), giveWarningOnUsingMalloc_(false)
125✔
135
{
136
}
125✔
137

138
void MemoryLeakOutputStringBuffer::addAllocationLocation(const char* allocationFile, size_t allocationLineNumber, size_t allocationSize, TestMemoryAllocator* allocator)
4✔
139
{
140
    outputBuffer_.add("   allocated at file: %s line: %d size: %lu type: %s\n", allocationFile, (int) allocationLineNumber, (unsigned long) allocationSize, allocator->alloc_name());
4✔
141
}
4✔
142

143
void MemoryLeakOutputStringBuffer::addDeallocationLocation(const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* allocator)
4✔
144
{
145
    outputBuffer_.add("   deallocated at file: %s line: %d type: %s\n", freeFile, (int) freeLineNumber, allocator->free_name());
4✔
146
}
4✔
147

148
void MemoryLeakOutputStringBuffer::addNoMemoryLeaksMessage()
4✔
149
{
150
    outputBuffer_.add("No memory leaks were detected.");
4✔
151
}
4✔
152

153
void MemoryLeakOutputStringBuffer::startMemoryLeakReporting()
18✔
154
{
155
    giveWarningOnUsingMalloc_ = false;
18✔
156
    total_leaks_ = 0;
18✔
157

158
    size_t memory_leak_normal_footer_size = sizeof(MEM_LEAK_FOOTER) + 10 + sizeof(MEM_LEAK_TOO_MUCH); /* the number of leaks */
18✔
159
    size_t memory_leak_foot_size_with_malloc_warning = memory_leak_normal_footer_size + sizeof(MEM_LEAK_ADDITION_MALLOC_WARNING);
18✔
160

161
    outputBuffer_.setWriteLimit(SimpleStringBuffer::SIMPLE_STRING_BUFFER_LEN - memory_leak_foot_size_with_malloc_warning);
18✔
162
}
18✔
163

164
void MemoryLeakOutputStringBuffer::reportMemoryLeak(MemoryLeakDetectorNode* leak)
118✔
165
{
166
    if (total_leaks_ == 0) {
118✔
167
        addMemoryLeakHeader();
14✔
168
    }
169

170
    total_leaks_++;
118✔
171
    outputBuffer_.add("Alloc num (%u) Leak size: %lu Allocated at: %s and line: %d. Type: \"%s\"\n\tMemory: <%p> Content:\n",
236✔
172
            leak->number_, (unsigned long) leak->size_, leak->file_, (int) leak->line_, leak->allocator_->alloc_name(), (void*) leak->memory_);
118✔
173
    outputBuffer_.addMemoryDump(leak->memory_, leak->size_);
118✔
174

175
    if (SimpleString::StrCmp(leak->allocator_->alloc_name(), (const char*) "malloc") == 0)
118✔
176
        giveWarningOnUsingMalloc_ = true;
103✔
177
}
118✔
178

179
void MemoryLeakOutputStringBuffer::stopMemoryLeakReporting()
18✔
180
{
181
    if (total_leaks_ == 0) {
18✔
182
        addNoMemoryLeaksMessage();
4✔
183
        return;
4✔
184
    }
185

186
    bool buffer_reached_its_capacity = outputBuffer_.reachedItsCapacity();
14✔
187
    outputBuffer_.resetWriteLimit();
14✔
188

189
    if (buffer_reached_its_capacity)
14✔
190
        addErrorMessageForTooMuchLeaks();
2✔
191

192
    addMemoryLeakFooter(total_leaks_);
14✔
193

194
    if (giveWarningOnUsingMalloc_)
14✔
195
        addWarningForUsingMalloc();
3✔
196

197
}
198

199
void MemoryLeakOutputStringBuffer::addMemoryLeakHeader()
14✔
200
{
201
    outputBuffer_.add("Memory leak(s) found.\n");
14✔
202
}
14✔
203

204
void MemoryLeakOutputStringBuffer::addErrorMessageForTooMuchLeaks()
2✔
205
{
206
    outputBuffer_.add(MEM_LEAK_TOO_MUCH);
2✔
207
}
2✔
208

209
void MemoryLeakOutputStringBuffer::addMemoryLeakFooter(size_t amountOfLeaks)
14✔
210
{
211
    outputBuffer_.add("%s %d\n", MEM_LEAK_FOOTER, (int) amountOfLeaks);
14✔
212
}
14✔
213

214
void MemoryLeakOutputStringBuffer::addWarningForUsingMalloc()
3✔
215
{
216
    outputBuffer_.add(MEM_LEAK_ADDITION_MALLOC_WARNING);
3✔
217
}
3✔
218

219
void MemoryLeakOutputStringBuffer::reportDeallocateNonAllocatedMemoryFailure(const char* freeFile, size_t freeLine, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
2✔
220
{
221
    reportFailure("Deallocating non-allocated memory\n", "<unknown>", 0, 0, NullUnknownAllocator::defaultAllocator(), freeFile, freeLine, freeAllocator, reporter);
2✔
222
}
2✔
223

224
void MemoryLeakOutputStringBuffer::reportAllocationDeallocationMismatchFailure(MemoryLeakDetectorNode* node, const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
1✔
225
{
226
    reportFailure("Allocation/deallocation type mismatch\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter);
1✔
227
}
1✔
228

229
void MemoryLeakOutputStringBuffer::reportMemoryCorruptionFailure(MemoryLeakDetectorNode* node, const char* freeFile, size_t freeLineNumber, TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
1✔
230
{
231
        reportFailure("Memory corruption (written out of bounds?)\n", node->file_, node->line_, node->size_, node->allocator_, freeFile, freeLineNumber, freeAllocator, reporter);
1✔
232
}
1✔
233

234
void MemoryLeakOutputStringBuffer::reportFailure(const char* message, const char* allocFile, size_t allocLine, size_t allocSize, TestMemoryAllocator* allocAllocator, const char* freeFile, size_t freeLine,
4✔
235
        TestMemoryAllocator* freeAllocator, MemoryLeakFailure* reporter)
236
{
237
    outputBuffer_.add("%s", message);
4✔
238
    addAllocationLocation(allocFile, allocLine, allocSize, allocAllocator);
4✔
239
    addDeallocationLocation(freeFile, freeLine, freeAllocator);
4✔
240
    reporter->fail(toString());
4✔
241
}
4✔
242

243

244
char* MemoryLeakOutputStringBuffer::toString()
22✔
245
{
246
    return outputBuffer_.toString();
22✔
247
}
248

249
void MemoryLeakOutputStringBuffer::clear()
1,345✔
250
{
251
    outputBuffer_.clear();
1,345✔
252
}
1,345✔
253

254
////////////////////////
255

256
void MemoryLeakDetectorNode::init(char* memory, unsigned number, size_t size, TestMemoryAllocator* allocator, MemLeakPeriod period, unsigned char allocation_stage, const char* file, size_t line)
2,220✔
257
{
258
    number_ = number;
2,220✔
259
    memory_ = memory;
2,220✔
260
    size_ = size;
2,220✔
261
    allocator_ = allocator;
2,220✔
262
    period_ = period;
2,220✔
263
    allocation_stage_ = allocation_stage;
2,220✔
264
    file_ = file;
2,220✔
265
    line_ = line;
2,220✔
266
}
2,220✔
267

268
///////////////////////
269

270
bool MemoryLeakDetectorList::isInPeriod(MemoryLeakDetectorNode* node, MemLeakPeriod period)
182✔
271
{
272
    return period == mem_leak_period_all || node->period_ == period || (node->period_ != mem_leak_period_disabled && period == mem_leak_period_enabled);
182✔
273
}
274

275
bool MemoryLeakDetectorList::isInAllocationStage(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
4✔
276
{
277
    return node->allocation_stage_ == allocation_stage;
4✔
278
}
279

280
void MemoryLeakDetectorList::clearAllAccounting(MemLeakPeriod period)
220✔
281
{
282
    MemoryLeakDetectorNode* cur = head_;
220✔
283
    MemoryLeakDetectorNode* prev = NULLPTR;
220✔
284

285
    while (cur) {
228✔
286
        if (isInPeriod(cur, period)) {
8✔
287
            if (prev) {
5✔
288
                prev->next_ = cur->next_;
2✔
289
                cur = prev;
2✔
290
            }
291
            else {
292
                head_ = cur->next_;
3✔
293
                cur = head_;
3✔
294
                continue;
3✔
295
            }
296
        }
297
        prev = cur;
5✔
298
        cur = cur->next_;
5✔
299
    }
300
}
220✔
301

302
void MemoryLeakDetectorList::addNewNode(MemoryLeakDetectorNode* node)
2,223✔
303
{
304
    node->next_ = head_;
2,223✔
305
    head_ = node;
2,223✔
306
}
2,223✔
307

308
MemoryLeakDetectorNode* MemoryLeakDetectorList::removeNode(char* memory)
2,104✔
309
{
310
    MemoryLeakDetectorNode* cur = head_;
2,104✔
311
    MemoryLeakDetectorNode* prev = NULLPTR;
2,104✔
312
    while (cur) {
2,105✔
313
        if (cur->memory_ == memory) {
2,103✔
314
            if (prev) {
2,102✔
315
                prev->next_ = cur->next_;
1✔
316
                return cur;
1✔
317
            }
318
            else {
319
                head_ = cur->next_;
2,101✔
320
                return cur;
2,101✔
321
            }
322
        }
323
        prev = cur;
1✔
324
        cur = cur->next_;
1✔
325
    }
326
    return NULLPTR;
2✔
327
}
328

329
MemoryLeakDetectorNode* MemoryLeakDetectorList::retrieveNode(char* memory)
2✔
330
{
331
  MemoryLeakDetectorNode* cur = head_;
2✔
332
  while (cur) {
2✔
333
    if (cur->memory_ == memory)
1✔
334
      return cur;
1✔
335
    cur = cur->next_;
×
336
  }
337
  return NULLPTR;
1✔
338
}
339

340
MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakFrom(MemoryLeakDetectorNode* node, MemLeakPeriod period)
96,852✔
341
{
342
    for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_)
96,853✔
343
        if (isInPeriod(cur, period)) return cur;
127✔
344
    return NULLPTR;
96,726✔
345
}
346

347
MemoryLeakDetectorNode* MemoryLeakDetectorList::getLeakForAllocationStageFrom(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
222✔
348
{
349
    for (MemoryLeakDetectorNode* cur = node; cur; cur = cur->next_)
223✔
350
        if (isInAllocationStage(cur, allocation_stage)) return cur;
4✔
351
    return NULLPTR;
219✔
352
}
353

354
MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeak(MemLeakPeriod period)
96,727✔
355
{
356
    return getLeakFrom(head_, period);
96,727✔
357
}
358

359
MemoryLeakDetectorNode* MemoryLeakDetectorList::getFirstLeakForAllocationStage(unsigned char allocation_stage)
219✔
360
{
361
    return getLeakForAllocationStageFrom(head_, allocation_stage);
219✔
362
}
363

364
MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeak(MemoryLeakDetectorNode* node, MemLeakPeriod period)
125✔
365
{
366
    return getLeakFrom(node->next_, period);
125✔
367
}
368

369
MemoryLeakDetectorNode* MemoryLeakDetectorList::getNextLeakForAllocationStage(MemoryLeakDetectorNode* node, unsigned char allocation_stage)
3✔
370
{
371
    return getLeakForAllocationStageFrom(node->next_, allocation_stage);
3✔
372
}
373

374

375

376
size_t MemoryLeakDetectorList::getTotalLeaks(MemLeakPeriod period)
104,025✔
377
{
378
    size_t total_leaks = 0;
104,025✔
379
    for (MemoryLeakDetectorNode* node = head_; node; node = node->next_) {
104,072✔
380
        if (isInPeriod(node, period)) total_leaks++;
47✔
381
    }
382
    return total_leaks;
104,025✔
383
}
384

385
/////////////////////////////////////////////////////////////
386

387
unsigned long MemoryLeakDetectorTable::hash(char* memory)
4,454✔
388
{
389
    return (unsigned long)((size_t)memory % hash_prime);
4,454✔
390
}
391

392
void MemoryLeakDetectorTable::clearAllAccounting(MemLeakPeriod period)
3✔
393
{
394
    for (int i = 0; i < hash_prime; i++)
222✔
395
        table_[i].clearAllAccounting(period);
219✔
396
}
3✔
397

398
void MemoryLeakDetectorTable::addNewNode(MemoryLeakDetectorNode* node)
2,220✔
399
{
400
    table_[hash(node->memory_)].addNewNode(node);
2,220✔
401
}
2,220✔
402

403
MemoryLeakDetectorNode* MemoryLeakDetectorTable::removeNode(char* memory)
2,104✔
404
{
405
    return table_[hash(memory)].removeNode(memory);
2,104✔
406
}
407

408
MemoryLeakDetectorNode* MemoryLeakDetectorTable::retrieveNode(char* memory)
2✔
409
{
410
  return table_[hash(memory)].retrieveNode(memory);
2✔
411
}
412

413
size_t MemoryLeakDetectorTable::getTotalLeaks(MemLeakPeriod period)
1,425✔
414
{
415
    size_t total_leaks = 0;
1,425✔
416
    for (int i = 0; i < hash_prime; i++)
105,450✔
417
        total_leaks += table_[i].getTotalLeaks(period);
104,025✔
418
    return total_leaks;
1,425✔
419
}
420

421
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeak(MemLeakPeriod period)
1,325✔
422
{
423
    for (int i = 0; i < hash_prime; i++) {
97,258✔
424
        MemoryLeakDetectorNode* node = table_[i].getFirstLeak(period);
95,951✔
425
        if (node) return node;
95,951✔
426
    }
427
    return NULLPTR;
1,307✔
428
}
429

430
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getFirstLeakForAllocationStage(unsigned char allocation_stage)
3✔
431
{
432
    for (int i = 0; i < hash_prime; i++) {
136✔
433
        MemoryLeakDetectorNode* node = table_[i].getFirstLeakForAllocationStage(allocation_stage);
135✔
434
        if (node) return node;
135✔
435
    }
436
    return NULLPTR;
1✔
437
}
438

439
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeak(MemoryLeakDetectorNode* leak, MemLeakPeriod period)
125✔
440
{
441
    unsigned long i = hash(leak->memory_);
125✔
442
    MemoryLeakDetectorNode* node = table_[i].getNextLeak(leak, period);
125✔
443
    if (node) return node;
125✔
444

445
    for (++i; i < hash_prime; i++) {
792✔
446
        node = table_[i].getFirstLeak(period);
774✔
447
        if (node) return node;
774✔
448
    }
449
    return NULLPTR;
18✔
450
}
451

452
MemoryLeakDetectorNode* MemoryLeakDetectorTable::getNextLeakForAllocationStage(MemoryLeakDetectorNode* leak, unsigned char allocation_stage)
3✔
453
{
454
    unsigned long i = hash(leak->memory_);
3✔
455
    MemoryLeakDetectorNode* node = table_[i].getNextLeakForAllocationStage(leak, allocation_stage);
3✔
456
    if (node) return node;
3✔
457

458
    for (++i; i < hash_prime; i++) {
86✔
459
        node = table_[i].getFirstLeakForAllocationStage(allocation_stage);
84✔
460
        if (node) return node;
84✔
461
    }
462
    return NULLPTR;
2✔
463
}
464

465
/////////////////////////////////////////////////////////////
466

467
MemoryLeakDetector::MemoryLeakDetector(MemoryLeakFailure* reporter)
125✔
468
{
469
    doAllocationTypeChecking_ = true;
125✔
470
    allocationSequenceNumber_ = 1;
125✔
471
    current_period_ = mem_leak_period_disabled;
125✔
472
    current_allocation_stage_ = 0;
125✔
473
    reporter_ = reporter;
125✔
474
    mutex_ = new SimpleMutex;
125✔
475
}
125✔
476

477
MemoryLeakDetector::~MemoryLeakDetector()
241✔
478
{
479
    if (mutex_)
124✔
480
    {
481
        delete mutex_;
124✔
482
    }
483
}
241✔
484

485
void MemoryLeakDetector::clearAllAccounting(MemLeakPeriod period)
3✔
486
{
487
    memoryTable_.clearAllAccounting(period);
3✔
488
}
3✔
489

490
void MemoryLeakDetector::startChecking()
1,345✔
491
{
492
    outputBuffer_.clear();
1,345✔
493
    current_period_ = mem_leak_period_checking;
1,345✔
494
}
1,345✔
495

496
void MemoryLeakDetector::stopChecking()
1,329✔
497
{
498
    current_period_ = mem_leak_period_enabled;
1,329✔
499
}
1,329✔
500

501
unsigned char MemoryLeakDetector::getCurrentAllocationStage() const
4✔
502
{
503
    return current_allocation_stage_;
4✔
504
}
505

506
void MemoryLeakDetector::enable()
123✔
507
{
508
    current_period_ = mem_leak_period_enabled;
123✔
509
}
123✔
510

511
void MemoryLeakDetector::disable()
1✔
512
{
513
    current_period_ = mem_leak_period_disabled;
1✔
514
}
1✔
515

516
void MemoryLeakDetector::disableAllocationTypeChecking()
1✔
517
{
518
    doAllocationTypeChecking_ = false;
1✔
519
}
1✔
520

521
void MemoryLeakDetector::enableAllocationTypeChecking()
1✔
522
{
523
    doAllocationTypeChecking_ = true;
1✔
524
}
1✔
525

526
unsigned MemoryLeakDetector::getCurrentAllocationNumber()
×
527
{
528
    return allocationSequenceNumber_;
×
529
}
530

531
void MemoryLeakDetector::increaseAllocationStage()
4✔
532
{
533
    current_allocation_stage_++;
4✔
534
}
4✔
535

536
void MemoryLeakDetector::decreaseAllocationStage()
1✔
537
{
538
    current_allocation_stage_--;
1✔
539
}
1✔
540

541
SimpleMutex *MemoryLeakDetector::getMutex()
×
542
{
543
    return mutex_;
×
544
}
545

546
static size_t calculateVoidPointerAlignedSize(size_t size)
4,437✔
547
{
548
#ifndef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
549
    return (sizeof(void*) - (size % sizeof(void*))) + size;
4,437✔
550
#else
551
   return size;
552
#endif
553
}
554

555
size_t MemoryLeakDetector::sizeOfMemoryWithCorruptionInfo(size_t size)
4,437✔
556
{
557
    return calculateVoidPointerAlignedSize(size + memory_corruption_buffer_size);
4,437✔
558
}
559

560
MemoryLeakDetectorNode* MemoryLeakDetector::getNodeFromMemoryPointer(char* memory, size_t memory_size)
2,216✔
561
{
562
    return (MemoryLeakDetectorNode*) (void*) (memory + sizeOfMemoryWithCorruptionInfo(memory_size));
2,216✔
563
}
564

565
void MemoryLeakDetector::storeLeakInformation(MemoryLeakDetectorNode * node, char *new_memory, size_t size, TestMemoryAllocator *allocator, const char *file, size_t line)
2,220✔
566
{
567
    node->init(new_memory, allocationSequenceNumber_++, size, allocator, current_period_, current_allocation_stage_, file, line);
2,220✔
568
    addMemoryCorruptionInformation(node->memory_ + node->size_);
2,220✔
569
    memoryTable_.addNewNode(node);
2,220✔
570
}
2,220✔
571

572
char* MemoryLeakDetector::reallocateMemoryAndLeakInformation(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
3✔
573
{
574
    char* new_memory = reallocateMemoryWithAccountingInformation(allocator, memory, size, file, line, allocatNodesSeperately);
3✔
575
    if (new_memory == NULLPTR) return NULLPTR;
3✔
576

577
    MemoryLeakDetectorNode *node = createMemoryLeakAccountingInformation(allocator, size, new_memory, allocatNodesSeperately);
3✔
578
    storeLeakInformation(node, new_memory, size, allocator, file, line);
3✔
579
    return node->memory_;
3✔
580
}
581

582
void MemoryLeakDetector::invalidateMemory(char* memory)
2✔
583
{
584
#ifndef CPPUTEST_DISABLE_HEAP_POISON
585
  MemoryLeakDetectorNode* node = memoryTable_.retrieveNode(memory);
2✔
586
  if (node)
2✔
587
    PlatformSpecificMemset(memory, 0xCD, node->size_);
1✔
588
#endif
589
}
2✔
590

591
void MemoryLeakDetector::addMemoryCorruptionInformation(char* memory)
2,220✔
592
{
593
   for (size_t i=0; i<memory_corruption_buffer_size; i++)
8,880✔
594
      memory[i] = GuardBytes[i % sizeof(GuardBytes)];
6,660✔
595
}
2,220✔
596

597
bool MemoryLeakDetector::validMemoryCorruptionInformation(char* memory)
2,101✔
598
{
599
   for (size_t i=0; i<memory_corruption_buffer_size; i++)
8,401✔
600
      if (memory[i] != GuardBytes[i % sizeof(GuardBytes)])
6,301✔
601
          return false;
1✔
602
   return true;
2,100✔
603
}
604

605
bool MemoryLeakDetector::matchingAllocation(TestMemoryAllocator *alloc_allocator, TestMemoryAllocator *free_allocator)
2,102✔
606
{
607
    if (alloc_allocator == free_allocator) return true;
2,102✔
608
    if (!doAllocationTypeChecking_) return true;
2✔
609
    return free_allocator->isOfEqualType(alloc_allocator);
1✔
610
}
611

612
void MemoryLeakDetector::checkForCorruption(MemoryLeakDetectorNode* node, const char* file, size_t line, TestMemoryAllocator* allocator, bool allocateNodesSeperately)
2,102✔
613
{
614
    if (!matchingAllocation(node->allocator_->actualAllocator(), allocator->actualAllocator()))
2,102✔
615
        outputBuffer_.reportAllocationDeallocationMismatchFailure(node, file, line, allocator->actualAllocator(), reporter_);
1✔
616
    else if (!validMemoryCorruptionInformation(node->memory_ + node->size_))
2,101✔
617
        outputBuffer_.reportMemoryCorruptionFailure(node, file, line, allocator->actualAllocator(), reporter_);
1✔
618
    else if (allocateNodesSeperately)
2,100✔
619
        allocator->freeMemoryLeakNode((char*) node);
4✔
620
}
2,102✔
621

622
char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, bool allocatNodesSeperately)
136✔
623
{
624
    return allocMemory(allocator, size, UNKNOWN, 0, allocatNodesSeperately);
136✔
625
}
626

627
char* MemoryLeakDetector::allocateMemoryWithAccountingInformation(TestMemoryAllocator* allocator, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
2,218✔
628
{
629
    if (allocatNodesSeperately) return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size), file, line);
2,218✔
630
    else return allocator->alloc_memory(sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode), file, line);
2,216✔
631
}
632

633
char* MemoryLeakDetector::reallocateMemoryWithAccountingInformation(TestMemoryAllocator* /*allocator*/, char* memory, size_t size, const char* /*file*/, size_t /*line*/, bool allocatNodesSeperately)
3✔
634
{
635
    if (allocatNodesSeperately) return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size));
3✔
636
    else return (char*) PlatformSpecificRealloc(memory, sizeOfMemoryWithCorruptionInfo(size) + sizeof(MemoryLeakDetectorNode));
1✔
637
}
638

639
MemoryLeakDetectorNode* MemoryLeakDetector::createMemoryLeakAccountingInformation(TestMemoryAllocator* allocator, size_t size, char* memory, bool allocatNodesSeperately)
2,220✔
640
{
641
    if (allocatNodesSeperately) return (MemoryLeakDetectorNode*) (void*) allocator->allocMemoryLeakNode(sizeof(MemoryLeakDetectorNode));
2,220✔
642
    else return getNodeFromMemoryPointer(memory, size);
2,216✔
643
}
644

645
char* MemoryLeakDetector::allocMemory(TestMemoryAllocator* allocator, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
2,218✔
646
{
647
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
648
   allocatNodesSeperately = true;
649
#endif
650
    /* With malloc, it is harder to guarantee that the allocator free is called.
651
     * This is because operator new is overloaded via linker symbols, but malloc just via #defines.
652
     * If the same allocation is used and the wrong free is called, it will deallocate the memory leak information
653
     * without the memory leak detector ever noticing it!
654
     * So, for malloc, we'll allocate the memory separately so we can detect this and give a proper error.
655
     */
656

657
    char* memory = allocateMemoryWithAccountingInformation(allocator, size, file, line, allocatNodesSeperately);
2,218✔
658
    if (memory == NULLPTR) return NULLPTR;
2,218✔
659
    MemoryLeakDetectorNode* node = createMemoryLeakAccountingInformation(allocator, size, memory, allocatNodesSeperately);
2,217✔
660

661
    storeLeakInformation(node, memory, size, allocator, file, line);
2,217✔
662
    return node->memory_;
2,217✔
663
}
664

665
void MemoryLeakDetector::removeMemoryLeakInformationWithoutCheckingOrDeallocatingTheMemoryButDeallocatingTheAccountInformation(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately)
×
666
{
667
    MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory);
×
668
    if (allocatNodesSeperately) allocator->freeMemoryLeakNode( (char*) node);
×
669
}
×
670

671
void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, const char* file, size_t line, bool allocatNodesSeperately)
2,106✔
672
{
673
    if (memory == NULLPTR) return;
2,106✔
674

675
    MemoryLeakDetectorNode* node = memoryTable_.removeNode((char*) memory);
2,100✔
676
    if (node == NULLPTR) {
2,100✔
677
        outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_);
1✔
678
        return;
1✔
679
    }
680
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
681
   allocatNodesSeperately = true;
682
#endif
683
    if (!allocator->hasBeenDestroyed()) {
2,099✔
684
        size_t size = node->size_;
2,099✔
685
        checkForCorruption(node, file, line, allocator, allocatNodesSeperately);
2,099✔
686
        allocator->free_memory((char*) memory, size, file, line);
2,099✔
687
    }
688
}
689

690
void MemoryLeakDetector::deallocMemory(TestMemoryAllocator* allocator, void* memory, bool allocatNodesSeperately)
27✔
691
{
692
    deallocMemory(allocator, (char*) memory, UNKNOWN, 0, allocatNodesSeperately);
27✔
693
}
27✔
694

695
void MemoryLeakDetector::deallocAllMemoryInCurrentAllocationStage()
3✔
696
{
697
    char* memory = NULLPTR;
3✔
698
    MemoryLeakDetectorNode* node = memoryTable_.getFirstLeakForAllocationStage(current_allocation_stage_);
3✔
699
    while (node) {
6✔
700
        memory = node->memory_;
3✔
701
        TestMemoryAllocator* allocator = node->allocator_;
3✔
702
        node = memoryTable_.getNextLeakForAllocationStage(node, current_allocation_stage_);
3✔
703
        deallocMemory(allocator, memory, __FILE__, __LINE__);
3✔
704
    }
705
}
3✔
706

707
char* MemoryLeakDetector::reallocMemory(TestMemoryAllocator* allocator, char* memory, size_t size, const char* file, size_t line, bool allocatNodesSeperately)
4✔
708
{
709
#ifdef CPPUTEST_DISABLE_MEM_CORRUPTION_CHECK
710
   allocatNodesSeperately = true;
711
#endif
712
    if (memory) {
4✔
713
        MemoryLeakDetectorNode* node = memoryTable_.removeNode(memory);
4✔
714
        if (node == NULLPTR) {
4✔
715
            outputBuffer_.reportDeallocateNonAllocatedMemoryFailure(file, line, allocator, reporter_);
1✔
716
            return NULLPTR;
1✔
717
        }
718
        checkForCorruption(node, file, line, allocator, allocatNodesSeperately);
3✔
719
    }
720
    return reallocateMemoryAndLeakInformation(allocator, memory, size, file, line, allocatNodesSeperately);
3✔
721
}
722

723
void MemoryLeakDetector::ConstructMemoryLeakReport(MemLeakPeriod period)
18✔
724
{
725
    MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(period);
18✔
726

727
    outputBuffer_.startMemoryLeakReporting();
18✔
728

729
    while (leak) {
136✔
730
        outputBuffer_.reportMemoryLeak(leak);
118✔
731
        leak = memoryTable_.getNextLeak(leak, period);
118✔
732
    }
733

734
    outputBuffer_.stopMemoryLeakReporting();
18✔
735
}
18✔
736

737
const char* MemoryLeakDetector::report(MemLeakPeriod period)
18✔
738
{
739
    ConstructMemoryLeakReport(period);
18✔
740

741
    return outputBuffer_.toString();
18✔
742
}
743

744
void MemoryLeakDetector::markCheckingPeriodLeaksAsNonCheckingPeriod()
1,307✔
745
{
746
    MemoryLeakDetectorNode* leak = memoryTable_.getFirstLeak(mem_leak_period_checking);
1,307✔
747
    while (leak) {
1,314✔
748
        if (leak->period_ == mem_leak_period_checking) leak->period_ = mem_leak_period_enabled;
7✔
749
        leak = memoryTable_.getNextLeak(leak, mem_leak_period_checking);
7✔
750
    }
751
}
1,307✔
752

753
size_t MemoryLeakDetector::totalMemoryLeaks(MemLeakPeriod period)
1,425✔
754
{
755
    return memoryTable_.getTotalLeaks(period);
1,425✔
756
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc