1 /*
2 * Copyright (c) 2017, The OpenThread Authors.
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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 * 3. Neither the name of the copyright holder 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 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 <openthread/config.h>
30
31 #include "core/utils/heap.hpp"
32
33 #include <stdlib.h>
34
35 #include "common/debug.hpp"
36 #include "crypto/aes_ccm.hpp"
37
38 #include "test_platform.h"
39 #include "test_util.h"
40
41 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
42
43 /**
44 * Verifies single variable allocating and freeing.
45 *
46 */
TestAllocateSingle(void)47 void TestAllocateSingle(void)
48 {
49 ot::Utils::Heap heap;
50
51 const size_t totalSize = heap.GetFreeSize();
52
53 {
54 void *p = heap.CAlloc(1, 0);
55 VerifyOrQuit(p == nullptr && totalSize == heap.GetFreeSize(), "TestAllocateSingle allocate 1 x 0 byte failed!");
56 heap.Free(p);
57
58 p = heap.CAlloc(0, 1);
59 VerifyOrQuit(p == nullptr && totalSize == heap.GetFreeSize(), "TestAllocateSingle allocate 0 x 1 byte failed!");
60 heap.Free(p);
61 }
62
63 for (size_t size = 1; size <= heap.GetCapacity(); ++size)
64 {
65 printf("%s allocating %zu bytes...\n", __func__, size);
66 void *p = heap.CAlloc(1, size);
67 VerifyOrQuit(p != nullptr && !heap.IsClean() && heap.GetFreeSize() + size <= totalSize, "allocating failed!");
68 memset(p, 0xff, size);
69 heap.Free(p);
70 VerifyOrQuit(heap.IsClean() && heap.GetFreeSize() == totalSize, "freeing failed!\n");
71 }
72 }
73
74 /**
75 * Verifies randomly allocating and freeing variables.
76 *
77 * @param[in] aSizeLimit The maximum allocation size.
78 * @param[in] aSeed The seed for generating random sizes.
79 *
80 */
TestAllocateRandomly(size_t aSizeLimit,unsigned int aSeed)81 void TestAllocateRandomly(size_t aSizeLimit, unsigned int aSeed)
82 {
83 struct Node
84 {
85 Node * mNext;
86 size_t mSize;
87 };
88
89 ot::Utils::Heap heap;
90 Node head;
91 size_t nnodes = 0;
92
93 srand(aSeed);
94
95 const size_t totalSize = heap.GetFreeSize();
96 Node * last = &head;
97
98 do
99 {
100 size_t size = sizeof(Node) + static_cast<size_t>(rand()) % aSizeLimit;
101 printf("TestAllocateRandomly allocating %zu bytes...\n", size);
102 last->mNext = static_cast<Node *>(heap.CAlloc(1, size));
103
104 // No more memory for allocation.
105 if (last->mNext == nullptr)
106 {
107 break;
108 }
109
110 VerifyOrQuit(last->mNext->mNext == nullptr, "TestAllocateRandomly memory not initialized to zero!");
111 last = last->mNext;
112 last->mSize = size;
113 ++nnodes;
114
115 // 50% probability to randomly free a node.
116 size_t freeIndex = static_cast<size_t>(rand()) % (nnodes * 2);
117
118 if (freeIndex > nnodes)
119 {
120 freeIndex /= 2;
121
122 Node *prev = &head;
123
124 while (freeIndex--)
125 {
126 prev = prev->mNext;
127 }
128
129 Node *curr = prev->mNext;
130 printf("TestAllocateRandomly freeing %zu bytes...\n", curr->mSize);
131 prev->mNext = curr->mNext;
132 heap.Free(curr);
133
134 if (last == curr)
135 {
136 last = prev;
137 }
138
139 --nnodes;
140 }
141 } while (true);
142
143 last = head.mNext;
144
145 while (last)
146 {
147 Node *next = last->mNext;
148 printf("TestAllocateRandomly freeing %zu bytes...\n", last->mSize);
149 heap.Free(last);
150 last = next;
151 }
152
153 VerifyOrQuit(heap.IsClean() && heap.GetFreeSize() == totalSize,
154 "TestAllocateRandomly heap not clean after freeing all!");
155 }
156
157 /**
158 * Verifies allocating and free multiple variables.
159 */
TestAllocateMultiple(void)160 void TestAllocateMultiple(void)
161 {
162 for (unsigned int seed = 0; seed < 10; ++seed)
163 {
164 size_t sizeLimit = (1 << seed);
165 printf("TestAllocateRandomly(%zu, %u)...\n", sizeLimit, seed);
166 TestAllocateRandomly(sizeLimit, seed);
167 }
168 }
169
RunTimerTests(void)170 void RunTimerTests(void)
171 {
172 TestAllocateSingle();
173 TestAllocateMultiple();
174 }
175
176 #endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
177
main(void)178 int main(void)
179 {
180 #if !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
181 RunTimerTests();
182 printf("All tests passed\n");
183 #endif // !OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
184 return 0;
185 }
186