tests/util_allocator.cpp

changeset 770
ed710122af44
parent 653
e081643aae2a
equal deleted inserted replaced
769:b53e0e003d7e 770:ed710122af44
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "util_allocator.h"
30
31 void *cx_malloc_testing(void *d, size_t n) {
32 auto data = reinterpret_cast<CxTestingAllocator *>(d);
33 void *ptr = malloc(n);
34 data->alloc_total++;
35 if (ptr == nullptr) {
36 data->alloc_failed++;
37 } else {
38 data->tracked.insert(ptr);
39 }
40 return ptr;
41 }
42
43 void *cx_realloc_testing(void *d, void *mem, size_t n) {
44 auto data = reinterpret_cast<CxTestingAllocator *>(d);
45 void *ptr = realloc(mem, n);
46 if (ptr == mem) {
47 return ptr;
48 } else {
49 data->alloc_total++;
50 if (ptr == nullptr) {
51 data->alloc_failed++;
52 } else {
53 data->free_total++;
54 if (data->tracked.erase(mem) == 0) {
55 data->free_failed++;
56 }
57 data->tracked.insert(ptr);
58 }
59 return ptr;
60 }
61 }
62
63 void *cx_calloc_testing(void *d, size_t nelem, size_t n) {
64 auto data = reinterpret_cast<CxTestingAllocator *>(d);
65 void *ptr = calloc(nelem, n);
66 data->alloc_total++;
67 if (ptr == nullptr) {
68 data->alloc_failed++;
69 } else {
70 data->tracked.insert(ptr);
71 }
72 return ptr;
73 }
74
75 void cx_free_testing(void *d, void *mem) {
76 auto data = reinterpret_cast<CxTestingAllocator *>(d);
77 data->free_total++;
78 if (data->tracked.erase(mem) == 0) {
79 data->free_failed++;
80 // do not even attempt to free mem, because it is likely to segfault
81 } else {
82 free(mem);
83 }
84 }
85
86 cx_allocator_class cx_testing_allocator_class = {
87 cx_malloc_testing,
88 cx_realloc_testing,
89 cx_calloc_testing,
90 cx_free_testing
91 };
92
93 CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
94 cl = &cx_testing_allocator_class;
95 data = this;
96 }
97
98 bool CxTestingAllocator::used() const {
99 return alloc_total > 0;
100 }
101
102 bool CxTestingAllocator::verify() const {
103 return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
104 }
105
106 // SELF-TEST
107
108 #include <gtest/gtest.h>
109
110 TEST(TestingAllocator, ExpectFree) {
111 CxTestingAllocator allocator;
112
113 ASSERT_TRUE(allocator.verify());
114 EXPECT_FALSE(allocator.used());
115 auto ptr = cxMalloc(&allocator, 16);
116 EXPECT_TRUE(allocator.used());
117 ASSERT_NE(ptr, nullptr);
118 EXPECT_FALSE(allocator.verify());
119
120 cxFree(&allocator, ptr);
121 EXPECT_TRUE(allocator.verify());
122 }
123
124 TEST(TestingAllocator, DetectDoubleFree) {
125 CxTestingAllocator allocator;
126
127 ASSERT_TRUE(allocator.verify());
128 auto ptr = cxMalloc(&allocator, 16);
129 ASSERT_NE(ptr, nullptr);
130
131 cxFree(&allocator, ptr);
132 EXPECT_TRUE(allocator.verify());
133 ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
134 EXPECT_FALSE(allocator.verify());
135 }
136
137 TEST(TestingAllocator, FreeUntracked) {
138 CxTestingAllocator allocator;
139
140 auto ptr = malloc(16);
141 ASSERT_TRUE(allocator.verify());
142 ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
143 EXPECT_FALSE(allocator.verify());
144 ASSERT_NO_FATAL_FAILURE(free(ptr));
145 }
146
147 TEST(TestingAllocator, FullLifecycleWithRealloc) {
148 CxTestingAllocator allocator;
149 ASSERT_TRUE(allocator.verify());
150 auto ptr = cxMalloc(&allocator, 16);
151 ASSERT_NE(ptr, nullptr);
152 EXPECT_EQ(allocator.tracked.size(), 1);
153 ptr = cxRealloc(&allocator, ptr, 256);
154 ASSERT_NE(ptr, nullptr);
155 EXPECT_EQ(allocator.tracked.size(), 1);
156 cxFree(&allocator, ptr);
157 EXPECT_TRUE(allocator.verify());
158 }
159
160 TEST(TestingAllocator, CallocInitializes) {
161 CxTestingAllocator allocator;
162 const char zeros[16] = {0};
163 auto ptr = cxCalloc(&allocator, 16, 1);
164 EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
165 cxFree(&allocator, ptr);
166 EXPECT_TRUE(allocator.verify());
167 }

mercurial