• 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

79.15
/src/CppUTest/TestMemoryAllocator.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

28
#include "CppUTest/TestHarness.h"
29
#include "CppUTest/TestMemoryAllocator.h"
30
#include "CppUTest/PlatformSpecificFunctions.h"
31
#include "CppUTest/MemoryLeakDetector.h"
32

33
static char* checkedMalloc(size_t size)
18,079✔
34
{
35
    char* mem = (char*) PlatformSpecificMalloc(size);
18,079✔
36
    if (mem == NULLPTR)
18,079✔
37
    FAIL("malloc returned null pointer");
1✔
38
    return mem;
18,078✔
39
}
40

41
static TestMemoryAllocator* currentNewAllocator = NULLPTR;
42
static TestMemoryAllocator* currentNewArrayAllocator = NULLPTR;
43
static TestMemoryAllocator* currentMallocAllocator = NULLPTR;
44

45
void setCurrentNewAllocator(TestMemoryAllocator* allocator)
152✔
46
{
47
    currentNewAllocator = allocator;
152✔
48
}
152✔
49

50
TestMemoryAllocator* getCurrentNewAllocator()
176✔
51
{
52
    if (currentNewAllocator == NULLPTR) setCurrentNewAllocatorToDefault();
176✔
53
    return currentNewAllocator;
176✔
54
}
55

56
void setCurrentNewAllocatorToDefault()
32✔
57
{
58
    currentNewAllocator = defaultNewAllocator();
32✔
59
}
32✔
60

61
TestMemoryAllocator* defaultNewAllocator()
199✔
62
{
63
    static TestMemoryAllocator allocator("Standard New Allocator", "new", "delete");
199✔
64
    return &allocator;
199✔
65
}
66

67
void setCurrentNewArrayAllocator(TestMemoryAllocator* allocator)
57✔
68
{
69
    currentNewArrayAllocator = allocator;
57✔
70
}
57✔
71

72
TestMemoryAllocator* getCurrentNewArrayAllocator()
4,092✔
73
{
74
    if (currentNewArrayAllocator == NULLPTR) setCurrentNewArrayAllocatorToDefault();
4,092✔
75
    return currentNewArrayAllocator;
4,092✔
76
}
77

78
void setCurrentNewArrayAllocatorToDefault()
33✔
79
{
80
    currentNewArrayAllocator = defaultNewArrayAllocator();
33✔
81
}
33✔
82

83
TestMemoryAllocator* defaultNewArrayAllocator()
748✔
84
{
85
    static TestMemoryAllocator allocator("Standard New [] Allocator", "new []", "delete []");
748✔
86
    return &allocator;
748✔
87
}
88

89
void setCurrentMallocAllocator(TestMemoryAllocator* allocator)
57✔
90
{
91
    currentMallocAllocator = allocator;
57✔
92
}
57✔
93

94
TestMemoryAllocator* getCurrentMallocAllocator()
138✔
95
{
96
    if (currentMallocAllocator == NULLPTR) setCurrentMallocAllocatorToDefault();
138✔
97
    return currentMallocAllocator;
138✔
98
}
99

100
void setCurrentMallocAllocatorToDefault()
33✔
101
{
102
    currentMallocAllocator = defaultMallocAllocator();
33✔
103
}
33✔
104

105
TestMemoryAllocator* defaultMallocAllocator()
459✔
106
{
107
    static TestMemoryAllocator allocator("Standard Malloc Allocator", "malloc", "free");
459✔
108
    return &allocator;
459✔
109
}
110

111
/////////////////////////////////////////////
112

113
GlobalMemoryAllocatorStash::GlobalMemoryAllocatorStash()
22✔
114
    : originalMallocAllocator(NULLPTR), originalNewAllocator(NULLPTR), originalNewArrayAllocator(NULLPTR)
22✔
115
{
116
}
22✔
117

118
void GlobalMemoryAllocatorStash::save()
22✔
119
{
120
    originalMallocAllocator = getCurrentMallocAllocator();
22✔
121
    originalNewAllocator = getCurrentNewAllocator();
22✔
122
    originalNewArrayAllocator = getCurrentNewArrayAllocator();
22✔
123
}
22✔
124

125
void GlobalMemoryAllocatorStash::restore()
22✔
126
{
127
    if (originalMallocAllocator) setCurrentMallocAllocator(originalMallocAllocator);
22✔
128
    if (originalNewAllocator) setCurrentNewAllocator(originalNewAllocator);
22✔
129
    if (originalNewArrayAllocator) setCurrentNewArrayAllocator(originalNewArrayAllocator);
22✔
130
}
22✔
131

132
TestMemoryAllocator::TestMemoryAllocator(const char* name_str, const char* alloc_name_str, const char* free_name_str)
652✔
133
    : name_(name_str), alloc_name_(alloc_name_str), free_name_(free_name_str), hasBeenDestroyed_(false)
652✔
134
{
135
}
652✔
136

137
TestMemoryAllocator::~TestMemoryAllocator()
659✔
138
{
139
    hasBeenDestroyed_ = true;
651✔
140
}
659✔
141

142
bool TestMemoryAllocator::hasBeenDestroyed()
2,099✔
143
{
144
    return hasBeenDestroyed_;
2,099✔
145
}
146

147
bool TestMemoryAllocator::isOfEqualType(TestMemoryAllocator* allocator)
1✔
148
{
149
    return SimpleString::StrCmp(this->name(), allocator->name()) == 0;
1✔
150
}
151

152
char* TestMemoryAllocator::allocMemoryLeakNode(size_t size)
6✔
153
{
154
    return alloc_memory(size, "MemoryLeakNode", 1);
6✔
155
}
156

157
void TestMemoryAllocator::freeMemoryLeakNode(char* memory)
2✔
158
{
159
    free_memory(memory, 0, "MemoryLeakNode", 1);
2✔
160
}
2✔
161

162
char* TestMemoryAllocator::alloc_memory(size_t size, const char*, size_t)
18,079✔
163
{
164
    return checkedMalloc(size);
18,079✔
165
}
166

167
void TestMemoryAllocator::free_memory(char* memory, size_t, const char*, size_t)
17,913✔
168
{
169
    PlatformSpecificFree(memory);
17,913✔
170
}
17,913✔
171

172
const char* TestMemoryAllocator::name() const
6✔
173
{
174
    return name_;
6✔
175
}
176

177
const char* TestMemoryAllocator::alloc_name() const
835✔
178
{
179
    return alloc_name_;
835✔
180
}
181

182
const char* TestMemoryAllocator::free_name() const
19✔
183
{
184
    return free_name_;
19✔
185
}
186

187
TestMemoryAllocator* TestMemoryAllocator::actualAllocator()
4,213✔
188
{
189
    return this;
4,213✔
190
}
191

192
MemoryLeakAllocator::MemoryLeakAllocator(TestMemoryAllocator* originalAllocator)
19✔
193
    : originalAllocator_(originalAllocator)
19✔
194
{
195
}
19✔
196

197
MemoryLeakAllocator::~MemoryLeakAllocator()
38✔
198
{
199
}
38✔
200

201
char* MemoryLeakAllocator::alloc_memory(size_t size, const char* file, size_t line)
83✔
202
{
203
    return MemoryLeakWarningPlugin::getGlobalDetector()->allocMemory(originalAllocator_, size, file, line);
83✔
204
}
205

206
void MemoryLeakAllocator::free_memory(char* memory, size_t, const char* file, size_t line)
83✔
207
{
208
    MemoryLeakWarningPlugin::getGlobalDetector()->deallocMemory(originalAllocator_, memory, file, line);
83✔
209
}
83✔
210

211
const char* MemoryLeakAllocator::name() const
1✔
212
{
213
    return "MemoryLeakAllocator";
1✔
214
}
215

216
const char* MemoryLeakAllocator::alloc_name() const
1✔
217
{
218
    return originalAllocator_->alloc_name();
1✔
219
}
220

221
const char* MemoryLeakAllocator::free_name() const
1✔
222
{
223
    return originalAllocator_->free_name();
1✔
224
}
225

226
TestMemoryAllocator* MemoryLeakAllocator::actualAllocator()
3✔
227
{
228
    return originalAllocator_->actualAllocator();
3✔
229
}
230

231
CrashOnAllocationAllocator::CrashOnAllocationAllocator() : allocationToCrashOn_(0)
×
232
{
233
}
×
234

235
CrashOnAllocationAllocator::~CrashOnAllocationAllocator()
×
236
{
237
}
×
238

239
void CrashOnAllocationAllocator::setNumberToCrashOn(unsigned allocationToCrashOn)
×
240
{
241
    allocationToCrashOn_ = allocationToCrashOn;
×
242
}
×
243

244
char* CrashOnAllocationAllocator::alloc_memory(size_t size, const char* file, size_t line)
×
245
{
246
    if (MemoryLeakWarningPlugin::getGlobalDetector()->getCurrentAllocationNumber() == allocationToCrashOn_)
×
247
        UT_CRASH();
×
248

249
    return TestMemoryAllocator::alloc_memory(size, file, line);
×
250
}
251

252

253
NullUnknownAllocator::~NullUnknownAllocator()
5✔
254
{
255
}
5✔
256

257
char* NullUnknownAllocator::alloc_memory(size_t /*size*/, const char*, size_t)
2✔
258
{
259
    return NULLPTR;
2✔
260
}
261

262
void NullUnknownAllocator::free_memory(char* /*memory*/, size_t, const char*, size_t)
1✔
263
{
264
}
1✔
265

266
NullUnknownAllocator::NullUnknownAllocator()
3✔
267
    : TestMemoryAllocator("Null Allocator", "unknown", "unknown")
3✔
268
{
269
}
3✔
270

271

272
TestMemoryAllocator* NullUnknownAllocator::defaultAllocator()
4✔
273
{
274
    static NullUnknownAllocator allocator;
4✔
275
    return &allocator;
4✔
276
}
277

278
class LocationToFailAllocNode
279
{
280
  public:
281
    int allocNumberToFail_;
282
    int actualAllocNumber_;
283
    const char* file_;
284
    size_t line_;
285
    LocationToFailAllocNode* next_;
286

287
    void failAtAllocNumber(int number, LocationToFailAllocNode* next)
×
288
    {
289
      init(next);
×
290
      allocNumberToFail_ = number;
×
291
    }
×
292

293
    void failNthAllocAt(int allocationNumber, const char* file, size_t line, LocationToFailAllocNode* next)
×
294
    {
295
      init(next);
×
296
      allocNumberToFail_ = allocationNumber;
×
297
      file_ = file;
×
298
      line_ = line;
×
299
    }
×
300

301
    bool shouldFail(int allocationNumber, const char* file, size_t line)
×
302
    {
303
      if (file_ && SimpleString::StrCmp(file, file_) == 0 && line == line_) {
×
304
        actualAllocNumber_++;
×
305
        return actualAllocNumber_ == allocNumberToFail_;
×
306
      }
307
      if (allocationNumber == allocNumberToFail_)
×
308
        return true;
×
309
      return false;
×
310
    }
311

312
  private:
313
    void init(LocationToFailAllocNode* next = NULLPTR)
×
314
    {
315
      allocNumberToFail_ = 0;
×
316
      actualAllocNumber_ = 0;
×
317
      file_ = NULLPTR;
×
318
      line_ = 0;
×
319
      next_ = next;
×
320
    }
×
321

322
};
323

324
FailableMemoryAllocator::~FailableMemoryAllocator()
×
325
{
326
}
×
327

328
FailableMemoryAllocator::FailableMemoryAllocator(const char* name_str, const char* alloc_name_str, const char* free_name_str)
×
329
: TestMemoryAllocator(name_str, alloc_name_str, free_name_str), head_(NULLPTR), currentAllocNumber_(0)
×
330
{
331
}
×
332

333
void FailableMemoryAllocator::failAllocNumber(int number)
×
334
{
335
    LocationToFailAllocNode* newNode = (LocationToFailAllocNode*) (void*) allocMemoryLeakNode(sizeof(LocationToFailAllocNode));
×
336
    newNode->failAtAllocNumber(number, head_);
×
337
    head_ = newNode;
×
338
}
×
339

340
void FailableMemoryAllocator::failNthAllocAt(int allocationNumber, const char* file, size_t line)
×
341
{
342
    LocationToFailAllocNode* newNode = (LocationToFailAllocNode*) (void*) allocMemoryLeakNode(sizeof(LocationToFailAllocNode));
×
343
    newNode->failNthAllocAt(allocationNumber, file, line, head_);
×
344
    head_ = newNode;
×
345
}
×
346

347
char* FailableMemoryAllocator::alloc_memory(size_t size, const char* file, size_t line)
×
348
{
349
    currentAllocNumber_++;
×
350
    LocationToFailAllocNode* current = head_;
×
351
    LocationToFailAllocNode* previous = NULLPTR;
×
352

353
    while (current) {
×
354
      if (current->shouldFail(currentAllocNumber_, file, line)) {
×
355
        if (previous) previous->next_ = current->next_;
×
356
        else head_ = current->next_;
×
357

358
        free_memory((char*) current, size, __FILE__, __LINE__);
×
359
        return NULLPTR;
×
360
      }
361
      previous = current;
×
362
      current = current->next_;
×
363
    }
364
    return TestMemoryAllocator::alloc_memory(size, file, line);
×
365
}
366

367
char* FailableMemoryAllocator::allocMemoryLeakNode(size_t size)
×
368
{
369
    return (char*)PlatformSpecificMalloc(size);
×
370
}
371

372
void FailableMemoryAllocator::checkAllFailedAllocsWereDone()
×
373
{
374
    if (head_) {
×
375
        UtestShell* currentTest = UtestShell::getCurrent();
×
376
        SimpleString failText;
×
377
        if (head_->file_)
×
378
            failText = StringFromFormat("Expected failing alloc at %s:%d was never done", head_->file_, (int) head_->line_);
×
379
        else
380
            failText = StringFromFormat("Expected allocation number %d was never done", (int) head_->allocNumberToFail_);
×
381

382
        currentTest->failWith(FailFailure(currentTest, currentTest->getName().asCharString(), currentTest->getLineNumber(), failText));
×
383
    }
×
384
}
×
385

386
void FailableMemoryAllocator::clearFailedAllocs()
×
387
{
388
  LocationToFailAllocNode* current = head_;
×
389
  while (current) {
×
390
    head_ = current->next_;
×
391
    free_memory((char*) current, 0, __FILE__, __LINE__);
×
392
    current = head_;
×
393
  }
394
  currentAllocNumber_ = 0;
×
395
}
×
396

397
struct MemoryAccountantAllocationNode
398
{
399
    size_t size_;
400
    size_t allocations_;
401
    size_t deallocations_;
402
    size_t maxAllocations_;
403
    size_t currentAllocations_;
404
    MemoryAccountantAllocationNode* next_;
405
};
406

407
MemoryAccountantAllocationNode* MemoryAccountant::createNewAccountantAllocationNode(size_t size, MemoryAccountantAllocationNode* next) const
63✔
408
{
409
    MemoryAccountantAllocationNode* node = (MemoryAccountantAllocationNode*) (void*) allocator_->alloc_memory(sizeof(MemoryAccountantAllocationNode), __FILE__, __LINE__);
63✔
410
    node->size_ = size;
63✔
411
    node->allocations_ = 0;
63✔
412
    node->deallocations_ = 0;
63✔
413
    node->maxAllocations_ = 0;
63✔
414
    node->currentAllocations_ = 0;
63✔
415
    node->next_ = next;
63✔
416
    return node;
63✔
417
}
418

419
void MemoryAccountant::destroyAccountantAllocationNode(MemoryAccountantAllocationNode* node) const
63✔
420
{
421
    allocator_->free_memory((char*) node, sizeof(*node), __FILE__, __LINE__);
63✔
422
}
63✔
423

424
MemoryAccountant::MemoryAccountant()
49✔
425
    : head_(NULLPTR), allocator_(defaultMallocAllocator()), useCacheSizes_(false)
49✔
426
{
427
}
49✔
428

429
MemoryAccountant::~MemoryAccountant()
49✔
430
{
431
    clear();
49✔
432
}
49✔
433

434
void MemoryAccountant::createCacheSizeNodes(size_t sizes[], size_t length)
4✔
435
{
436
    for (size_t i = 0; i < length; i++)
9✔
437
        findOrCreateNodeOfSize(sizes[i]);
5✔
438

439
    if (head_ == NULLPTR)
4✔
440
        head_ = createNewAccountantAllocationNode(0, NULLPTR);
1✔
441
    else {
442
        for (MemoryAccountantAllocationNode* lastNode = head_; lastNode; lastNode = lastNode->next_) {
5✔
443
            if (lastNode->next_ == NULLPTR) {
5✔
444
                lastNode->next_ = createNewAccountantAllocationNode(0, NULLPTR);
3✔
445
                break;
3✔
446
            }
447
        }
448
    }
449
}
4✔
450

451

452
void MemoryAccountant::useCacheSizes(size_t sizes[], size_t length)
5✔
453
{
454
    if (head_)
5✔
455
      FAIL("MemoryAccountant: Cannot set cache sizes as allocations already occured!");
1✔
456

457
    createCacheSizeNodes(sizes, length);
4✔
458
    useCacheSizes_ = true;
4✔
459
}
4✔
460

461
void MemoryAccountant::setAllocator(TestMemoryAllocator* allocator)
6✔
462
{
463
    allocator_ = allocator;
6✔
464
}
6✔
465

466
void MemoryAccountant::clear()
81✔
467
{
468
    MemoryAccountantAllocationNode* node = head_;
81✔
469
    MemoryAccountantAllocationNode* to_be_deleted = NULLPTR;
81✔
470
    while (node) {
144✔
471
        to_be_deleted = node;
63✔
472
        node = node->next_;
63✔
473
        destroyAccountantAllocationNode(to_be_deleted);
63✔
474
    }
475
    head_ = NULLPTR;
81✔
476
}
81✔
477

478
MemoryAccountantAllocationNode* MemoryAccountant::findNodeOfSize(size_t size) const
46✔
479
{
480
    if (useCacheSizes_) {
46✔
481
        for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_) {
23✔
482
            if (((size > node->size_) && (node->next_ == NULLPTR))
23✔
483
                || ((size <= node->size_) &&
19✔
484
                    !((node->next_->size_ != 0) && (node->next_->size_ <= size))))
11✔
485
                return node;
15✔
486
        }
487
    }
488
    else
489
        for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
65✔
490
            if (node->size_ == size)
59✔
491
                return node;
25✔
492
    return NULLPTR;
6✔
493
}
494

495
MemoryAccountantAllocationNode* MemoryAccountant::findOrCreateNodeOfSize(size_t size)
155✔
496
{
497
    if (useCacheSizes_)
155✔
498
      return findNodeOfSize(size);
15✔
499

500
    if (head_ && head_->size_ > size)
140✔
501
        head_ = createNewAccountantAllocationNode(size, head_);
8✔
502

503
    for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_) {
234✔
504
        if (node->size_ == size)
207✔
505
            return node;
113✔
506
        if (node->next_ == NULLPTR || node->next_->size_ > size)
94✔
507
            node->next_ = createNewAccountantAllocationNode(size, node->next_);
24✔
508
    }
509
    head_ = createNewAccountantAllocationNode(size, head_);
27✔
510
    return head_;
27✔
511
}
512

513
void MemoryAccountant::alloc(size_t size)
76✔
514
{
515
    MemoryAccountantAllocationNode* node = findOrCreateNodeOfSize(size);
76✔
516
    node->allocations_++;
76✔
517
    node->currentAllocations_++;
76✔
518
    node->maxAllocations_ = (node->currentAllocations_ > node->maxAllocations_) ? node->currentAllocations_ : node->maxAllocations_;
76✔
519
}
76✔
520

521
void MemoryAccountant::dealloc(size_t size)
74✔
522
{
523
    MemoryAccountantAllocationNode* node = findOrCreateNodeOfSize(size);
74✔
524
    node->deallocations_++;
74✔
525
    if (node->currentAllocations_)
74✔
526
      node->currentAllocations_--;
54✔
527
}
74✔
528

529
size_t MemoryAccountant::totalAllocationsOfSize(size_t size) const
18✔
530
{
531
    MemoryAccountantAllocationNode* node = findNodeOfSize(size);
18✔
532
    if (node)
18✔
533
      return node->allocations_;
14✔
534
    return 0;
4✔
535
}
536

537
size_t MemoryAccountant::totalDeallocationsOfSize(size_t size) const
11✔
538
{
539
    MemoryAccountantAllocationNode* node = findNodeOfSize(size);
11✔
540
    if (node)
11✔
541
      return node->deallocations_;
10✔
542
    return 0;
1✔
543
}
544

545
size_t MemoryAccountant::maximumAllocationAtATimeOfSize(size_t size) const
2✔
546
{
547
    MemoryAccountantAllocationNode* node = findNodeOfSize(size);
2✔
548
    if (node)
2✔
549
      return node->maxAllocations_;
1✔
550
    return 0;
1✔
551
}
552

553
size_t MemoryAccountant::totalAllocations() const
8✔
554
{
555
    size_t theTotalAllocations = 0;
8✔
556

557
    for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
28✔
558
        theTotalAllocations += node->allocations_;
20✔
559

560
    return theTotalAllocations;
8✔
561
}
562

563
size_t MemoryAccountant::totalDeallocations() const
6✔
564
{
565
    size_t theTotalDeallocations = 0;
6✔
566

567
    for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
20✔
568
        theTotalDeallocations += node->deallocations_;
14✔
569

570
    return theTotalDeallocations;
6✔
571
}
572

573
SimpleString MemoryAccountant::reportNoAllocations() const
1✔
574
{
575
      return SimpleString("CppUTest Memory Accountant has not noticed any allocations or deallocations. Sorry\n");
1✔
576
}
577

578
SimpleString MemoryAccountant::reportTitle() const
7✔
579
{
580
      if (useCacheSizes_)
7✔
581
        return "CppUTest Memory Accountant report (with cache sizes):\n";
4✔
582
      return "CppUTest Memory Accountant report:\n";
3✔
583
}
584

585
SimpleString MemoryAccountant::reportHeader() const
7✔
586
{
587
    if (useCacheSizes_)
7✔
588
        return "Cache size          # allocations    # deallocations   max # allocations at one time\n";
4✔
589
    return "Allocation size     # allocations    # deallocations   max # allocations at one time\n";
3✔
590
}
591

592
#define MEMORY_ACCOUNTANT_ROW_FORMAT "%s               %5d            %5d             %5d\n"
593

594
SimpleString MemoryAccountant::reportFooter() const
7✔
595
{
596
    return SimpleString("   Thank you for your business\n");
7✔
597
}
598

599
SimpleString MemoryAccountant::stringSize(size_t size) const
15✔
600
{
601
    return (size == 0) ? StringFrom("other") : StringFromFormat("%5d", (int) size);
15✔
602
}
603

604
SimpleString MemoryAccountant::report() const
8✔
605
{
606
    if (head_ == NULLPTR)
8✔
607
      return reportNoAllocations();
1✔
608

609
    SimpleString accountantReport = reportTitle() + reportHeader();
7✔
610

611
    for (MemoryAccountantAllocationNode* node = head_; node; node = node->next_)
22✔
612
        accountantReport += StringFromFormat(MEMORY_ACCOUNTANT_ROW_FORMAT, stringSize(node->size_).asCharString(), (int) node->allocations_, (int) node->deallocations_, (int) node->maxAllocations_);
15✔
613

614
    return accountantReport + reportFooter();
7✔
615
}
7✔
616

617
AccountingTestMemoryAllocator::AccountingTestMemoryAllocator(MemoryAccountant& accountant, TestMemoryAllocator* origAllocator)
46✔
618
    : accountant_(accountant), originalAllocator_(origAllocator), head_(NULLPTR)
46✔
619
{
620
}
46✔
621

622
AccountingTestMemoryAllocator::~AccountingTestMemoryAllocator()
92✔
623
{
624
}
92✔
625

626
struct AccountingTestMemoryAllocatorMemoryNode
627
{
628
    char* memory_;
629
    size_t size_;
630
    AccountingTestMemoryAllocatorMemoryNode* next_;
631
};
632

633
void AccountingTestMemoryAllocator::addMemoryToMemoryTrackingToKeepTrackOfSize(char* memory, size_t size)
50✔
634
{
635
    AccountingTestMemoryAllocatorMemoryNode* node = (AccountingTestMemoryAllocatorMemoryNode*) (void*) originalAllocator_->alloc_memory(sizeof(AccountingTestMemoryAllocatorMemoryNode), __FILE__, __LINE__);
50✔
636
    node->memory_ = memory;
50✔
637
    node->size_ = size;
50✔
638
    node->next_ = head_;
50✔
639
    head_ = node;
50✔
640
}
50✔
641

642
size_t AccountingTestMemoryAllocator::removeNextNodeAndReturnSize(AccountingTestMemoryAllocatorMemoryNode* node)
18✔
643
{
644
    AccountingTestMemoryAllocatorMemoryNode* foundNode = node->next_;
18✔
645
    node->next_ = node->next_->next_;
18✔
646

647
    size_t size = foundNode->size_;
18✔
648
    originalAllocator_->free_memory((char*) foundNode, size, __FILE__, __LINE__);
18✔
649
    return size;
18✔
650
}
651

652
size_t AccountingTestMemoryAllocator::removeHeadAndReturnSize()
30✔
653
{
654
    AccountingTestMemoryAllocatorMemoryNode* foundNode = head_;
30✔
655
    head_ = head_->next_;
30✔
656

657
    size_t size = foundNode->size_;
30✔
658
    originalAllocator_->free_memory((char*) foundNode, size, __FILE__, __LINE__);
30✔
659
    return size;
30✔
660
}
661

662
size_t AccountingTestMemoryAllocator::removeMemoryFromTrackingAndReturnAllocatedSize(char* memory)
57✔
663
{
664
    if (head_ && head_->memory_ == memory)
57✔
665
        return removeHeadAndReturnSize();
30✔
666

667
    for (AccountingTestMemoryAllocatorMemoryNode* node = head_; node; node = node->next_) {
65✔
668
        if (node->next_ && node->next_->memory_ == memory)
56✔
669
            return removeNextNodeAndReturnSize(node);
18✔
670
    }
671

672
    return 0;
9✔
673
}
674

675
char* AccountingTestMemoryAllocator::alloc_memory(size_t size, const char* file, size_t line)
50✔
676
{
677
    accountant_.alloc(size);
50✔
678
    char* memory = originalAllocator_->alloc_memory(size, file, line);
50✔
679
    addMemoryToMemoryTrackingToKeepTrackOfSize(memory, size);
50✔
680
    return memory;
50✔
681
}
682

683
void AccountingTestMemoryAllocator::free_memory(char* memory, size_t, const char* file, size_t line)
57✔
684
{
685
    size_t size = removeMemoryFromTrackingAndReturnAllocatedSize(memory);
57✔
686
    accountant_.dealloc(size);
57✔
687
    originalAllocator_->free_memory(memory, size, file, line);
57✔
688
}
57✔
689

690
TestMemoryAllocator* AccountingTestMemoryAllocator::actualAllocator()
1✔
691
{
692
    return originalAllocator_->actualAllocator();
1✔
693
}
694

695
TestMemoryAllocator* AccountingTestMemoryAllocator::originalAllocator()
16✔
696
{
697
    return originalAllocator_;
16✔
698
}
699

700
const char* AccountingTestMemoryAllocator::alloc_name() const
2✔
701
{
702
    return originalAllocator_->alloc_name();
2✔
703
}
704

705
const char* AccountingTestMemoryAllocator::free_name() const
2✔
706
{
707
    return originalAllocator_->free_name();
2✔
708
}
709

710
GlobalMemoryAccountant::GlobalMemoryAccountant()
7✔
711
    : mallocAllocator_(NULLPTR), newAllocator_(NULLPTR), newArrayAllocator_(NULLPTR)
7✔
712
{
713
}
7✔
714

715
GlobalMemoryAccountant::~GlobalMemoryAccountant()
7✔
716
{
717
    restoreMemoryAllocators();
7✔
718
    delete mallocAllocator_;
7✔
719
    delete newAllocator_;
7✔
720
    delete newArrayAllocator_;
7✔
721
}
7✔
722

723
void GlobalMemoryAccountant::useCacheSizes(size_t sizes[], size_t length)
×
724
{
725
    accountant_.useCacheSizes(sizes, length);
×
726
}
×
727

728
void GlobalMemoryAccountant::start()
7✔
729
{
730
    if (mallocAllocator_ != NULLPTR)
7✔
731
      FAIL("Global allocator start called twice!");
1✔
732

733
    mallocAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentMallocAllocator());
6✔
734
    newAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentNewAllocator());
6✔
735
    newArrayAllocator_ = new AccountingTestMemoryAllocator(accountant_, getCurrentNewArrayAllocator());
6✔
736

737
    accountant_.setAllocator(getCurrentMallocAllocator());
6✔
738

739
    setCurrentMallocAllocator(mallocAllocator_);
6✔
740
    setCurrentNewAllocator(newAllocator_);
6✔
741
    setCurrentNewArrayAllocator(newArrayAllocator_);
6✔
742
}
6✔
743

744
void GlobalMemoryAccountant::restoreMemoryAllocators()
10✔
745
{
746
    if (getCurrentMallocAllocator() == mallocAllocator_)
10✔
747
        setCurrentMallocAllocator(mallocAllocator_->originalAllocator());
3✔
748

749
    if (getCurrentNewAllocator() == newAllocator_)
10✔
750
        setCurrentNewAllocator(newAllocator_->originalAllocator());
3✔
751

752
    if (getCurrentNewArrayAllocator() == newArrayAllocator_)
10✔
753
        setCurrentNewArrayAllocator(newArrayAllocator_->originalAllocator());
3✔
754
}
10✔
755

756
void GlobalMemoryAccountant::stop()
7✔
757
{
758
    if (mallocAllocator_ == NULLPTR)
7✔
759
      FAIL("GlobalMemoryAccount: Stop called without starting");
1✔
760

761
    if (getCurrentMallocAllocator() != mallocAllocator_)
6✔
762
        FAIL("GlobalMemoryAccountant: Malloc memory allocator has been changed while accounting for memory");
1✔
763

764
    if (getCurrentNewAllocator() != newAllocator_)
5✔
765
        FAIL("GlobalMemoryAccountant: New memory allocator has been changed while accounting for memory");
1✔
766

767
    if (getCurrentNewArrayAllocator() != newArrayAllocator_)
4✔
768
        FAIL("GlobalMemoryAccountant: New Array memory allocator has been changed while accounting for memory");
1✔
769

770
    restoreMemoryAllocators();
3✔
771
}
3✔
772

773
SimpleString GlobalMemoryAccountant::report()
×
774
{
775
    return accountant_.report();
×
776
}
777

778
TestMemoryAllocator* GlobalMemoryAccountant::getMallocAllocator()
1✔
779
{
780
    return mallocAllocator_;
1✔
781
}
782

783
TestMemoryAllocator* GlobalMemoryAccountant::getNewAllocator()
1✔
784
{
785
    return newAllocator_;
1✔
786
}
787

788
TestMemoryAllocator* GlobalMemoryAccountant::getNewArrayAllocator()
1✔
789
{
790
    return newArrayAllocator_;
1✔
791
}
792

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