Sun, 20 Nov 2022 16:28:03 +0100
#219 array list: implement compare member func
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 */
29 #include "util_allocator.h"
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 }
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 }
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 }
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 }
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 };
93 CxTestingAllocator::CxTestingAllocator() : CxAllocator() {
94 cl = &cx_testing_allocator_class;
95 data = this;
96 }
98 bool CxTestingAllocator::used() const {
99 return alloc_total > 0;
100 }
102 bool CxTestingAllocator::verify() const {
103 return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
104 }
106 // SELF-TEST
108 #include <gtest/gtest.h>
110 TEST(TestingAllocator, ExpectFree) {
111 CxTestingAllocator allocator;
113 ASSERT_TRUE(allocator.verify());
114 auto ptr = cxMalloc(&allocator, 16);
115 ASSERT_NE(ptr, nullptr);
116 EXPECT_FALSE(allocator.verify());
118 cxFree(&allocator, ptr);
119 EXPECT_TRUE(allocator.verify());
120 }
122 TEST(TestingAllocator, DetectDoubleFree) {
123 CxTestingAllocator allocator;
125 ASSERT_TRUE(allocator.verify());
126 auto ptr = cxMalloc(&allocator, 16);
127 ASSERT_NE(ptr, nullptr);
129 cxFree(&allocator, ptr);
130 EXPECT_TRUE(allocator.verify());
131 ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
132 EXPECT_FALSE(allocator.verify());
133 }
135 TEST(TestingAllocator, FreeUntracked) {
136 CxTestingAllocator allocator;
138 auto ptr = malloc(16);
139 ASSERT_TRUE(allocator.verify());
140 ASSERT_NO_FATAL_FAILURE(cxFree(&allocator, ptr));
141 EXPECT_FALSE(allocator.verify());
142 ASSERT_NO_FATAL_FAILURE(free(ptr));
143 }
145 TEST(TestingAllocator, FullLifecycleWithRealloc) {
146 CxTestingAllocator allocator;
147 ASSERT_TRUE(allocator.verify());
148 auto ptr = cxMalloc(&allocator, 16);
149 ASSERT_NE(ptr, nullptr);
150 EXPECT_EQ(allocator.tracked.size(), 1);
151 ptr = cxRealloc(&allocator, ptr, 256);
152 ASSERT_NE(ptr, nullptr);
153 EXPECT_EQ(allocator.tracked.size(), 1);
154 cxFree(&allocator, ptr);
155 EXPECT_TRUE(allocator.verify());
156 }
158 TEST(TestingAllocator, CallocInitializes) {
159 CxTestingAllocator allocator;
160 const char* zeros[16] = {0};
161 auto ptr = cxCalloc(&allocator, 16, 1);
162 EXPECT_EQ(memcmp(ptr, zeros, 16), 0);
163 cxFree(&allocator, ptr);
164 EXPECT_TRUE(allocator.verify());
165 }