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