1ae8c6e27Sflorian /* 2ae8c6e27Sflorian * util/alloc.c - memory allocation service. 3ae8c6e27Sflorian * 4ae8c6e27Sflorian * Copyright (c) 2007, NLnet Labs. All rights reserved. 5ae8c6e27Sflorian * 6ae8c6e27Sflorian * This software is open source. 7ae8c6e27Sflorian * 8ae8c6e27Sflorian * Redistribution and use in source and binary forms, with or without 9ae8c6e27Sflorian * modification, are permitted provided that the following conditions 10ae8c6e27Sflorian * are met: 11ae8c6e27Sflorian * 12ae8c6e27Sflorian * Redistributions of source code must retain the above copyright notice, 13ae8c6e27Sflorian * this list of conditions and the following disclaimer. 14ae8c6e27Sflorian * 15ae8c6e27Sflorian * Redistributions in binary form must reproduce the above copyright notice, 16ae8c6e27Sflorian * this list of conditions and the following disclaimer in the documentation 17ae8c6e27Sflorian * and/or other materials provided with the distribution. 18ae8c6e27Sflorian * 19ae8c6e27Sflorian * Neither the name of the NLNET LABS nor the names of its contributors may 20ae8c6e27Sflorian * be used to endorse or promote products derived from this software without 21ae8c6e27Sflorian * specific prior written permission. 22ae8c6e27Sflorian * 23ae8c6e27Sflorian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24ae8c6e27Sflorian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25ae8c6e27Sflorian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26ae8c6e27Sflorian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27ae8c6e27Sflorian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28ae8c6e27Sflorian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29ae8c6e27Sflorian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30ae8c6e27Sflorian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31ae8c6e27Sflorian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32ae8c6e27Sflorian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33ae8c6e27Sflorian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34ae8c6e27Sflorian */ 35ae8c6e27Sflorian 36ae8c6e27Sflorian /** 37ae8c6e27Sflorian * \file 38ae8c6e27Sflorian * 39ae8c6e27Sflorian * This file contains memory allocation functions. 40ae8c6e27Sflorian */ 41ae8c6e27Sflorian 42ae8c6e27Sflorian #include "config.h" 43ae8c6e27Sflorian #include "util/alloc.h" 44ae8c6e27Sflorian #include "util/regional.h" 45ae8c6e27Sflorian #include "util/data/packed_rrset.h" 46ae8c6e27Sflorian #include "util/fptr_wlist.h" 47ae8c6e27Sflorian 48ae8c6e27Sflorian /** custom size of cached regional blocks */ 49ae8c6e27Sflorian #define ALLOC_REG_SIZE 16384 50ae8c6e27Sflorian /** number of bits for ID part of uint64, rest for number of threads. */ 51ae8c6e27Sflorian #define THRNUM_SHIFT 48 /* for 65k threads, 2^48 rrsets per thr. */ 52ae8c6e27Sflorian 53ae8c6e27Sflorian /** setup new special type */ 54ae8c6e27Sflorian static void 55ae8c6e27Sflorian alloc_setup_special(alloc_special_type* t) 56ae8c6e27Sflorian { 57ae8c6e27Sflorian memset(t, 0, sizeof(*t)); 58ae8c6e27Sflorian lock_rw_init(&t->entry.lock); 59ae8c6e27Sflorian t->entry.key = t; 60ae8c6e27Sflorian } 61ae8c6e27Sflorian 62ae8c6e27Sflorian /** prealloc some entries in the cache. To minimize contention. 63ae8c6e27Sflorian * Result is 1 lock per alloc_max newly created entries. 64ae8c6e27Sflorian * @param alloc: the structure to fill up. 65ae8c6e27Sflorian */ 66ae8c6e27Sflorian static void 67ae8c6e27Sflorian prealloc_setup(struct alloc_cache* alloc) 68ae8c6e27Sflorian { 69ae8c6e27Sflorian alloc_special_type* p; 70ae8c6e27Sflorian int i; 71ae8c6e27Sflorian for(i=0; i<ALLOC_SPECIAL_MAX; i++) { 72ae8c6e27Sflorian if(!(p = (alloc_special_type*)malloc( 73ae8c6e27Sflorian sizeof(alloc_special_type)))) { 74ae8c6e27Sflorian log_err("prealloc: out of memory"); 75ae8c6e27Sflorian return; 76ae8c6e27Sflorian } 77ae8c6e27Sflorian alloc_setup_special(p); 78ae8c6e27Sflorian alloc_set_special_next(p, alloc->quar); 79ae8c6e27Sflorian alloc->quar = p; 80ae8c6e27Sflorian alloc->num_quar++; 81ae8c6e27Sflorian } 82ae8c6e27Sflorian } 83ae8c6e27Sflorian 84ae8c6e27Sflorian /** prealloc region blocks */ 85ae8c6e27Sflorian static void 86ae8c6e27Sflorian prealloc_blocks(struct alloc_cache* alloc, size_t num) 87ae8c6e27Sflorian { 88ae8c6e27Sflorian size_t i; 89ae8c6e27Sflorian struct regional* r; 90ae8c6e27Sflorian for(i=0; i<num; i++) { 91ae8c6e27Sflorian r = regional_create_custom(ALLOC_REG_SIZE); 92ae8c6e27Sflorian if(!r) { 93ae8c6e27Sflorian log_err("prealloc blocks: out of memory"); 94ae8c6e27Sflorian return; 95ae8c6e27Sflorian } 96ae8c6e27Sflorian r->next = (char*)alloc->reg_list; 97ae8c6e27Sflorian alloc->reg_list = r; 98ae8c6e27Sflorian alloc->num_reg_blocks ++; 99ae8c6e27Sflorian } 100ae8c6e27Sflorian } 101ae8c6e27Sflorian 102ae8c6e27Sflorian void 103ae8c6e27Sflorian alloc_init(struct alloc_cache* alloc, struct alloc_cache* super, 104ae8c6e27Sflorian int thread_num) 105ae8c6e27Sflorian { 106ae8c6e27Sflorian memset(alloc, 0, sizeof(*alloc)); 107ae8c6e27Sflorian alloc->super = super; 108ae8c6e27Sflorian alloc->thread_num = thread_num; 109ae8c6e27Sflorian alloc->next_id = (uint64_t)thread_num; /* in steps, so that type */ 110ae8c6e27Sflorian alloc->next_id <<= THRNUM_SHIFT; /* of *_id is used. */ 111ae8c6e27Sflorian alloc->last_id = 1; /* so no 64bit constants, */ 112ae8c6e27Sflorian alloc->last_id <<= THRNUM_SHIFT; /* or implicit 'int' ops. */ 113ae8c6e27Sflorian alloc->last_id -= 1; /* for compiler portability. */ 114ae8c6e27Sflorian alloc->last_id |= alloc->next_id; 115ae8c6e27Sflorian alloc->next_id += 1; /* because id=0 is special. */ 1169946295bSotto alloc->max_reg_blocks = 10; 117ae8c6e27Sflorian alloc->num_reg_blocks = 0; 118ae8c6e27Sflorian alloc->reg_list = NULL; 119ae8c6e27Sflorian alloc->cleanup = NULL; 120ae8c6e27Sflorian alloc->cleanup_arg = NULL; 121ae8c6e27Sflorian if(alloc->super) 122ae8c6e27Sflorian prealloc_blocks(alloc, alloc->max_reg_blocks); 123ae8c6e27Sflorian if(!alloc->super) { 124ae8c6e27Sflorian lock_quick_init(&alloc->lock); 125ae8c6e27Sflorian lock_protect(&alloc->lock, alloc, sizeof(*alloc)); 126ae8c6e27Sflorian } 127ae8c6e27Sflorian } 128ae8c6e27Sflorian 129ae8c6e27Sflorian /** free the special list */ 130ae8c6e27Sflorian static void 131ae8c6e27Sflorian alloc_clear_special_list(struct alloc_cache* alloc) 132ae8c6e27Sflorian { 133ae8c6e27Sflorian alloc_special_type* p, *np; 134ae8c6e27Sflorian /* free */ 135ae8c6e27Sflorian p = alloc->quar; 136ae8c6e27Sflorian while(p) { 137ae8c6e27Sflorian np = alloc_special_next(p); 138ae8c6e27Sflorian /* deinit special type */ 139ae8c6e27Sflorian lock_rw_destroy(&p->entry.lock); 140ae8c6e27Sflorian free(p); 141ae8c6e27Sflorian p = np; 142ae8c6e27Sflorian } 143ae8c6e27Sflorian } 144ae8c6e27Sflorian 145ae8c6e27Sflorian void 146ae8c6e27Sflorian alloc_clear_special(struct alloc_cache* alloc) 147ae8c6e27Sflorian { 148ae8c6e27Sflorian if(!alloc->super) { 149ae8c6e27Sflorian lock_quick_lock(&alloc->lock); 150ae8c6e27Sflorian } 151ae8c6e27Sflorian alloc_clear_special_list(alloc); 152ae8c6e27Sflorian alloc->quar = 0; 153ae8c6e27Sflorian alloc->num_quar = 0; 154ae8c6e27Sflorian if(!alloc->super) { 155ae8c6e27Sflorian lock_quick_unlock(&alloc->lock); 156ae8c6e27Sflorian } 157ae8c6e27Sflorian } 158ae8c6e27Sflorian 159ae8c6e27Sflorian void 160ae8c6e27Sflorian alloc_clear(struct alloc_cache* alloc) 161ae8c6e27Sflorian { 162ae8c6e27Sflorian alloc_special_type* p; 163ae8c6e27Sflorian struct regional* r, *nr; 164ae8c6e27Sflorian if(!alloc) 165ae8c6e27Sflorian return; 166ae8c6e27Sflorian if(!alloc->super) { 167ae8c6e27Sflorian lock_quick_destroy(&alloc->lock); 168ae8c6e27Sflorian } 169ae8c6e27Sflorian if(alloc->super && alloc->quar) { 170ae8c6e27Sflorian /* push entire list into super */ 171ae8c6e27Sflorian p = alloc->quar; 172ae8c6e27Sflorian while(alloc_special_next(p)) /* find last */ 173ae8c6e27Sflorian p = alloc_special_next(p); 174ae8c6e27Sflorian lock_quick_lock(&alloc->super->lock); 175ae8c6e27Sflorian alloc_set_special_next(p, alloc->super->quar); 176ae8c6e27Sflorian alloc->super->quar = alloc->quar; 177ae8c6e27Sflorian alloc->super->num_quar += alloc->num_quar; 178ae8c6e27Sflorian lock_quick_unlock(&alloc->super->lock); 179ae8c6e27Sflorian } else { 180ae8c6e27Sflorian alloc_clear_special_list(alloc); 181ae8c6e27Sflorian } 182ae8c6e27Sflorian alloc->quar = 0; 183ae8c6e27Sflorian alloc->num_quar = 0; 184ae8c6e27Sflorian r = alloc->reg_list; 185ae8c6e27Sflorian while(r) { 186ae8c6e27Sflorian nr = (struct regional*)r->next; 187ae8c6e27Sflorian free(r); 188ae8c6e27Sflorian r = nr; 189ae8c6e27Sflorian } 190ae8c6e27Sflorian alloc->reg_list = NULL; 191ae8c6e27Sflorian alloc->num_reg_blocks = 0; 192ae8c6e27Sflorian } 193ae8c6e27Sflorian 194ae8c6e27Sflorian uint64_t 195ae8c6e27Sflorian alloc_get_id(struct alloc_cache* alloc) 196ae8c6e27Sflorian { 197ae8c6e27Sflorian uint64_t id = alloc->next_id++; 198ae8c6e27Sflorian if(id == alloc->last_id) { 199ae8c6e27Sflorian log_warn("rrset alloc: out of 64bit ids. Clearing cache."); 200ae8c6e27Sflorian fptr_ok(fptr_whitelist_alloc_cleanup(alloc->cleanup)); 201ae8c6e27Sflorian (*alloc->cleanup)(alloc->cleanup_arg); 202ae8c6e27Sflorian 203ae8c6e27Sflorian /* start back at first number */ /* like in alloc_init*/ 204ae8c6e27Sflorian alloc->next_id = (uint64_t)alloc->thread_num; 205ae8c6e27Sflorian alloc->next_id <<= THRNUM_SHIFT; /* in steps for comp. */ 206ae8c6e27Sflorian alloc->next_id += 1; /* portability. */ 207ae8c6e27Sflorian /* and generate new and safe id */ 208ae8c6e27Sflorian id = alloc->next_id++; 209ae8c6e27Sflorian } 210ae8c6e27Sflorian return id; 211ae8c6e27Sflorian } 212ae8c6e27Sflorian 213ae8c6e27Sflorian alloc_special_type* 214ae8c6e27Sflorian alloc_special_obtain(struct alloc_cache* alloc) 215ae8c6e27Sflorian { 216ae8c6e27Sflorian alloc_special_type* p; 217ae8c6e27Sflorian log_assert(alloc); 218ae8c6e27Sflorian /* see if in local cache */ 219ae8c6e27Sflorian if(alloc->quar) { 220ae8c6e27Sflorian p = alloc->quar; 221ae8c6e27Sflorian alloc->quar = alloc_special_next(p); 222ae8c6e27Sflorian alloc->num_quar--; 223ae8c6e27Sflorian p->id = alloc_get_id(alloc); 224ae8c6e27Sflorian return p; 225ae8c6e27Sflorian } 226ae8c6e27Sflorian /* see if in global cache */ 227ae8c6e27Sflorian if(alloc->super) { 228ae8c6e27Sflorian /* could maybe grab alloc_max/2 entries in one go, 229ae8c6e27Sflorian * but really, isn't that just as fast as this code? */ 230ae8c6e27Sflorian lock_quick_lock(&alloc->super->lock); 231ae8c6e27Sflorian if((p = alloc->super->quar)) { 232ae8c6e27Sflorian alloc->super->quar = alloc_special_next(p); 233ae8c6e27Sflorian alloc->super->num_quar--; 234ae8c6e27Sflorian } 235ae8c6e27Sflorian lock_quick_unlock(&alloc->super->lock); 236ae8c6e27Sflorian if(p) { 237ae8c6e27Sflorian p->id = alloc_get_id(alloc); 238ae8c6e27Sflorian return p; 239ae8c6e27Sflorian } 240ae8c6e27Sflorian } 241ae8c6e27Sflorian /* allocate new */ 242ae8c6e27Sflorian prealloc_setup(alloc); 243ae8c6e27Sflorian if(!(p = (alloc_special_type*)malloc(sizeof(alloc_special_type)))) { 244ae8c6e27Sflorian log_err("alloc_special_obtain: out of memory"); 245ae8c6e27Sflorian return NULL; 246ae8c6e27Sflorian } 247ae8c6e27Sflorian alloc_setup_special(p); 248ae8c6e27Sflorian p->id = alloc_get_id(alloc); 249ae8c6e27Sflorian return p; 250ae8c6e27Sflorian } 251ae8c6e27Sflorian 252ae8c6e27Sflorian /** push mem and some more items to the super */ 253ae8c6e27Sflorian static void 254ae8c6e27Sflorian pushintosuper(struct alloc_cache* alloc, alloc_special_type* mem) 255ae8c6e27Sflorian { 256ae8c6e27Sflorian int i; 257ae8c6e27Sflorian alloc_special_type *p = alloc->quar; 258ae8c6e27Sflorian log_assert(p); 259ae8c6e27Sflorian log_assert(alloc && alloc->super && 260ae8c6e27Sflorian alloc->num_quar >= ALLOC_SPECIAL_MAX); 261ae8c6e27Sflorian /* push ALLOC_SPECIAL_MAX/2 after mem */ 262ae8c6e27Sflorian alloc_set_special_next(mem, alloc->quar); 263ae8c6e27Sflorian for(i=1; i<ALLOC_SPECIAL_MAX/2; i++) { 264ae8c6e27Sflorian p = alloc_special_next(p); 265ae8c6e27Sflorian } 266ae8c6e27Sflorian alloc->quar = alloc_special_next(p); 267ae8c6e27Sflorian alloc->num_quar -= ALLOC_SPECIAL_MAX/2; 268ae8c6e27Sflorian 269ae8c6e27Sflorian /* dump mem+list into the super quar list */ 270ae8c6e27Sflorian lock_quick_lock(&alloc->super->lock); 271ae8c6e27Sflorian alloc_set_special_next(p, alloc->super->quar); 272ae8c6e27Sflorian alloc->super->quar = mem; 273ae8c6e27Sflorian alloc->super->num_quar += ALLOC_SPECIAL_MAX/2 + 1; 274ae8c6e27Sflorian lock_quick_unlock(&alloc->super->lock); 275ae8c6e27Sflorian /* so 1 lock per mem+alloc/2 deletes */ 276ae8c6e27Sflorian } 277ae8c6e27Sflorian 278ae8c6e27Sflorian void 279ae8c6e27Sflorian alloc_special_release(struct alloc_cache* alloc, alloc_special_type* mem) 280ae8c6e27Sflorian { 281ae8c6e27Sflorian log_assert(alloc); 282ae8c6e27Sflorian if(!mem) 283ae8c6e27Sflorian return; 284ae8c6e27Sflorian if(!alloc->super) { 285ae8c6e27Sflorian lock_quick_lock(&alloc->lock); /* superalloc needs locking */ 286ae8c6e27Sflorian } 287ae8c6e27Sflorian 288ae8c6e27Sflorian alloc_special_clean(mem); 289ae8c6e27Sflorian if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) { 290ae8c6e27Sflorian /* push it to the super structure */ 291ae8c6e27Sflorian pushintosuper(alloc, mem); 292ae8c6e27Sflorian return; 293ae8c6e27Sflorian } 294ae8c6e27Sflorian 295ae8c6e27Sflorian alloc_set_special_next(mem, alloc->quar); 296ae8c6e27Sflorian alloc->quar = mem; 297ae8c6e27Sflorian alloc->num_quar++; 298ae8c6e27Sflorian if(!alloc->super) { 299ae8c6e27Sflorian lock_quick_unlock(&alloc->lock); 300ae8c6e27Sflorian } 301ae8c6e27Sflorian } 302ae8c6e27Sflorian 303ae8c6e27Sflorian void 304ae8c6e27Sflorian alloc_stats(struct alloc_cache* alloc) 305ae8c6e27Sflorian { 306ae8c6e27Sflorian log_info("%salloc: %d in cache, %d blocks.", alloc->super?"":"sup", 307ae8c6e27Sflorian (int)alloc->num_quar, (int)alloc->num_reg_blocks); 308ae8c6e27Sflorian } 309ae8c6e27Sflorian 310ae8c6e27Sflorian size_t alloc_get_mem(struct alloc_cache* alloc) 311ae8c6e27Sflorian { 312ae8c6e27Sflorian alloc_special_type* p; 313ae8c6e27Sflorian size_t s = sizeof(*alloc); 314ae8c6e27Sflorian if(!alloc->super) { 315ae8c6e27Sflorian lock_quick_lock(&alloc->lock); /* superalloc needs locking */ 316ae8c6e27Sflorian } 317ae8c6e27Sflorian s += sizeof(alloc_special_type) * alloc->num_quar; 318ae8c6e27Sflorian for(p = alloc->quar; p; p = alloc_special_next(p)) { 319ae8c6e27Sflorian s += lock_get_mem(&p->entry.lock); 320ae8c6e27Sflorian } 321ae8c6e27Sflorian s += alloc->num_reg_blocks * ALLOC_REG_SIZE; 322ae8c6e27Sflorian if(!alloc->super) { 323ae8c6e27Sflorian lock_quick_unlock(&alloc->lock); 324ae8c6e27Sflorian } 325ae8c6e27Sflorian return s; 326ae8c6e27Sflorian } 327ae8c6e27Sflorian 328ae8c6e27Sflorian struct regional* 329ae8c6e27Sflorian alloc_reg_obtain(struct alloc_cache* alloc) 330ae8c6e27Sflorian { 331ae8c6e27Sflorian if(alloc->num_reg_blocks > 0) { 332ae8c6e27Sflorian struct regional* r = alloc->reg_list; 333ae8c6e27Sflorian alloc->reg_list = (struct regional*)r->next; 334ae8c6e27Sflorian r->next = NULL; 335ae8c6e27Sflorian alloc->num_reg_blocks--; 336ae8c6e27Sflorian return r; 337ae8c6e27Sflorian } 338ae8c6e27Sflorian return regional_create_custom(ALLOC_REG_SIZE); 339ae8c6e27Sflorian } 340ae8c6e27Sflorian 341ae8c6e27Sflorian void 342ae8c6e27Sflorian alloc_reg_release(struct alloc_cache* alloc, struct regional* r) 343ae8c6e27Sflorian { 344ae8c6e27Sflorian if(alloc->num_reg_blocks >= alloc->max_reg_blocks) { 345ae8c6e27Sflorian regional_destroy(r); 346ae8c6e27Sflorian return; 347ae8c6e27Sflorian } 348ae8c6e27Sflorian if(!r) return; 349ae8c6e27Sflorian regional_free_all(r); 350ae8c6e27Sflorian log_assert(r->next == NULL); 351ae8c6e27Sflorian r->next = (char*)alloc->reg_list; 352ae8c6e27Sflorian alloc->reg_list = r; 353ae8c6e27Sflorian alloc->num_reg_blocks++; 354ae8c6e27Sflorian } 355ae8c6e27Sflorian 356ae8c6e27Sflorian void 357ae8c6e27Sflorian alloc_set_id_cleanup(struct alloc_cache* alloc, void (*cleanup)(void*), 358ae8c6e27Sflorian void* arg) 359ae8c6e27Sflorian { 360ae8c6e27Sflorian alloc->cleanup = cleanup; 361ae8c6e27Sflorian alloc->cleanup_arg = arg; 362ae8c6e27Sflorian } 363ae8c6e27Sflorian 364ae8c6e27Sflorian /** global debug value to keep track of total memory mallocs */ 365ae8c6e27Sflorian size_t unbound_mem_alloc = 0; 366ae8c6e27Sflorian /** global debug value to keep track of total memory frees */ 367ae8c6e27Sflorian size_t unbound_mem_freed = 0; 368ae8c6e27Sflorian #ifdef UNBOUND_ALLOC_STATS 369ae8c6e27Sflorian /** special value to know if the memory is being tracked */ 370ae8c6e27Sflorian uint64_t mem_special = (uint64_t)0xfeed43327766abcdLL; 371ae8c6e27Sflorian #ifdef malloc 372ae8c6e27Sflorian #undef malloc 373ae8c6e27Sflorian #endif 374ae8c6e27Sflorian /** malloc with stats */ 375ae8c6e27Sflorian void *unbound_stat_malloc(size_t size) 376ae8c6e27Sflorian { 377ae8c6e27Sflorian void* res; 378ae8c6e27Sflorian if(size == 0) size = 1; 3799b465e50Sflorian log_assert(size <= SIZE_MAX-16); 380ae8c6e27Sflorian res = malloc(size+16); 381ae8c6e27Sflorian if(!res) return NULL; 382ae8c6e27Sflorian unbound_mem_alloc += size; 383ae8c6e27Sflorian log_info("stat %p=malloc(%u)", res+16, (unsigned)size); 384ae8c6e27Sflorian memcpy(res, &size, sizeof(size)); 385ae8c6e27Sflorian memcpy(res+8, &mem_special, sizeof(mem_special)); 386ae8c6e27Sflorian return res+16; 387ae8c6e27Sflorian } 388ae8c6e27Sflorian #ifdef calloc 389ae8c6e27Sflorian #undef calloc 390ae8c6e27Sflorian #endif 391ae8c6e27Sflorian #ifndef INT_MAX 392ae8c6e27Sflorian #define INT_MAX (((int)-1)>>1) 393ae8c6e27Sflorian #endif 394ae8c6e27Sflorian /** calloc with stats */ 395ae8c6e27Sflorian void *unbound_stat_calloc(size_t nmemb, size_t size) 396ae8c6e27Sflorian { 397ae8c6e27Sflorian size_t s; 398ae8c6e27Sflorian void* res; 399ae8c6e27Sflorian if(nmemb != 0 && INT_MAX/nmemb < size) 400ae8c6e27Sflorian return NULL; /* integer overflow check */ 401ae8c6e27Sflorian s = (nmemb*size==0)?(size_t)1:nmemb*size; 4029b465e50Sflorian log_assert(s <= SIZE_MAX-16); 403ae8c6e27Sflorian res = calloc(1, s+16); 404ae8c6e27Sflorian if(!res) return NULL; 405ae8c6e27Sflorian log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, (unsigned)size); 406ae8c6e27Sflorian unbound_mem_alloc += s; 407ae8c6e27Sflorian memcpy(res, &s, sizeof(s)); 408ae8c6e27Sflorian memcpy(res+8, &mem_special, sizeof(mem_special)); 409ae8c6e27Sflorian return res+16; 410ae8c6e27Sflorian } 411ae8c6e27Sflorian #ifdef free 412ae8c6e27Sflorian #undef free 413ae8c6e27Sflorian #endif 414ae8c6e27Sflorian /** free with stats */ 415ae8c6e27Sflorian void unbound_stat_free(void *ptr) 416ae8c6e27Sflorian { 417ae8c6e27Sflorian size_t s; 418ae8c6e27Sflorian if(!ptr) return; 419ae8c6e27Sflorian if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) { 420ae8c6e27Sflorian free(ptr); 421ae8c6e27Sflorian return; 422ae8c6e27Sflorian } 423ae8c6e27Sflorian ptr-=16; 424ae8c6e27Sflorian memcpy(&s, ptr, sizeof(s)); 425ae8c6e27Sflorian log_info("stat free(%p) size %u", ptr+16, (unsigned)s); 426ae8c6e27Sflorian memset(ptr+8, 0, 8); 427ae8c6e27Sflorian unbound_mem_freed += s; 428ae8c6e27Sflorian free(ptr); 429ae8c6e27Sflorian } 430ae8c6e27Sflorian #ifdef realloc 431ae8c6e27Sflorian #undef realloc 432ae8c6e27Sflorian #endif 433ae8c6e27Sflorian /** realloc with stats */ 434ae8c6e27Sflorian void *unbound_stat_realloc(void *ptr, size_t size) 435ae8c6e27Sflorian { 436ae8c6e27Sflorian size_t cursz; 437ae8c6e27Sflorian void* res; 438ae8c6e27Sflorian if(!ptr) return unbound_stat_malloc(size); 439ae8c6e27Sflorian if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) { 440ae8c6e27Sflorian return realloc(ptr, size); 441ae8c6e27Sflorian } 442ae8c6e27Sflorian if(size==0) { 443ae8c6e27Sflorian unbound_stat_free(ptr); 444ae8c6e27Sflorian return NULL; 445ae8c6e27Sflorian } 446ae8c6e27Sflorian ptr -= 16; 447ae8c6e27Sflorian memcpy(&cursz, ptr, sizeof(cursz)); 448ae8c6e27Sflorian if(cursz == size) { 449ae8c6e27Sflorian /* nothing changes */ 450ae8c6e27Sflorian return ptr; 451ae8c6e27Sflorian } 4529b465e50Sflorian log_assert(size <= SIZE_MAX-16); 453ae8c6e27Sflorian res = malloc(size+16); 454ae8c6e27Sflorian if(!res) return NULL; 455ae8c6e27Sflorian unbound_mem_alloc += size; 456ae8c6e27Sflorian unbound_mem_freed += cursz; 457ae8c6e27Sflorian log_info("stat realloc(%p, %u) from %u", ptr+16, (unsigned)size, (unsigned)cursz); 458ae8c6e27Sflorian if(cursz > size) { 459ae8c6e27Sflorian memcpy(res+16, ptr+16, size); 460ae8c6e27Sflorian } else if(size > cursz) { 461ae8c6e27Sflorian memcpy(res+16, ptr+16, cursz); 462ae8c6e27Sflorian } 463ae8c6e27Sflorian memset(ptr+8, 0, 8); 464ae8c6e27Sflorian free(ptr); 465ae8c6e27Sflorian memcpy(res, &size, sizeof(size)); 466ae8c6e27Sflorian memcpy(res+8, &mem_special, sizeof(mem_special)); 467ae8c6e27Sflorian return res+16; 468ae8c6e27Sflorian } 469*7037e34cSflorian /** strdup with stats */ 470*7037e34cSflorian char *unbound_stat_strdup(const char* s) 471*7037e34cSflorian { 472*7037e34cSflorian size_t len; 473*7037e34cSflorian char* res; 474*7037e34cSflorian if(!s) return NULL; 475*7037e34cSflorian len = strlen(s); 476*7037e34cSflorian res = unbound_stat_malloc(len+1); 477*7037e34cSflorian if(!res) return NULL; 478*7037e34cSflorian memmove(res, s, len+1); 479*7037e34cSflorian return res; 480*7037e34cSflorian } 481ae8c6e27Sflorian 482ae8c6e27Sflorian /** log to file where alloc was done */ 483ae8c6e27Sflorian void *unbound_stat_malloc_log(size_t size, const char* file, int line, 484ae8c6e27Sflorian const char* func) 485ae8c6e27Sflorian { 486ae8c6e27Sflorian log_info("%s:%d %s malloc(%u)", file, line, func, (unsigned)size); 487ae8c6e27Sflorian return unbound_stat_malloc(size); 488ae8c6e27Sflorian } 489ae8c6e27Sflorian 490ae8c6e27Sflorian /** log to file where alloc was done */ 491ae8c6e27Sflorian void *unbound_stat_calloc_log(size_t nmemb, size_t size, const char* file, 492ae8c6e27Sflorian int line, const char* func) 493ae8c6e27Sflorian { 494ae8c6e27Sflorian log_info("%s:%d %s calloc(%u, %u)", file, line, func, 495ae8c6e27Sflorian (unsigned) nmemb, (unsigned)size); 496ae8c6e27Sflorian return unbound_stat_calloc(nmemb, size); 497ae8c6e27Sflorian } 498ae8c6e27Sflorian 499ae8c6e27Sflorian /** log to file where free was done */ 500ae8c6e27Sflorian void unbound_stat_free_log(void *ptr, const char* file, int line, 501ae8c6e27Sflorian const char* func) 502ae8c6e27Sflorian { 503ae8c6e27Sflorian if(ptr && memcmp(ptr-8, &mem_special, sizeof(mem_special)) == 0) { 504ae8c6e27Sflorian size_t s; 505ae8c6e27Sflorian memcpy(&s, ptr-16, sizeof(s)); 506ae8c6e27Sflorian log_info("%s:%d %s free(%p) size %u", 507ae8c6e27Sflorian file, line, func, ptr, (unsigned)s); 508ae8c6e27Sflorian } else 509ae8c6e27Sflorian log_info("%s:%d %s unmatched free(%p)", file, line, func, ptr); 510ae8c6e27Sflorian unbound_stat_free(ptr); 511ae8c6e27Sflorian } 512ae8c6e27Sflorian 513ae8c6e27Sflorian /** log to file where alloc was done */ 514ae8c6e27Sflorian void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file, 515ae8c6e27Sflorian int line, const char* func) 516ae8c6e27Sflorian { 517ae8c6e27Sflorian log_info("%s:%d %s realloc(%p, %u)", file, line, func, 518ae8c6e27Sflorian ptr, (unsigned)size); 519ae8c6e27Sflorian return unbound_stat_realloc(ptr, size); 520ae8c6e27Sflorian } 521ae8c6e27Sflorian 522*7037e34cSflorian /** log to file where strdup was done */ 523*7037e34cSflorian char *unbound_stat_strdup_log(const char *s, const char* file, int line, 524*7037e34cSflorian const char* func) 525*7037e34cSflorian { 526*7037e34cSflorian log_info("%s:%d %s strdup size %u", file, line, func, 527*7037e34cSflorian (s?(unsigned)strlen(s)+1:0)); 528*7037e34cSflorian return unbound_stat_strdup(s); 529*7037e34cSflorian } 530*7037e34cSflorian 531ae8c6e27Sflorian #endif /* UNBOUND_ALLOC_STATS */ 532ae8c6e27Sflorian #ifdef UNBOUND_ALLOC_LITE 533ae8c6e27Sflorian #undef malloc 534ae8c6e27Sflorian #undef calloc 535ae8c6e27Sflorian #undef free 536ae8c6e27Sflorian #undef realloc 537ae8c6e27Sflorian /** length of prefix and suffix */ 538ae8c6e27Sflorian static size_t lite_pad = 16; 539ae8c6e27Sflorian /** prefix value to check */ 540ae8c6e27Sflorian static char* lite_pre = "checkfront123456"; 541ae8c6e27Sflorian /** suffix value to check */ 542ae8c6e27Sflorian static char* lite_post= "checkafter123456"; 543ae8c6e27Sflorian 544ae8c6e27Sflorian void *unbound_stat_malloc_lite(size_t size, const char* file, int line, 545ae8c6e27Sflorian const char* func) 546ae8c6e27Sflorian { 547ae8c6e27Sflorian /* [prefix .. len .. actual data .. suffix] */ 5489b465e50Sflorian void* res; 5499b465e50Sflorian log_assert(size <= SIZE_MAX-(lite_pad*2+sizeof(size_t))); 5509b465e50Sflorian res = malloc(size+lite_pad*2+sizeof(size_t)); 551ae8c6e27Sflorian if(!res) return NULL; 552ae8c6e27Sflorian memmove(res, lite_pre, lite_pad); 553ae8c6e27Sflorian memmove(res+lite_pad, &size, sizeof(size_t)); 554ae8c6e27Sflorian memset(res+lite_pad+sizeof(size_t), 0x1a, size); /* init the memory */ 555ae8c6e27Sflorian memmove(res+lite_pad+size+sizeof(size_t), lite_post, lite_pad); 556ae8c6e27Sflorian return res+lite_pad+sizeof(size_t); 557ae8c6e27Sflorian } 558ae8c6e27Sflorian 559ae8c6e27Sflorian void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file, 560ae8c6e27Sflorian int line, const char* func) 561ae8c6e27Sflorian { 562ae8c6e27Sflorian size_t req; 563ae8c6e27Sflorian void* res; 564ae8c6e27Sflorian if(nmemb != 0 && INT_MAX/nmemb < size) 565ae8c6e27Sflorian return NULL; /* integer overflow check */ 566ae8c6e27Sflorian req = nmemb * size; 5679b465e50Sflorian log_assert(req <= SIZE_MAX-(lite_pad*2+sizeof(size_t))); 568ae8c6e27Sflorian res = malloc(req+lite_pad*2+sizeof(size_t)); 569ae8c6e27Sflorian if(!res) return NULL; 570ae8c6e27Sflorian memmove(res, lite_pre, lite_pad); 571ae8c6e27Sflorian memmove(res+lite_pad, &req, sizeof(size_t)); 572ae8c6e27Sflorian memset(res+lite_pad+sizeof(size_t), 0, req); 573ae8c6e27Sflorian memmove(res+lite_pad+req+sizeof(size_t), lite_post, lite_pad); 574ae8c6e27Sflorian return res+lite_pad+sizeof(size_t); 575ae8c6e27Sflorian } 576ae8c6e27Sflorian 577ae8c6e27Sflorian void unbound_stat_free_lite(void *ptr, const char* file, int line, 578ae8c6e27Sflorian const char* func) 579ae8c6e27Sflorian { 580ae8c6e27Sflorian void* real; 581ae8c6e27Sflorian size_t orig = 0; 582ae8c6e27Sflorian if(!ptr) return; 583ae8c6e27Sflorian real = ptr-lite_pad-sizeof(size_t); 584ae8c6e27Sflorian if(memcmp(real, lite_pre, lite_pad) != 0) { 585ae8c6e27Sflorian log_err("free(): prefix failed %s:%d %s", file, line, func); 586ae8c6e27Sflorian log_hex("prefix here", real, lite_pad); 587ae8c6e27Sflorian log_hex(" should be", lite_pre, lite_pad); 588ae8c6e27Sflorian fatal_exit("alloc assertion failed"); 589ae8c6e27Sflorian } 590ae8c6e27Sflorian memmove(&orig, real+lite_pad, sizeof(size_t)); 591ae8c6e27Sflorian if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){ 592ae8c6e27Sflorian log_err("free(): suffix failed %s:%d %s", file, line, func); 593ae8c6e27Sflorian log_err("alloc size is %d", (int)orig); 594ae8c6e27Sflorian log_hex("suffix here", real+lite_pad+orig+sizeof(size_t), 595ae8c6e27Sflorian lite_pad); 596ae8c6e27Sflorian log_hex(" should be", lite_post, lite_pad); 597ae8c6e27Sflorian fatal_exit("alloc assertion failed"); 598ae8c6e27Sflorian } 599ae8c6e27Sflorian memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */ 600ae8c6e27Sflorian free(real); 601ae8c6e27Sflorian } 602ae8c6e27Sflorian 603ae8c6e27Sflorian void *unbound_stat_realloc_lite(void *ptr, size_t size, const char* file, 604ae8c6e27Sflorian int line, const char* func) 605ae8c6e27Sflorian { 606ae8c6e27Sflorian /* always free and realloc (no growing) */ 607ae8c6e27Sflorian void* real, *newa; 608ae8c6e27Sflorian size_t orig = 0; 609ae8c6e27Sflorian if(!ptr) { 610ae8c6e27Sflorian /* like malloc() */ 611ae8c6e27Sflorian return unbound_stat_malloc_lite(size, file, line, func); 612ae8c6e27Sflorian } 613ae8c6e27Sflorian if(!size) { 614ae8c6e27Sflorian /* like free() */ 615ae8c6e27Sflorian unbound_stat_free_lite(ptr, file, line, func); 616ae8c6e27Sflorian return NULL; 617ae8c6e27Sflorian } 618ae8c6e27Sflorian /* change allocation size and copy */ 619ae8c6e27Sflorian real = ptr-lite_pad-sizeof(size_t); 620ae8c6e27Sflorian if(memcmp(real, lite_pre, lite_pad) != 0) { 621ae8c6e27Sflorian log_err("realloc(): prefix failed %s:%d %s", file, line, func); 622ae8c6e27Sflorian log_hex("prefix here", real, lite_pad); 623ae8c6e27Sflorian log_hex(" should be", lite_pre, lite_pad); 624ae8c6e27Sflorian fatal_exit("alloc assertion failed"); 625ae8c6e27Sflorian } 626ae8c6e27Sflorian memmove(&orig, real+lite_pad, sizeof(size_t)); 627ae8c6e27Sflorian if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){ 628ae8c6e27Sflorian log_err("realloc(): suffix failed %s:%d %s", file, line, func); 629ae8c6e27Sflorian log_err("alloc size is %d", (int)orig); 630ae8c6e27Sflorian log_hex("suffix here", real+lite_pad+orig+sizeof(size_t), 631ae8c6e27Sflorian lite_pad); 632ae8c6e27Sflorian log_hex(" should be", lite_post, lite_pad); 633ae8c6e27Sflorian fatal_exit("alloc assertion failed"); 634ae8c6e27Sflorian } 635ae8c6e27Sflorian /* new alloc and copy over */ 636ae8c6e27Sflorian newa = unbound_stat_malloc_lite(size, file, line, func); 637ae8c6e27Sflorian if(!newa) 638ae8c6e27Sflorian return NULL; 639ae8c6e27Sflorian if(orig < size) 640ae8c6e27Sflorian memmove(newa, ptr, orig); 641ae8c6e27Sflorian else memmove(newa, ptr, size); 642ae8c6e27Sflorian memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */ 643ae8c6e27Sflorian free(real); 644ae8c6e27Sflorian return newa; 645ae8c6e27Sflorian } 646ae8c6e27Sflorian 647ae8c6e27Sflorian char* unbound_strdup_lite(const char* s, const char* file, int line, 648ae8c6e27Sflorian const char* func) 649ae8c6e27Sflorian { 650ae8c6e27Sflorian /* this routine is made to make sure strdup() uses the malloc_lite */ 651ae8c6e27Sflorian size_t l = strlen(s)+1; 652ae8c6e27Sflorian char* n = (char*)unbound_stat_malloc_lite(l, file, line, func); 653ae8c6e27Sflorian if(!n) return NULL; 654ae8c6e27Sflorian memmove(n, s, l); 655ae8c6e27Sflorian return n; 656ae8c6e27Sflorian } 657ae8c6e27Sflorian 658ae8c6e27Sflorian char* unbound_lite_wrapstr(char* s) 659ae8c6e27Sflorian { 660ae8c6e27Sflorian char* n = unbound_strdup_lite(s, __FILE__, __LINE__, __func__); 661ae8c6e27Sflorian free(s); 662ae8c6e27Sflorian return n; 663ae8c6e27Sflorian } 664ae8c6e27Sflorian 665ae8c6e27Sflorian #undef sldns_pkt2wire 666ae8c6e27Sflorian sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p, 667ae8c6e27Sflorian size_t *size) 668ae8c6e27Sflorian { 669ae8c6e27Sflorian uint8_t* md = NULL; 670ae8c6e27Sflorian size_t ms = 0; 671ae8c6e27Sflorian sldns_status s = sldns_pkt2wire(&md, p, &ms); 672ae8c6e27Sflorian if(md) { 673ae8c6e27Sflorian *dest = unbound_stat_malloc_lite(ms, __FILE__, __LINE__, 674ae8c6e27Sflorian __func__); 675ae8c6e27Sflorian *size = ms; 676ae8c6e27Sflorian if(!*dest) { free(md); return LDNS_STATUS_MEM_ERR; } 677ae8c6e27Sflorian memcpy(*dest, md, ms); 678ae8c6e27Sflorian free(md); 679ae8c6e27Sflorian } else { 680ae8c6e27Sflorian *dest = NULL; 681ae8c6e27Sflorian *size = 0; 682ae8c6e27Sflorian } 683ae8c6e27Sflorian return s; 684ae8c6e27Sflorian } 685ae8c6e27Sflorian 686ae8c6e27Sflorian #undef i2d_DSA_SIG 687ae8c6e27Sflorian int unbound_lite_i2d_DSA_SIG(DSA_SIG* dsasig, unsigned char** sig) 688ae8c6e27Sflorian { 689ae8c6e27Sflorian unsigned char* n = NULL; 690ae8c6e27Sflorian int r= i2d_DSA_SIG(dsasig, &n); 691ae8c6e27Sflorian if(n) { 692ae8c6e27Sflorian *sig = unbound_stat_malloc_lite((size_t)r, __FILE__, __LINE__, 693ae8c6e27Sflorian __func__); 694ae8c6e27Sflorian if(!*sig) return -1; 695ae8c6e27Sflorian memcpy(*sig, n, (size_t)r); 696ae8c6e27Sflorian free(n); 697ae8c6e27Sflorian return r; 698ae8c6e27Sflorian } 699ae8c6e27Sflorian *sig = NULL; 700ae8c6e27Sflorian return r; 701ae8c6e27Sflorian } 702ae8c6e27Sflorian 703ae8c6e27Sflorian #endif /* UNBOUND_ALLOC_LITE */ 704