1 /* 2 * testcode/unitregional.c - unit test for regional allocator. 3 * 4 * Copyright (c) 2010, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * 35 */ 36 /** 37 * \file 38 * Tests the regional special purpose allocator. 39 */ 40 41 #include "config.h" 42 #include "testcode/unitmain.h" 43 #include "util/log.h" 44 #include "util/regional.h" 45 46 /** test regional corner cases, zero, one, end of structure */ 47 static void 48 corner_cases(struct regional* r) 49 { 50 size_t s; /* shadow count of allocated memory */ 51 void* a; 52 size_t minsize = sizeof(uint64_t); 53 #ifndef UNBOUND_ALLOC_NONREGIONAL 54 size_t mysize; 55 #endif 56 char* str; 57 unit_assert(r); 58 /* alloc cases: 59 * 0, 1, 2. 60 * smaller than LARGE_OBJECT_SIZE. 61 * smaller but does not fit in remainder in regional. 62 * smaller but exactly fits in remainder of regional. 63 * size is remainder of regional - 8. 64 * size is remainder of regional + 8. 65 * larger than LARGE_OBJECT_SIZE. 66 */ 67 s = sizeof(struct regional); 68 unit_assert((s % minsize) == 0); 69 unit_assert(r->available == r->first_size - s); 70 unit_assert(r->large_list == NULL); 71 unit_assert(r->next == NULL); 72 73 /* Note an alloc of 0 gets a pointer to current last 74 * position (where you should then use 0 bytes) */ 75 a = regional_alloc(r, 0); 76 unit_assert(a); 77 s+=0; 78 unit_assert(r->available == r->first_size - s); 79 80 #ifndef UNBOUND_ALLOC_NONREGIONAL 81 a = regional_alloc(r, 1); 82 unit_assert(a); 83 memset(a, 0x42, 1); 84 s+=minsize; 85 unit_assert(r->available == r->first_size - s); 86 87 a = regional_alloc(r, 2); 88 unit_assert(a); 89 memset(a, 0x42, 2); 90 s+=minsize; 91 unit_assert(r->available == r->first_size - s); 92 93 a = regional_alloc(r, 128); 94 unit_assert(a); 95 memset(a, 0x42, 128); 96 s+=128; 97 unit_assert(r->available == r->first_size - s); 98 99 unit_assert(r->large_list == NULL); 100 a = regional_alloc(r, 10240); 101 unit_assert(a); 102 unit_assert(r->large_list != NULL); 103 memset(a, 0x42, 10240); 104 /* s does not change */ 105 unit_assert(r->available == r->first_size - s); 106 unit_assert(r->total_large == 10240+minsize); 107 108 /* go towards the end of the current chunk */ 109 while(r->available > 1024) { 110 a = regional_alloc(r, 1024); 111 unit_assert(a); 112 memset(a, 0x42, 1024); 113 s += 1024; 114 unit_assert(r->available == r->first_size - s); 115 } 116 117 unit_assert(r->next == NULL); 118 mysize = 1280; /* does not fit in current chunk */ 119 a = regional_alloc(r, mysize); 120 memset(a, 0x42, mysize); 121 unit_assert(r->next != NULL); 122 unit_assert(a); 123 124 /* go towards the end of the current chunk */ 125 while(r->available > 864) { 126 a = regional_alloc(r, 864); 127 unit_assert(a); 128 memset(a, 0x42, 864); 129 s += 864; 130 } 131 132 mysize = r->available; /* exactly fits */ 133 a = regional_alloc(r, mysize); 134 memset(a, 0x42, mysize); 135 unit_assert(a); 136 unit_assert(r->available == 0); /* implementation does not go ahead*/ 137 138 a = regional_alloc(r, 8192); /* another large allocation */ 139 unit_assert(a); 140 memset(a, 0x42, 8192); 141 unit_assert(r->available == 0); 142 unit_assert(r->total_large == 10240 + 8192 + 2*minsize); 143 144 a = regional_alloc(r, 32); /* make new chunk */ 145 unit_assert(a); 146 memset(a, 0x42, 32); 147 unit_assert(r->available > 0); 148 unit_assert(r->total_large == 10240 + 8192 + 2*minsize); 149 150 /* go towards the end of the current chunk */ 151 while(r->available > 1320) { 152 a = regional_alloc(r, 1320); 153 unit_assert(a); 154 memset(a, 0x42, 1320); 155 s += 1320; 156 } 157 158 mysize = r->available + 8; /* exact + 8 ; does not fit */ 159 a = regional_alloc(r, mysize); 160 memset(a, 0x42, mysize); 161 unit_assert(a); 162 unit_assert(r->available > 0); /* new chunk */ 163 164 /* go towards the end of the current chunk */ 165 while(r->available > 1480) { 166 a = regional_alloc(r, 1480); 167 unit_assert(a); 168 memset(a, 0x42, 1480); 169 s += 1480; 170 } 171 172 mysize = r->available - 8; /* exact - 8 ; fits. */ 173 a = regional_alloc(r, mysize); 174 memset(a, 0x42, mysize); 175 unit_assert(a); 176 unit_assert(r->available == 8); 177 #endif /* UNBOUND_ALLOC_NONREGIONAL */ 178 179 /* test if really copied over */ 180 str = "test12345"; 181 a = regional_alloc_init(r, str, 8); 182 unit_assert(a); 183 unit_assert(memcmp(a, str, 8) == 0); 184 185 /* test if really zeroed */ 186 a = regional_alloc_zero(r, 32); 187 str="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 188 unit_assert(a); 189 unit_assert(memcmp(a, str, 32) == 0); 190 191 /* test if copied over (and null byte) */ 192 str = "an interesting string"; 193 a = regional_strdup(r, str); 194 unit_assert(a); 195 unit_assert(memcmp(a, str, strlen(str)+1) == 0); 196 197 regional_free_all(r); 198 } 199 200 /** test specific cases */ 201 static void 202 specific_cases(void) 203 { 204 struct regional* r = regional_create(); 205 corner_cases(r); 206 regional_destroy(r); 207 r = regional_create_custom(2048); /* a small regional */ 208 unit_assert(r->first_size == 2048); 209 unit_assert(regional_get_mem(r) == 2048); 210 corner_cases(r); 211 unit_assert(regional_get_mem(r) == 2048); 212 regional_destroy(r); 213 } 214 215 /** put random stuff in a region and free it */ 216 static void 217 burden_test(size_t max) 218 { 219 size_t get; 220 void* a; 221 int i; 222 struct regional* r = regional_create_custom(2048); 223 for(i=0; i<1000; i++) { 224 get = random() % max; 225 a = regional_alloc(r, get); 226 unit_assert(a); 227 memset(a, 0x54, get); 228 } 229 regional_free_all(r); 230 regional_destroy(r); 231 } 232 233 /** randomly allocate stuff */ 234 static void 235 random_burden(void) 236 { 237 size_t max_alloc = 2048 + 128; /* small chance of LARGE */ 238 int i; 239 for(i=0; i<100; i++) 240 burden_test(max_alloc); 241 } 242 243 void regional_test(void) 244 { 245 unit_show_feature("regional"); 246 specific_cases(); 247 random_burden(); 248 } 249