alloc.c revision 287917
1186681Sed/* 2186681Sed * util/alloc.c - memory allocation service. 3186681Sed * 4186681Sed * Copyright (c) 2007, NLnet Labs. All rights reserved. 5186681Sed * 6186681Sed * This software is open source. 7186681Sed * 8186681Sed * Redistribution and use in source and binary forms, with or without 9186681Sed * modification, are permitted provided that the following conditions 10186681Sed * are met: 11186681Sed * 12186681Sed * Redistributions of source code must retain the above copyright notice, 13186681Sed * this list of conditions and the following disclaimer. 14186681Sed * 15186681Sed * Redistributions in binary form must reproduce the above copyright notice, 16186681Sed * this list of conditions and the following disclaimer in the documentation 17186681Sed * and/or other materials provided with the distribution. 18186681Sed * 19186681Sed * Neither the name of the NLNET LABS nor the names of its contributors may 20186681Sed * be used to endorse or promote products derived from this software without 21186681Sed * specific prior written permission. 22186681Sed * 23186681Sed * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24186681Sed * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25186681Sed * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26186681Sed * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27186681Sed * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28186681Sed * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29186681Sed * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30186681Sed * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31186681Sed * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32286798Sed * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33186681Sed * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34186681Sed */ 35186681Sed 36186681Sed/** 37186681Sed * \file 38186681Sed * 39286798Sed * This file contains memory allocation functions. 40206141Sed */ 41186681Sed 42186681Sed#include "config.h" 43186681Sed#include "util/alloc.h" 44186681Sed#include "util/regional.h" 45186681Sed#include "util/data/packed_rrset.h" 46221698Sed#include "util/fptr_wlist.h" 47221698Sed 48221698Sed/** custom size of cached regional blocks */ 49186681Sed#define ALLOC_REG_SIZE 16384 50199171Sed/** number of bits for ID part of uint64, rest for number of threads. */ 51199171Sed#define THRNUM_SHIFT 48 /* for 65k threads, 2^48 rrsets per thr. */ 52199171Sed 53199171Sed/** setup new special type */ 54199171Sedstatic void 55199171Sedalloc_setup_special(alloc_special_t* t) 56199171Sed{ 57199171Sed memset(t, 0, sizeof(*t)); 58199171Sed lock_rw_init(&t->entry.lock); 59186681Sed t->entry.key = t; 60186681Sed} 61186681Sed 62186681Sed/** prealloc some entries in the cache. To minimize contention. 63197470Sed * Result is 1 lock per alloc_max newly created entries. 64197470Sed * @param alloc: the structure to fill up. 65197470Sed */ 66197470Sedstatic void 67186681Sedprealloc(struct alloc_cache* alloc) 68186681Sed{ 69186681Sed alloc_special_t* p; 70186681Sed int i; 71186681Sed for(i=0; i<ALLOC_SPECIAL_MAX; i++) { 72186681Sed if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) { 73186681Sed log_err("prealloc: out of memory"); 74186681Sed return; 75186681Sed } 76186681Sed alloc_setup_special(p); 77186681Sed alloc_set_special_next(p, alloc->quar); 78186681Sed alloc->quar = p; 79186681Sed alloc->num_quar++; 80186681Sed } 81186681Sed} 82186681Sed 83186681Sed/** prealloc region blocks */ 84186681Sedstatic void 85186681Sedprealloc_blocks(struct alloc_cache* alloc, size_t num) 86186681Sed{ 87186681Sed size_t i; 88186681Sed struct regional* r; 89186681Sed for(i=0; i<num; i++) { 90186681Sed r = regional_create_custom(ALLOC_REG_SIZE); 91186681Sed if(!r) { 92186681Sed log_err("prealloc blocks: out of memory"); 93186681Sed return; 94186681Sed } 95186681Sed r->next = (char*)alloc->reg_list; 96186681Sed alloc->reg_list = r; 97186681Sed alloc->num_reg_blocks ++; 98186681Sed } 99186681Sed} 100186681Sed 101186681Sedvoid 102186681Sedalloc_init(struct alloc_cache* alloc, struct alloc_cache* super, 103186681Sed int thread_num) 104186681Sed{ 105186681Sed memset(alloc, 0, sizeof(*alloc)); 106186681Sed alloc->super = super; 107186681Sed alloc->thread_num = thread_num; 108186681Sed alloc->next_id = (uint64_t)thread_num; /* in steps, so that type */ 109186681Sed alloc->next_id <<= THRNUM_SHIFT; /* of *_id is used. */ 110186681Sed alloc->last_id = 1; /* so no 64bit constants, */ 111186681Sed alloc->last_id <<= THRNUM_SHIFT; /* or implicit 'int' ops. */ 112186681Sed alloc->last_id -= 1; /* for compiler portability. */ 113186681Sed alloc->last_id |= alloc->next_id; 114186681Sed alloc->next_id += 1; /* because id=0 is special. */ 115186681Sed alloc->max_reg_blocks = 100; 116186681Sed alloc->num_reg_blocks = 0; 117186681Sed alloc->reg_list = NULL; 118186681Sed alloc->cleanup = NULL; 119186681Sed alloc->cleanup_arg = NULL; 120186681Sed if(alloc->super) 121186681Sed prealloc_blocks(alloc, alloc->max_reg_blocks); 122186681Sed if(!alloc->super) { 123186681Sed lock_quick_init(&alloc->lock); 124186681Sed lock_protect(&alloc->lock, alloc, sizeof(*alloc)); 125186681Sed } 126186681Sed} 127186681Sed 128186681Sedvoid 129193184Sedalloc_clear(struct alloc_cache* alloc) 130186681Sed{ 131186681Sed alloc_special_t* p, *np; 132186681Sed struct regional* r, *nr; 133186681Sed if(!alloc) 134186681Sed return; 135186681Sed if(!alloc->super) { 136186681Sed lock_quick_destroy(&alloc->lock); 137186681Sed } 138186681Sed if(alloc->super && alloc->quar) { 139186681Sed /* push entire list into super */ 140186681Sed p = alloc->quar; 141186681Sed while(alloc_special_next(p)) /* find last */ 142186681Sed p = alloc_special_next(p); 143186681Sed lock_quick_lock(&alloc->super->lock); 144186681Sed alloc_set_special_next(p, alloc->super->quar); 145186681Sed alloc->super->quar = alloc->quar; 146186681Sed alloc->super->num_quar += alloc->num_quar; 147186681Sed lock_quick_unlock(&alloc->super->lock); 148186681Sed } else { 149186681Sed /* free */ 150186681Sed p = alloc->quar; 151186681Sed while(p) { 152186681Sed np = alloc_special_next(p); 153186681Sed /* deinit special type */ 154186681Sed lock_rw_destroy(&p->entry.lock); 155186681Sed free(p); 156186681Sed p = np; 157186681Sed } 158197117Sed } 159197117Sed alloc->quar = 0; 160186681Sed alloc->num_quar = 0; 161186681Sed r = alloc->reg_list; 162186681Sed while(r) { 163186681Sed nr = (struct regional*)r->next; 164186681Sed free(r); 165186681Sed r = nr; 166186681Sed } 167186681Sed alloc->reg_list = NULL; 168186681Sed alloc->num_reg_blocks = 0; 169186681Sed} 170186681Sed 171186681Seduint64_t 172186681Sedalloc_get_id(struct alloc_cache* alloc) 173197853Sed{ 174197853Sed uint64_t id = alloc->next_id++; 175197853Sed if(id == alloc->last_id) { 176197853Sed log_warn("rrset alloc: out of 64bit ids. Clearing cache."); 177197853Sed fptr_ok(fptr_whitelist_alloc_cleanup(alloc->cleanup)); 178197853Sed (*alloc->cleanup)(alloc->cleanup_arg); 179197853Sed 180197853Sed /* start back at first number */ /* like in alloc_init*/ 181197853Sed alloc->next_id = (uint64_t)alloc->thread_num; 182197853Sed alloc->next_id <<= THRNUM_SHIFT; /* in steps for comp. */ 183197853Sed alloc->next_id += 1; /* portability. */ 184197853Sed /* and generate new and safe id */ 185197853Sed id = alloc->next_id++; 186197853Sed } 187197853Sed return id; 188197853Sed} 189197853Sed 190197853Sedalloc_special_t* 191186681Sedalloc_special_obtain(struct alloc_cache* alloc) 192186681Sed{ 193186681Sed alloc_special_t* p; 194186681Sed log_assert(alloc); 195186681Sed /* see if in local cache */ 196186681Sed if(alloc->quar) { 197186681Sed p = alloc->quar; 198186681Sed alloc->quar = alloc_special_next(p); 199186681Sed alloc->num_quar--; 200186681Sed p->id = alloc_get_id(alloc); 201186681Sed return p; 202186681Sed } 203186681Sed /* see if in global cache */ 204186798Sed if(alloc->super) { 205186798Sed /* could maybe grab alloc_max/2 entries in one go, 206186798Sed * but really, isn't that just as fast as this code? */ 207187469Sed lock_quick_lock(&alloc->super->lock); 208197117Sed if((p = alloc->super->quar)) { 209197117Sed alloc->super->quar = alloc_special_next(p); 210197117Sed alloc->super->num_quar--; 211197520Sed } 212187469Sed lock_quick_unlock(&alloc->super->lock); 213187469Sed if(p) { 214197117Sed p->id = alloc_get_id(alloc); 215197117Sed return p; 216197117Sed } 217197520Sed } 218187469Sed /* allocate new */ 219186681Sed prealloc(alloc); 220186681Sed if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) { 221186681Sed log_err("alloc_special_obtain: out of memory"); 222186681Sed return NULL; 223186681Sed } 224186681Sed alloc_setup_special(p); 225186681Sed p->id = alloc_get_id(alloc); 226186681Sed return p; 227186681Sed} 228186681Sed 229186681Sed/** push mem and some more items to the super */ 230186681Sedstatic void 231186681Sedpushintosuper(struct alloc_cache* alloc, alloc_special_t* mem) 232186681Sed{ 233186681Sed int i; 234186681Sed alloc_special_t *p = alloc->quar; 235186681Sed log_assert(p); 236186681Sed log_assert(alloc && alloc->super && 237186681Sed alloc->num_quar >= ALLOC_SPECIAL_MAX); 238186681Sed /* push ALLOC_SPECIAL_MAX/2 after mem */ 239186681Sed alloc_set_special_next(mem, alloc->quar); 240186681Sed for(i=1; i<ALLOC_SPECIAL_MAX/2; i++) { 241186681Sed p = alloc_special_next(p); 242186681Sed } 243186681Sed alloc->quar = alloc_special_next(p); 244186681Sed alloc->num_quar -= ALLOC_SPECIAL_MAX/2; 245186681Sed 246186681Sed /* dump mem+list into the super quar list */ 247186681Sed lock_quick_lock(&alloc->super->lock); 248186681Sed alloc_set_special_next(p, alloc->super->quar); 249186681Sed alloc->super->quar = mem; 250186681Sed alloc->super->num_quar += ALLOC_SPECIAL_MAX/2 + 1; 251186681Sed lock_quick_unlock(&alloc->super->lock); 252186681Sed /* so 1 lock per mem+alloc/2 deletes */ 253197117Sed} 254186681Sed 255186681Sedvoid 256186681Sedalloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem) 257186681Sed{ 258186681Sed log_assert(alloc); 259186681Sed if(!mem) 260186681Sed return; 261186681Sed if(!alloc->super) { 262186681Sed lock_quick_lock(&alloc->lock); /* superalloc needs locking */ 263186681Sed } 264186681Sed 265186681Sed alloc_special_clean(mem); 266186681Sed if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) { 267186681Sed /* push it to the super structure */ 268186681Sed pushintosuper(alloc, mem); 269186681Sed return; 270186681Sed } 271186681Sed 272186681Sed alloc_set_special_next(mem, alloc->quar); 273186681Sed alloc->quar = mem; 274186681Sed alloc->num_quar++; 275194293Sed if(!alloc->super) { 276186681Sed lock_quick_unlock(&alloc->lock); 277186681Sed } 278186681Sed} 279186681Sed 280186681Sedvoid 281186681Sedalloc_stats(struct alloc_cache* alloc) 282186681Sed{ 283186681Sed log_info("%salloc: %d in cache, %d blocks.", alloc->super?"":"sup", 284186681Sed (int)alloc->num_quar, (int)alloc->num_reg_blocks); 285186681Sed} 286186681Sed 287186681Sedsize_t alloc_get_mem(struct alloc_cache* alloc) 288186681Sed{ 289186681Sed alloc_special_t* p; 290197117Sed size_t s = sizeof(*alloc); 291197117Sed if(!alloc->super) { 292197117Sed lock_quick_lock(&alloc->lock); /* superalloc needs locking */ 293197117Sed } 294197117Sed s += sizeof(alloc_special_t) * alloc->num_quar; 295197117Sed for(p = alloc->quar; p; p = alloc_special_next(p)) { 296197117Sed s += lock_get_mem(&p->entry.lock); 297186681Sed } 298186681Sed s += alloc->num_reg_blocks * ALLOC_REG_SIZE; 299186681Sed if(!alloc->super) { 300186681Sed lock_quick_unlock(&alloc->lock); 301186681Sed } 302186681Sed return s; 303186681Sed} 304186681Sed 305186681Sedstruct regional* 306186681Sedalloc_reg_obtain(struct alloc_cache* alloc) 307186681Sed{ 308188391Sed if(alloc->num_reg_blocks > 0) { 309188391Sed struct regional* r = alloc->reg_list; 310188391Sed alloc->reg_list = (struct regional*)r->next; 311188391Sed r->next = NULL; 312188391Sed alloc->num_reg_blocks--; 313188391Sed return r; 314188391Sed } 315189617Sed return regional_create_custom(ALLOC_REG_SIZE); 316189617Sed} 317189617Sed 318189617Sedvoid 319189617Sedalloc_reg_release(struct alloc_cache* alloc, struct regional* r) 320189617Sed{ 321189617Sed if(alloc->num_reg_blocks >= alloc->max_reg_blocks) { 322188391Sed regional_destroy(r); 323188391Sed return; 324188391Sed } 325188391Sed if(!r) return; 326188391Sed regional_free_all(r); 327188391Sed log_assert(r->next == NULL); 328188391Sed r->next = (char*)alloc->reg_list; 329186681Sed alloc->reg_list = r; 330186681Sed alloc->num_reg_blocks++; 331186681Sed} 332186681Sed 333186681Sedvoid 334186681Sedalloc_set_id_cleanup(struct alloc_cache* alloc, void (*cleanup)(void*), 335186681Sed void* arg) 336197117Sed{ 337197117Sed alloc->cleanup = cleanup; 338197117Sed alloc->cleanup_arg = arg; 339197117Sed} 340197117Sed 341197117Sed/** global debug value to keep track of total memory mallocs */ 342197117Sedsize_t unbound_mem_alloc = 0; 343261547Sray/** global debug value to keep track of total memory frees */ 344261551Sraysize_t unbound_mem_freed = 0; 345261547Sray#ifdef UNBOUND_ALLOC_STATS 346261547Sray/** special value to know if the memory is being tracked */ 347261547Srayuint64_t mem_special = (uint64_t)0xfeed43327766abcdLL; 348261547Sray#ifdef malloc 349261547Sray#undef malloc 350261547Sray#endif 351261547Sray/** malloc with stats */ 352261547Srayvoid *unbound_stat_malloc(size_t size) 353261547Sray{ 354261547Sray void* res; 355261547Sray if(size == 0) size = 1; 356261547Sray res = malloc(size+16); 357261547Sray if(!res) return NULL; 358186681Sed unbound_mem_alloc += size; 359186681Sed log_info("stat %p=malloc(%u)", res+16, (unsigned)size); 360186681Sed memcpy(res, &size, sizeof(size)); 361186681Sed memcpy(res+8, &mem_special, sizeof(mem_special)); 362261551Sray return res+16; 363186681Sed} 364197114Sed#ifdef calloc 365186681Sed#undef calloc 366186681Sed#endif 367197115Sed#ifndef INT_MAX 368259016Sray#define INT_MAX (((int)-1)>>1) 369259016Sray#endif 370259016Sray/** calloc with stats */ 371261551Srayvoid *unbound_stat_calloc(size_t nmemb, size_t size) 372259016Sray{ 373259016Sray size_t s; 374259016Sray void* res; 375259016Sray if(nmemb != 0 && INT_MAX/nmemb < size) 376259016Sray return NULL; /* integer overflow check */ 377197115Sed s = (nmemb*size==0)?(size_t)1:nmemb*size; 378197115Sed res = calloc(1, s+16); 379197115Sed if(!res) return NULL; 380197117Sed log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, (unsigned)size); 381197115Sed unbound_mem_alloc += s; 382197115Sed memcpy(res, &s, sizeof(s)); 383197117Sed memcpy(res+8, &mem_special, sizeof(mem_special)); 384197117Sed return res+16; 385197117Sed} 386197117Sed#ifdef free 387197117Sed#undef free 388197117Sed#endif 389197117Sed/** free with stats */ 390186681Sedvoid unbound_stat_free(void *ptr) 391186681Sed{ 392186681Sed size_t s; 393186681Sed if(!ptr) return; 394186681Sed if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) { 395186681Sed free(ptr); 396186681Sed return; 397186681Sed } 398186681Sed ptr-=16; 399186681Sed memcpy(&s, ptr, sizeof(s)); 400186681Sed log_info("stat free(%p) size %u", ptr+16, (unsigned)s); 401186681Sed memset(ptr+8, 0, 8); 402186681Sed unbound_mem_freed += s; 403186681Sed free(ptr); 404186681Sed} 405186681Sed#ifdef realloc 406186681Sed#undef realloc 407186681Sed#endif 408186681Sed/** realloc with stats */ 409186681Sedvoid *unbound_stat_realloc(void *ptr, size_t size) 410186681Sed{ 411286798Sed size_t cursz; 412186681Sed void* res; 413286798Sed if(!ptr) return unbound_stat_malloc(size); 414286798Sed if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) { 415286798Sed return realloc(ptr, size); 416286798Sed } 417286798Sed if(size==0) { 418286798Sed unbound_stat_free(ptr); 419286798Sed return NULL; 420286798Sed } 421286798Sed ptr -= 16; 422286798Sed memcpy(&cursz, ptr, sizeof(cursz)); 423286798Sed if(cursz == size) { 424186681Sed /* nothing changes */ 425186681Sed return ptr; 426186681Sed } 427186681Sed res = malloc(size+16); 428186681Sed if(!res) return NULL; 429186681Sed unbound_mem_alloc += size; 430186681Sed unbound_mem_freed += cursz; 431186681Sed log_info("stat realloc(%p, %u) from %u", ptr+16, (unsigned)size, (unsigned)cursz); 432186681Sed if(cursz > size) { 433186681Sed memcpy(res+16, ptr+16, size); 434186681Sed } else if(size > cursz) { 435186681Sed memcpy(res+16, ptr+16, cursz); 436186681Sed } 437186681Sed memset(ptr+8, 0, 8); 438186681Sed free(ptr); 439186681Sed memcpy(res, &size, sizeof(size)); 440186681Sed memcpy(res+8, &mem_special, sizeof(mem_special)); 441186681Sed return res+16; 442186681Sed} 443186681Sed 444186681Sed/** log to file where alloc was done */ 445186681Sedvoid *unbound_stat_malloc_log(size_t size, const char* file, int line, 446186681Sed const char* func) 447186681Sed{ 448186681Sed log_info("%s:%d %s malloc(%u)", file, line, func, (unsigned)size); 449186681Sed return unbound_stat_malloc(size); 450186681Sed} 451186681Sed 452197522Sed/** log to file where alloc was done */ 453197522Sedvoid *unbound_stat_calloc_log(size_t nmemb, size_t size, const char* file, 454197522Sed int line, const char* func) 455197522Sed{ 456197522Sed log_info("%s:%d %s calloc(%u, %u)", file, line, func, 457197522Sed (unsigned) nmemb, (unsigned)size); 458197522Sed return unbound_stat_calloc(nmemb, size); 459197522Sed} 460197522Sed 461197522Sed/** log to file where free was done */ 462197522Sedvoid unbound_stat_free_log(void *ptr, const char* file, int line, 463197522Sed const char* func) 464197522Sed{ 465197522Sed if(ptr && memcmp(ptr-8, &mem_special, sizeof(mem_special)) == 0) { 466197522Sed size_t s; 467197522Sed memcpy(&s, ptr-16, sizeof(s)); 468197522Sed log_info("%s:%d %s free(%p) size %u", 469197522Sed file, line, func, ptr, (unsigned)s); 470197522Sed } else 471197522Sed log_info("%s:%d %s unmatched free(%p)", file, line, func, ptr); 472197522Sed unbound_stat_free(ptr); 473197522Sed} 474197522Sed 475197522Sed/** log to file where alloc was done */ 476197522Sedvoid *unbound_stat_realloc_log(void *ptr, size_t size, const char* file, 477197522Sed int line, const char* func) 478197522Sed{ 479197522Sed log_info("%s:%d %s realloc(%p, %u)", file, line, func, 480197522Sed ptr, (unsigned)size); 481197522Sed return unbound_stat_realloc(ptr, size); 482197522Sed} 483197522Sed 484197522Sed#endif /* UNBOUND_ALLOC_STATS */ 485197522Sed#ifdef UNBOUND_ALLOC_LITE 486197522Sed#undef malloc 487197522Sed#undef calloc 488197522Sed#undef free 489197522Sed#undef realloc 490197522Sed/** length of prefix and suffix */ 491197522Sedstatic size_t lite_pad = 16; 492197522Sed/** prefix value to check */ 493197522Sedstatic char* lite_pre = "checkfront123456"; 494197522Sed/** suffix value to check */ 495197522Sedstatic char* lite_post= "checkafter123456"; 496197522Sed 497197522Sedvoid *unbound_stat_malloc_lite(size_t size, const char* file, int line, 498197522Sed const char* func) 499197522Sed{ 500197522Sed /* [prefix .. len .. actual data .. suffix] */ 501197522Sed void* res = malloc(size+lite_pad*2+sizeof(size_t)); 502197522Sed if(!res) return NULL; 503199171Sed memmove(res, lite_pre, lite_pad); 504199171Sed memmove(res+lite_pad, &size, sizeof(size_t)); 505199171Sed memset(res+lite_pad+sizeof(size_t), 0x1a, size); /* init the memory */ 506199171Sed memmove(res+lite_pad+size+sizeof(size_t), lite_post, lite_pad); 507199175Sed return res+lite_pad+sizeof(size_t); 508199171Sed} 509199171Sed 510199171Sedvoid *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file, 511199171Sed int line, const char* func) 512199171Sed{ 513199171Sed size_t req; 514199171Sed void* res; 515199171Sed if(nmemb != 0 && INT_MAX/nmemb < size) 516199171Sed return NULL; /* integer overflow check */ 517199171Sed req = nmemb * size; 518199171Sed res = malloc(req+lite_pad*2+sizeof(size_t)); 519199171Sed if(!res) return NULL; 520199171Sed memmove(res, lite_pre, lite_pad); 521199171Sed memmove(res+lite_pad, &req, sizeof(size_t)); 522199171Sed memset(res+lite_pad+sizeof(size_t), 0, req); 523199171Sed memmove(res+lite_pad+req+sizeof(size_t), lite_post, lite_pad); 524199171Sed return res+lite_pad+sizeof(size_t); 525199171Sed} 526199171Sed 527199171Sedvoid unbound_stat_free_lite(void *ptr, const char* file, int line, 528199171Sed const char* func) 529199171Sed{ 530199175Sed void* real; 531199171Sed size_t orig = 0; 532199171Sed if(!ptr) return; 533199171Sed real = ptr-lite_pad-sizeof(size_t); 534199171Sed if(memcmp(real, lite_pre, lite_pad) != 0) { 535199171Sed log_err("free(): prefix failed %s:%d %s", file, line, func); 536199171Sed log_hex("prefix here", real, lite_pad); 537199171Sed log_hex(" should be", lite_pre, lite_pad); 538199171Sed fatal_exit("alloc assertion failed"); 539199171Sed } 540199171Sed memmove(&orig, real+lite_pad, sizeof(size_t)); 541199171Sed if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){ 542199171Sed log_err("free(): suffix failed %s:%d %s", file, line, func); 543199171Sed log_err("alloc size is %d", (int)orig); 544199171Sed log_hex("suffix here", real+lite_pad+orig+sizeof(size_t), 545199171Sed lite_pad); 546199171Sed log_hex(" should be", lite_post, lite_pad); 547199171Sed fatal_exit("alloc assertion failed"); 548199171Sed } 549199171Sed memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */ 550199171Sed free(real); 551199171Sed} 552199171Sed 553199171Sedvoid *unbound_stat_realloc_lite(void *ptr, size_t size, const char* file, 554199171Sed int line, const char* func) 555199171Sed{ 556199171Sed /* always free and realloc (no growing) */ 557199171Sed void* real, *newa; 558199171Sed size_t orig = 0; 559223574Sed if(!ptr) { 560199171Sed /* like malloc() */ 561199171Sed return unbound_stat_malloc_lite(size, file, line, func); 562199171Sed } 563186681Sed if(!size) { 564 /* like free() */ 565 unbound_stat_free_lite(ptr, file, line, func); 566 return NULL; 567 } 568 /* change allocation size and copy */ 569 real = ptr-lite_pad-sizeof(size_t); 570 if(memcmp(real, lite_pre, lite_pad) != 0) { 571 log_err("realloc(): prefix failed %s:%d %s", file, line, func); 572 log_hex("prefix here", real, lite_pad); 573 log_hex(" should be", lite_pre, lite_pad); 574 fatal_exit("alloc assertion failed"); 575 } 576 memmove(&orig, real+lite_pad, sizeof(size_t)); 577 if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){ 578 log_err("realloc(): suffix failed %s:%d %s", file, line, func); 579 log_err("alloc size is %d", (int)orig); 580 log_hex("suffix here", real+lite_pad+orig+sizeof(size_t), 581 lite_pad); 582 log_hex(" should be", lite_post, lite_pad); 583 fatal_exit("alloc assertion failed"); 584 } 585 /* new alloc and copy over */ 586 newa = unbound_stat_malloc_lite(size, file, line, func); 587 if(!newa) 588 return NULL; 589 if(orig < size) 590 memmove(newa, ptr, orig); 591 else memmove(newa, ptr, size); 592 memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */ 593 free(real); 594 return newa; 595} 596 597char* unbound_strdup_lite(const char* s, const char* file, int line, 598 const char* func) 599{ 600 /* this routine is made to make sure strdup() uses the malloc_lite */ 601 size_t l = strlen(s)+1; 602 char* n = (char*)unbound_stat_malloc_lite(l, file, line, func); 603 if(!n) return NULL; 604 memmove(n, s, l); 605 return n; 606} 607 608char* unbound_lite_wrapstr(char* s) 609{ 610 char* n = unbound_strdup_lite(s, __FILE__, __LINE__, __func__); 611 free(s); 612 return n; 613} 614 615#undef sldns_pkt2wire 616sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p, 617 size_t *size) 618{ 619 uint8_t* md = NULL; 620 size_t ms = 0; 621 sldns_status s = sldns_pkt2wire(&md, p, &ms); 622 if(md) { 623 *dest = unbound_stat_malloc_lite(ms, __FILE__, __LINE__, 624 __func__); 625 *size = ms; 626 if(!*dest) { free(md); return LDNS_STATUS_MEM_ERR; } 627 memcpy(*dest, md, ms); 628 free(md); 629 } else { 630 *dest = NULL; 631 *size = 0; 632 } 633 return s; 634} 635 636#undef i2d_DSA_SIG 637int unbound_lite_i2d_DSA_SIG(DSA_SIG* dsasig, unsigned char** sig) 638{ 639 unsigned char* n = NULL; 640 int r= i2d_DSA_SIG(dsasig, &n); 641 if(n) { 642 *sig = unbound_stat_malloc_lite((size_t)r, __FILE__, __LINE__, 643 __func__); 644 if(!*sig) return -1; 645 memcpy(*sig, n, (size_t)r); 646 free(n); 647 return r; 648 } 649 *sig = NULL; 650 return r; 651} 652 653#endif /* UNBOUND_ALLOC_LITE */ 654