1 /* $NetBSD: alloc.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $ */ 2 /* alloc.c 3 4 Functions supporting memory allocation for the object management 5 protocol... */ 6 7 /* 8 * Copyright (c) 2012,2014 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC") 10 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") 11 * Copyright (c) 1999-2003 by Internet Software Consortium 12 * 13 * Permission to use, copy, modify, and distribute this software for any 14 * purpose with or without fee is hereby granted, provided that the above 15 * copyright notice and this permission notice appear in all copies. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 18 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 20 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 23 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 * 25 * Internet Systems Consortium, Inc. 26 * 950 Charter Street 27 * Redwood City, CA 94063 28 * <info@isc.org> 29 * https://www.isc.org/ 30 * 31 */ 32 33 #include <sys/cdefs.h> 34 __RCSID("$NetBSD: alloc.c,v 1.1.1.3 2014/07/12 11:57:58 spz Exp $"); 35 36 #include "dhcpd.h" 37 38 #include <omapip/omapip_p.h> 39 40 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 41 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 42 struct dmalloc_preamble *dmalloc_list; 43 unsigned long dmalloc_outstanding; 44 unsigned long dmalloc_longterm; 45 unsigned long dmalloc_generation; 46 unsigned long dmalloc_cutoff_generation; 47 #endif 48 49 #if defined (DEBUG_RC_HISTORY) 50 struct rc_history_entry rc_history [RC_HISTORY_MAX]; 51 int rc_history_index; 52 int rc_history_count; 53 #endif 54 55 #if defined (DEBUG_RC_HISTORY) 56 static void print_rc_hist_entry (int); 57 #endif 58 59 void * 60 dmalloc(unsigned size, const char *file, int line) { 61 unsigned char *foo; 62 unsigned len; 63 void **bar; 64 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 65 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 66 int i; 67 struct dmalloc_preamble *dp; 68 #endif 69 70 len = size + DMDSIZE; 71 if (len < size) 72 return NULL; 73 74 foo = malloc(len); 75 76 if (!foo) 77 return NULL; 78 bar = (void *)(foo + DMDOFFSET); 79 memset (bar, 0, size); 80 81 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 82 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 83 dp = (struct dmalloc_preamble *)foo; 84 dp -> prev = dmalloc_list; 85 if (dmalloc_list) 86 dmalloc_list -> next = dp; 87 dmalloc_list = dp; 88 dp -> next = (struct dmalloc_preamble *)0; 89 dp -> size = size; 90 dp -> file = file; 91 dp -> line = line; 92 dp -> generation = dmalloc_generation++; 93 dmalloc_outstanding += size; 94 for (i = 0; i < DMLFSIZE; i++) 95 dp -> low_fence [i] = 96 (((unsigned long) 97 (&dp -> low_fence [i])) % 143) + 113; 98 for (i = DMDOFFSET; i < DMDSIZE; i++) 99 foo [i + size] = 100 (((unsigned long) 101 (&foo [i + size])) % 143) + 113; 102 #if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY) 103 /* Check _every_ entry in the pool! Very expensive. */ 104 for (dp = dmalloc_list; dp; dp = dp -> prev) { 105 for (i = 0; i < DMLFSIZE; i++) { 106 if (dp -> low_fence [i] != 107 (((unsigned long) 108 (&dp -> low_fence [i])) % 143) + 113) 109 { 110 log_error ("malloc fence modified: %s(%d)", 111 dp -> file, dp -> line); 112 abort (); 113 } 114 } 115 foo = (unsigned char *)dp; 116 for (i = DMDOFFSET; i < DMDSIZE; i++) { 117 if (foo [i + dp -> size] != 118 (((unsigned long) 119 (&foo [i + dp -> size])) % 143) + 113) { 120 log_error ("malloc fence modified: %s(%d)", 121 dp -> file, dp -> line); 122 abort (); 123 } 124 } 125 } 126 #endif 127 #endif 128 #ifdef DEBUG_REFCNT_DMALLOC_FREE 129 rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC); 130 #endif 131 return bar; 132 } 133 134 void 135 dfree(void *ptr, const char *file, int line) { 136 if (!ptr) { 137 log_error ("dfree %s(%d): free on null pointer.", file, line); 138 return; 139 } 140 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 141 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 142 { 143 unsigned char *bar = ptr; 144 struct dmalloc_preamble *dp, *cur; 145 int i; 146 bar -= DMDOFFSET; 147 cur = (struct dmalloc_preamble *)bar; 148 for (dp = dmalloc_list; dp; dp = dp -> prev) 149 if (dp == cur) 150 break; 151 if (!dp) { 152 log_error ("%s(%d): freeing unknown memory: %lx", 153 file, line, (unsigned long)cur); 154 abort (); 155 } 156 if (dp -> prev) 157 dp -> prev -> next = dp -> next; 158 if (dp -> next) 159 dp -> next -> prev = dp -> prev; 160 if (dp == dmalloc_list) 161 dmalloc_list = dp -> prev; 162 if (dp -> generation >= dmalloc_cutoff_generation) 163 dmalloc_outstanding -= dp -> size; 164 else 165 dmalloc_longterm -= dp -> size; 166 167 for (i = 0; i < DMLFSIZE; i++) { 168 if (dp -> low_fence [i] != 169 (((unsigned long) 170 (&dp -> low_fence [i])) % 143) + 113) 171 { 172 log_error ("malloc fence modified: %s(%d)", 173 dp -> file, dp -> line); 174 abort (); 175 } 176 } 177 for (i = DMDOFFSET; i < DMDSIZE; i++) { 178 if (bar [i + dp -> size] != 179 (((unsigned long) 180 (&bar [i + dp -> size])) % 143) + 113) { 181 log_error ("malloc fence modified: %s(%d)", 182 dp -> file, dp -> line); 183 abort (); 184 } 185 } 186 ptr = bar; 187 } 188 #endif 189 #ifdef DEBUG_REFCNT_DMALLOC_FREE 190 rc_register (file, line, 191 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC); 192 #endif 193 free (ptr); 194 } 195 196 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 197 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 198 /* For allocation functions that keep their own free lists, we want to 199 account for the reuse of the memory. */ 200 201 void 202 dmalloc_reuse(void *foo, const char *file, int line, int justref) { 203 struct dmalloc_preamble *dp; 204 205 /* Get the pointer to the dmalloc header. */ 206 dp = foo; 207 dp--; 208 209 /* If we just allocated this and are now referencing it, this 210 function would almost be a no-op, except that it would 211 increment the generation count needlessly. So just return 212 in this case. */ 213 if (dp -> generation == dmalloc_generation) 214 return; 215 216 /* If this is longterm data, and we just made reference to it, 217 don't put it on the short-term list or change its name - 218 we don't need to know about this. */ 219 if (dp -> generation < dmalloc_cutoff_generation && justref) 220 return; 221 222 /* Take it out of the place in the allocated list where it was. */ 223 if (dp -> prev) 224 dp -> prev -> next = dp -> next; 225 if (dp -> next) 226 dp -> next -> prev = dp -> prev; 227 if (dp == dmalloc_list) 228 dmalloc_list = dp -> prev; 229 230 /* Account for its removal. */ 231 if (dp -> generation >= dmalloc_cutoff_generation) 232 dmalloc_outstanding -= dp -> size; 233 else 234 dmalloc_longterm -= dp -> size; 235 236 /* Now put it at the head of the list. */ 237 dp -> prev = dmalloc_list; 238 if (dmalloc_list) 239 dmalloc_list -> next = dp; 240 dmalloc_list = dp; 241 dp -> next = (struct dmalloc_preamble *)0; 242 243 /* Change the reference location information. */ 244 dp -> file = file; 245 dp -> line = line; 246 247 /* Increment the generation. */ 248 dp -> generation = dmalloc_generation++; 249 250 /* Account for it. */ 251 dmalloc_outstanding += dp -> size; 252 } 253 254 void dmalloc_dump_outstanding () 255 { 256 static unsigned long dmalloc_cutoff_point; 257 struct dmalloc_preamble *dp; 258 #if defined(DEBUG_MALLOC_POOL) 259 unsigned char *foo; 260 int i; 261 #endif 262 263 if (!dmalloc_cutoff_point) 264 dmalloc_cutoff_point = dmalloc_cutoff_generation; 265 for (dp = dmalloc_list; dp; dp = dp -> prev) { 266 if (dp -> generation <= dmalloc_cutoff_point) 267 break; 268 #if defined (DEBUG_MALLOC_POOL) 269 for (i = 0; i < DMLFSIZE; i++) { 270 if (dp -> low_fence [i] != 271 (((unsigned long) 272 (&dp -> low_fence [i])) % 143) + 113) 273 { 274 log_error ("malloc fence modified: %s(%d)", 275 dp -> file, dp -> line); 276 abort (); 277 } 278 } 279 foo = (unsigned char *)dp; 280 for (i = DMDOFFSET; i < DMDSIZE; i++) { 281 if (foo [i + dp -> size] != 282 (((unsigned long) 283 (&foo [i + dp -> size])) % 143) + 113) { 284 log_error ("malloc fence modified: %s(%d)", 285 dp -> file, dp -> line); 286 abort (); 287 } 288 } 289 #endif 290 #if defined (DEBUG_MEMORY_LEAKAGE) || \ 291 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 292 /* Don't count data that's actually on a free list 293 somewhere. */ 294 if (dp -> file) { 295 #if defined (DEBUG_RC_HISTORY) 296 int i, count, inhistory = 0, noted = 0; 297 298 /* If we have the info, see if this is actually 299 new garbage. */ 300 if (rc_history_count < RC_HISTORY_MAX) { 301 count = rc_history_count; 302 } else 303 count = RC_HISTORY_MAX; 304 i = rc_history_index - 1; 305 if (i < 0) 306 i += RC_HISTORY_MAX; 307 308 do { 309 if (rc_history [i].addr == dp + 1) { 310 inhistory = 1; 311 if (!noted) { 312 log_info (" %s(%d): %ld", dp -> file, 313 dp -> line, (long) dp -> size); 314 noted = 1; 315 } 316 print_rc_hist_entry (i); 317 if (!rc_history [i].refcnt) 318 break; 319 } 320 if (--i < 0) 321 i = RC_HISTORY_MAX - 1; 322 } while (count--); 323 if (!inhistory) 324 #endif 325 log_info (" %s(%d): %ld", 326 dp -> file, dp -> line, 327 (long) dp -> size); 328 } 329 #endif 330 } 331 if (dmalloc_list) 332 dmalloc_cutoff_point = dmalloc_list -> generation; 333 } 334 #endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ 335 336 #if defined (DEBUG_RC_HISTORY) 337 static void print_rc_hist_entry (int i) 338 { 339 log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x", 340 rc_history [i].file, rc_history [i].line, 341 (unsigned long)rc_history [i].reference, 342 (unsigned long)rc_history [i].addr, 343 rc_history [i].refcnt); 344 } 345 346 void dump_rc_history (void *addr) 347 { 348 int i; 349 350 i = rc_history_index; 351 if (!rc_history [i].file) 352 i = 0; 353 else if (rc_history_count < RC_HISTORY_MAX) { 354 i -= rc_history_count; 355 if (i < 0) 356 i += RC_HISTORY_MAX; 357 } 358 rc_history_count = 0; 359 360 while (rc_history [i].file) { 361 if (!addr || addr == rc_history [i].addr) 362 print_rc_hist_entry (i); 363 ++i; 364 if (i == RC_HISTORY_MAX) 365 i = 0; 366 if (i == rc_history_index) 367 break; 368 } 369 } 370 void rc_history_next (int d) 371 { 372 #if defined (RC_HISTORY_COMPRESSION) 373 int i, j = 0, m, n = 0; 374 void *ap, *rp; 375 376 /* If we are decreasing the reference count, try to find the 377 entry where the reference was made and eliminate it; then 378 we can also eliminate this reference. */ 379 if (d) { 380 m = rc_history_index - 1000; 381 if (m < -1) 382 m = -1; 383 ap = rc_history [rc_history_index].addr; 384 rp = rc_history [rc_history_index].reference; 385 for (i = rc_history_index - 1; i > m; i--) { 386 if (rc_history [i].addr == ap) { 387 if (rc_history [i].reference == rp) { 388 if (n > 10) { 389 for (n = i; n <= rc_history_index; n++) 390 print_rc_hist_entry (n); 391 n = 11; 392 } 393 memmove (&rc_history [i], 394 &rc_history [i + 1], 395 (unsigned)((rc_history_index - i) * 396 sizeof (struct rc_history_entry))); 397 --rc_history_count; 398 --rc_history_index; 399 for (j = i; j < rc_history_count; j++) { 400 if (rc_history [j].addr == ap) 401 --rc_history [j].refcnt; 402 } 403 if (n > 10) { 404 for (n = i; n <= rc_history_index; n++) 405 print_rc_hist_entry (n); 406 n = 11; 407 exit (0); 408 } 409 return; 410 } 411 } 412 } 413 } 414 #endif 415 if (++rc_history_index == RC_HISTORY_MAX) 416 rc_history_index = 0; 417 ++rc_history_count; 418 } 419 #endif /* DEBUG_RC_HISTORY */ 420 421 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 422 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 423 struct caller { 424 struct dmalloc_preamble *dp; 425 int count; 426 }; 427 428 static int dmalloc_find_entry (struct dmalloc_preamble *dp, 429 struct caller *array, 430 int min, int max) 431 { 432 int middle; 433 434 middle = (min + max) / 2; 435 if (middle == min) 436 return middle; 437 if (array [middle].dp -> file == dp -> file) { 438 if (array [middle].dp -> line == dp -> line) 439 return middle; 440 else if (array [middle].dp -> line < dp -> line) 441 return dmalloc_find_entry (dp, array, middle, max); 442 else 443 return dmalloc_find_entry (dp, array, 0, middle); 444 } else if (array [middle].dp -> file < dp -> file) 445 return dmalloc_find_entry (dp, array, middle, max); 446 else 447 return dmalloc_find_entry (dp, array, 0, middle); 448 } 449 450 void omapi_print_dmalloc_usage_by_caller () 451 { 452 struct dmalloc_preamble *dp; 453 int ccur, cmax, i; 454 struct caller cp [1024]; 455 456 cmax = 1024; 457 ccur = 0; 458 459 memset (cp, 0, sizeof cp); 460 for (dp = dmalloc_list; dp; dp = dp -> prev) { 461 i = dmalloc_find_entry (dp, cp, 0, ccur); 462 if ((i == ccur || 463 cp [i].dp -> file != dp -> file || 464 cp [i].dp -> line != dp -> line) && 465 ccur == cmax) { 466 log_error ("no space for memory usage summary."); 467 return; 468 } 469 if (i == ccur) { 470 cp [ccur++].dp = dp; 471 cp [i].count = 1; 472 } else if (cp [i].dp -> file < dp -> file || 473 (cp [i].dp -> file == dp -> file && 474 cp [i].dp -> line < dp -> line)) { 475 if (i + 1 != ccur) 476 memmove (cp + i + 2, cp + i + 1, 477 (ccur - i) * sizeof *cp); 478 cp [i + 1].dp = dp; 479 cp [i + 1].count = 1; 480 ccur++; 481 } else if (cp [i].dp -> file != dp -> file || 482 cp [i].dp -> line != dp -> line) { 483 memmove (cp + i + 1, 484 cp + i, (ccur - i) * sizeof *cp); 485 cp [i].dp = dp; 486 cp [i].count = 1; 487 ccur++; 488 } else 489 cp [i].count++; 490 #if 0 491 printf ("%d\t%s:%d\n", i, dp -> file, dp -> line); 492 dump_rc_history (dp + 1); 493 #endif 494 } 495 for (i = 0; i < ccur; i++) { 496 printf ("%d\t%s:%d\t%d\n", i, 497 cp [i].dp -> file, cp [i].dp -> line, cp [i].count); 498 #if defined(DUMP_RC_HISTORY) 499 dump_rc_history (cp [i].dp + 1); 500 #endif 501 } 502 } 503 #endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */ 504 505 isc_result_t omapi_object_allocate (omapi_object_t **o, 506 omapi_object_type_t *type, 507 size_t size, 508 const char *file, int line) 509 { 510 size_t tsize; 511 omapi_object_t *foo; 512 isc_result_t status; 513 514 if (type -> allocator) { 515 foo = (omapi_object_t *)0; 516 status = (*type -> allocator) (&foo, file, line); 517 tsize = type -> size; 518 } else { 519 status = ISC_R_NOMEMORY; 520 tsize = 0; 521 } 522 523 if (status == ISC_R_NOMEMORY) { 524 if (type -> sizer) 525 tsize = (*type -> sizer) (size); 526 else 527 tsize = type -> size; 528 529 /* Sanity check. */ 530 if (tsize < sizeof (omapi_object_t)) 531 return DHCP_R_INVALIDARG; 532 533 foo = dmalloc (tsize, file, line); 534 if (!foo) 535 return ISC_R_NOMEMORY; 536 } 537 538 status = omapi_object_initialize (foo, type, size, tsize, file, line); 539 if (status != ISC_R_SUCCESS) { 540 if (type -> freer) 541 (*type -> freer) (foo, file, line); 542 else 543 dfree (foo, file, line); 544 return status; 545 } 546 return omapi_object_reference (o, foo, file, line); 547 } 548 549 isc_result_t omapi_object_initialize (omapi_object_t *o, 550 omapi_object_type_t *type, 551 size_t usize, size_t psize, 552 const char *file, int line) 553 { 554 memset (o, 0, psize); 555 o -> type = type; 556 if (type -> initialize) 557 (*type -> initialize) (o, file, line); 558 return ISC_R_SUCCESS; 559 } 560 561 isc_result_t omapi_object_reference (omapi_object_t **r, 562 omapi_object_t *h, 563 const char *file, int line) 564 { 565 if (!h || !r) 566 return DHCP_R_INVALIDARG; 567 568 if (*r) { 569 #if defined (POINTER_DEBUG) 570 log_error ("%s(%d): reference store into non-null pointer!", 571 file, line); 572 abort (); 573 #else 574 return DHCP_R_INVALIDARG; 575 #endif 576 } 577 *r = h; 578 h -> refcnt++; 579 rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag); 580 return ISC_R_SUCCESS; 581 } 582 583 isc_result_t omapi_object_dereference (omapi_object_t **h, 584 const char *file, int line) 585 { 586 int outer_reference = 0; 587 int inner_reference = 0; 588 int handle_reference = 0; 589 int extra_references; 590 omapi_object_t *p, *hp; 591 592 if (!h) 593 return DHCP_R_INVALIDARG; 594 595 if (!*h) { 596 #if defined (POINTER_DEBUG) 597 log_error ("%s(%d): dereference of null pointer!", file, line); 598 abort (); 599 #else 600 return DHCP_R_INVALIDARG; 601 #endif 602 } 603 604 if ((*h) -> refcnt <= 0) { 605 #if defined (POINTER_DEBUG) 606 log_error ("%s(%d): dereference of pointer with refcnt of zero!", 607 file, line); 608 #if defined (DEBUG_RC_HISTORY) 609 dump_rc_history (*h); 610 #endif 611 abort (); 612 #else 613 *h = 0; 614 return DHCP_R_INVALIDARG; 615 #endif 616 } 617 618 /* See if this object's inner object refers to it, but don't 619 count this as a reference if we're being asked to free the 620 reference from the inner object. */ 621 if ((*h) -> inner && (*h) -> inner -> outer && 622 h != &((*h) -> inner -> outer)) 623 inner_reference = 1; 624 625 /* Ditto for the outer object. */ 626 if ((*h) -> outer && (*h) -> outer -> inner && 627 h != &((*h) -> outer -> inner)) 628 outer_reference = 1; 629 630 /* Ditto for the outer object. The code below assumes that 631 the only reason we'd get a dereference from the handle 632 table is if this function does it - otherwise we'd have to 633 traverse the handle table to find the address where the 634 reference is stored and compare against that, and we don't 635 want to do that if we can avoid it. */ 636 if ((*h) -> handle) 637 handle_reference = 1; 638 639 /* If we are getting rid of the last reference other than 640 references to inner and outer objects, or from the handle 641 table, then we must examine all the objects in either 642 direction to see if they hold any non-inner, non-outer, 643 non-handle-table references. If not, we need to free the 644 entire chain of objects. */ 645 if ((*h) -> refcnt == 646 inner_reference + outer_reference + handle_reference + 1) { 647 if (inner_reference || outer_reference || handle_reference) { 648 /* XXX we could check for a reference from the 649 handle table here. */ 650 extra_references = 0; 651 for (p = (*h) -> inner; 652 p && !extra_references; p = p -> inner) { 653 extra_references += p -> refcnt; 654 if (p -> inner && p -> inner -> outer == p) 655 --extra_references; 656 if (p -> outer) 657 --extra_references; 658 if (p -> handle) 659 --extra_references; 660 } 661 for (p = (*h) -> outer; 662 p && !extra_references; p = p -> outer) { 663 extra_references += p -> refcnt; 664 if (p -> outer && p -> outer -> inner == p) 665 --extra_references; 666 if (p -> inner) 667 --extra_references; 668 if (p -> handle) 669 --extra_references; 670 } 671 } else 672 extra_references = 0; 673 674 if (!extra_references) { 675 hp = *h; 676 *h = 0; 677 hp -> refcnt--; 678 if (inner_reference) 679 omapi_object_dereference 680 (&hp -> inner, file, line); 681 if (outer_reference) 682 omapi_object_dereference 683 (&hp -> outer, file, line); 684 /* if (!hp -> type -> freer) */ 685 rc_register (file, line, h, hp, 686 0, 1, hp -> type -> rc_flag); 687 if (handle_reference) { 688 if (omapi_handle_clear(hp->handle) != 689 ISC_R_SUCCESS) { 690 log_debug("Attempt to clear null " 691 "handle pointer"); 692 } 693 } 694 if (hp -> type -> destroy) 695 (*(hp -> type -> destroy)) (hp, file, line); 696 if (hp -> type -> freer) 697 (hp -> type -> freer (hp, file, line)); 698 else 699 dfree (hp, file, line); 700 } else { 701 (*h) -> refcnt--; 702 /* if (!(*h) -> type -> freer) */ 703 rc_register (file, line, 704 h, *h, (*h) -> refcnt, 1, 705 (*h) -> type -> rc_flag); 706 } 707 } else { 708 (*h) -> refcnt--; 709 /* if (!(*h) -> type -> freer) */ 710 rc_register (file, line, h, *h, (*h) -> refcnt, 1, 711 (*h) -> type -> rc_flag); 712 } 713 *h = 0; 714 return ISC_R_SUCCESS; 715 } 716 717 isc_result_t omapi_buffer_new (omapi_buffer_t **h, 718 const char *file, int line) 719 { 720 omapi_buffer_t *t; 721 isc_result_t status; 722 723 t = (omapi_buffer_t *)dmalloc (sizeof *t, file, line); 724 if (!t) 725 return ISC_R_NOMEMORY; 726 memset (t, 0, sizeof *t); 727 status = omapi_buffer_reference (h, t, file, line); 728 if (status != ISC_R_SUCCESS) 729 dfree (t, file, line); 730 (*h) -> head = sizeof ((*h) -> buf) - 1; 731 return status; 732 } 733 734 isc_result_t omapi_buffer_reference (omapi_buffer_t **r, 735 omapi_buffer_t *h, 736 const char *file, int line) 737 { 738 if (!h || !r) 739 return DHCP_R_INVALIDARG; 740 741 if (*r) { 742 #if defined (POINTER_DEBUG) 743 log_error ("%s(%d): reference store into non-null pointer!", 744 file, line); 745 abort (); 746 #else 747 return DHCP_R_INVALIDARG; 748 #endif 749 } 750 *r = h; 751 h -> refcnt++; 752 rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); 753 return ISC_R_SUCCESS; 754 } 755 756 isc_result_t omapi_buffer_dereference (omapi_buffer_t **h, 757 const char *file, int line) 758 { 759 if (!h) 760 return DHCP_R_INVALIDARG; 761 762 if (!*h) { 763 #if defined (POINTER_DEBUG) 764 log_error ("%s(%d): dereference of null pointer!", file, line); 765 abort (); 766 #else 767 return DHCP_R_INVALIDARG; 768 #endif 769 } 770 771 if ((*h) -> refcnt <= 0) { 772 #if defined (POINTER_DEBUG) 773 log_error ("%s(%d): dereference of pointer with refcnt of zero!", 774 file, line); 775 #if defined (DEBUG_RC_HISTORY) 776 dump_rc_history (*h); 777 #endif 778 abort (); 779 #else 780 *h = 0; 781 return DHCP_R_INVALIDARG; 782 #endif 783 } 784 785 --(*h) -> refcnt; 786 rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); 787 if ((*h) -> refcnt == 0) 788 dfree (*h, file, line); 789 *h = 0; 790 return ISC_R_SUCCESS; 791 } 792 793 isc_result_t omapi_typed_data_new (const char *file, int line, 794 omapi_typed_data_t **t, 795 omapi_datatype_t type, ...) 796 { 797 va_list l; 798 omapi_typed_data_t *new; 799 unsigned len; 800 unsigned val = 0; 801 int intval = 0; 802 char *s = NULL; 803 isc_result_t status; 804 omapi_object_t *obj = NULL; 805 806 va_start (l, type); 807 808 switch (type) { 809 case omapi_datatype_int: 810 len = OMAPI_TYPED_DATA_INT_LEN; 811 intval = va_arg (l, int); 812 break; 813 case omapi_datatype_string: 814 s = va_arg (l, char *); 815 val = strlen (s); 816 len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; 817 if (len < val) { 818 va_end(l); 819 return DHCP_R_INVALIDARG; 820 } 821 break; 822 case omapi_datatype_data: 823 val = va_arg (l, unsigned); 824 len = OMAPI_TYPED_DATA_NOBUFFER_LEN + val; 825 if (len < val) { 826 va_end(l); 827 return DHCP_R_INVALIDARG; 828 } 829 break; 830 case omapi_datatype_object: 831 len = OMAPI_TYPED_DATA_OBJECT_LEN; 832 obj = va_arg (l, omapi_object_t *); 833 break; 834 default: 835 va_end (l); 836 return DHCP_R_INVALIDARG; 837 } 838 va_end (l); 839 840 new = dmalloc (len, file, line); 841 if (!new) 842 return ISC_R_NOMEMORY; 843 memset (new, 0, len); 844 845 switch (type) { 846 case omapi_datatype_int: 847 new -> u.integer = intval; 848 break; 849 case omapi_datatype_string: 850 memcpy (new -> u.buffer.value, s, val); 851 new -> u.buffer.len = val; 852 break; 853 case omapi_datatype_data: 854 new -> u.buffer.len = val; 855 break; 856 case omapi_datatype_object: 857 status = omapi_object_reference (&new -> u.object, obj, 858 file, line); 859 if (status != ISC_R_SUCCESS) { 860 dfree (new, file, line); 861 return status; 862 } 863 break; 864 } 865 new -> type = type; 866 867 return omapi_typed_data_reference (t, new, file, line); 868 } 869 870 isc_result_t omapi_typed_data_reference (omapi_typed_data_t **r, 871 omapi_typed_data_t *h, 872 const char *file, int line) 873 { 874 if (!h || !r) 875 return DHCP_R_INVALIDARG; 876 877 if (*r) { 878 #if defined (POINTER_DEBUG) 879 log_error ("%s(%d): reference store into non-null pointer!", file, line); 880 abort (); 881 #else 882 return DHCP_R_INVALIDARG; 883 #endif 884 } 885 *r = h; 886 h -> refcnt++; 887 rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); 888 return ISC_R_SUCCESS; 889 } 890 891 isc_result_t omapi_typed_data_dereference (omapi_typed_data_t **h, 892 const char *file, int line) 893 { 894 if (!h) 895 return DHCP_R_INVALIDARG; 896 897 if (!*h) { 898 #if defined (POINTER_DEBUG) 899 log_error ("%s(%d): dereference of null pointer!", file, line); 900 abort (); 901 #else 902 return DHCP_R_INVALIDARG; 903 #endif 904 } 905 906 if ((*h) -> refcnt <= 0) { 907 #if defined (POINTER_DEBUG) 908 log_error ("%s(%d): dereference of pointer with refcnt of zero!", 909 file, line); 910 #if defined (DEBUG_RC_HISTORY) 911 dump_rc_history (*h); 912 #endif 913 abort (); 914 #else 915 *h = 0; 916 return DHCP_R_INVALIDARG; 917 #endif 918 } 919 920 --((*h) -> refcnt); 921 rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); 922 if ((*h) -> refcnt <= 0 ) { 923 switch ((*h) -> type) { 924 case omapi_datatype_int: 925 case omapi_datatype_string: 926 case omapi_datatype_data: 927 default: 928 break; 929 case omapi_datatype_object: 930 omapi_object_dereference (&(*h) -> u.object, 931 file, line); 932 break; 933 } 934 dfree (*h, file, line); 935 } 936 *h = 0; 937 return ISC_R_SUCCESS; 938 } 939 940 isc_result_t omapi_data_string_new (omapi_data_string_t **d, unsigned len, 941 const char *file, int line) 942 { 943 omapi_data_string_t *new; 944 unsigned nlen; 945 946 nlen = OMAPI_DATA_STRING_EMPTY_SIZE + len; 947 if (nlen < len) 948 return DHCP_R_INVALIDARG; 949 new = dmalloc (nlen, file, line); 950 if (!new) 951 return ISC_R_NOMEMORY; 952 memset (new, 0, OMAPI_DATA_STRING_EMPTY_SIZE); 953 new -> len = len; 954 return omapi_data_string_reference (d, new, file, line); 955 } 956 957 isc_result_t omapi_data_string_reference (omapi_data_string_t **r, 958 omapi_data_string_t *h, 959 const char *file, int line) 960 { 961 if (!h || !r) 962 return DHCP_R_INVALIDARG; 963 964 if (*r) { 965 #if defined (POINTER_DEBUG) 966 log_error ("%s(%d): reference store into non-null pointer!", file, line); 967 abort (); 968 #else 969 return DHCP_R_INVALIDARG; 970 #endif 971 } 972 *r = h; 973 h -> refcnt++; 974 rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); 975 return ISC_R_SUCCESS; 976 } 977 978 isc_result_t omapi_data_string_dereference (omapi_data_string_t **h, 979 const char *file, int line) 980 { 981 if (!h) 982 return DHCP_R_INVALIDARG; 983 984 if (!*h) { 985 #if defined (POINTER_DEBUG) 986 log_error ("%s(%d): dereference of null pointer!", file, line); 987 abort (); 988 #else 989 return DHCP_R_INVALIDARG; 990 #endif 991 } 992 993 if ((*h) -> refcnt <= 0) { 994 #if defined (POINTER_DEBUG) 995 log_error ("%s(%d): dereference of pointer with refcnt of zero!", 996 file, line); 997 #if defined (DEBUG_RC_HISTORY) 998 dump_rc_history (*h); 999 #endif 1000 abort (); 1001 #else 1002 *h = 0; 1003 return DHCP_R_INVALIDARG; 1004 #endif 1005 } 1006 1007 --((*h) -> refcnt); 1008 rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); 1009 if ((*h) -> refcnt <= 0 ) { 1010 dfree (*h, file, line); 1011 } 1012 *h = 0; 1013 return ISC_R_SUCCESS; 1014 } 1015 1016 isc_result_t omapi_value_new (omapi_value_t **d, 1017 const char *file, int line) 1018 { 1019 omapi_value_t *new; 1020 1021 new = dmalloc (sizeof *new, file, line); 1022 if (!new) 1023 return ISC_R_NOMEMORY; 1024 memset (new, 0, sizeof *new); 1025 return omapi_value_reference (d, new, file, line); 1026 } 1027 1028 isc_result_t omapi_value_reference (omapi_value_t **r, 1029 omapi_value_t *h, 1030 const char *file, int line) 1031 { 1032 if (!h || !r) 1033 return DHCP_R_INVALIDARG; 1034 1035 if (*r) { 1036 #if defined (POINTER_DEBUG) 1037 log_error ("%s(%d): reference store into non-null pointer!", 1038 file, line); 1039 abort (); 1040 #else 1041 return DHCP_R_INVALIDARG; 1042 #endif 1043 } 1044 *r = h; 1045 h -> refcnt++; 1046 rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); 1047 return ISC_R_SUCCESS; 1048 } 1049 1050 isc_result_t omapi_value_dereference (omapi_value_t **h, 1051 const char *file, int line) 1052 { 1053 if (!h) 1054 return DHCP_R_INVALIDARG; 1055 1056 if (!*h) { 1057 #if defined (POINTER_DEBUG) 1058 log_error ("%s(%d): dereference of null pointer!", file, line); 1059 abort (); 1060 #else 1061 return DHCP_R_INVALIDARG; 1062 #endif 1063 } 1064 1065 if ((*h) -> refcnt <= 0) { 1066 #if defined (POINTER_DEBUG) 1067 log_error ("%s(%d): dereference of pointer with refcnt of zero!", 1068 file, line); 1069 #if defined (DEBUG_RC_HISTORY) 1070 dump_rc_history (*h); 1071 #endif 1072 abort (); 1073 #else 1074 *h = 0; 1075 return DHCP_R_INVALIDARG; 1076 #endif 1077 } 1078 1079 --((*h) -> refcnt); 1080 rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); 1081 if ((*h) -> refcnt == 0) { 1082 if ((*h) -> name) 1083 omapi_data_string_dereference (&(*h) -> name, 1084 file, line); 1085 if ((*h) -> value) 1086 omapi_typed_data_dereference (&(*h) -> value, 1087 file, line); 1088 dfree (*h, file, line); 1089 } 1090 *h = 0; 1091 return ISC_R_SUCCESS; 1092 } 1093 1094 isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count, 1095 const char *file, int line) 1096 { 1097 omapi_addr_list_t *new; 1098 1099 new = dmalloc ((count * sizeof (omapi_addr_t)) + 1100 sizeof (omapi_addr_list_t), file, line); 1101 if (!new) 1102 return ISC_R_NOMEMORY; 1103 memset (new, 0, ((count * sizeof (omapi_addr_t)) + 1104 sizeof (omapi_addr_list_t))); 1105 new -> count = count; 1106 new -> addresses = (omapi_addr_t *)(new + 1); 1107 return omapi_addr_list_reference (d, new, file, line); 1108 } 1109 1110 isc_result_t omapi_addr_list_reference (omapi_addr_list_t **r, 1111 omapi_addr_list_t *h, 1112 const char *file, int line) 1113 { 1114 if (!h || !r) 1115 return DHCP_R_INVALIDARG; 1116 1117 if (*r) { 1118 #if defined (POINTER_DEBUG) 1119 log_error ("%s(%d): reference store into non-null pointer!", 1120 file, line); 1121 abort (); 1122 #else 1123 return DHCP_R_INVALIDARG; 1124 #endif 1125 } 1126 *r = h; 1127 h -> refcnt++; 1128 rc_register (file, line, r, h, h -> refcnt, 0, RC_MISC); 1129 return ISC_R_SUCCESS; 1130 } 1131 1132 isc_result_t omapi_addr_list_dereference (omapi_addr_list_t **h, 1133 const char *file, int line) 1134 { 1135 if (!h) 1136 return DHCP_R_INVALIDARG; 1137 1138 if (!*h) { 1139 #if defined (POINTER_DEBUG) 1140 log_error ("%s(%d): dereference of null pointer!", file, line); 1141 abort (); 1142 #else 1143 return DHCP_R_INVALIDARG; 1144 #endif 1145 } 1146 1147 if ((*h) -> refcnt <= 0) { 1148 #if defined (POINTER_DEBUG) 1149 log_error ("%s(%d): dereference of pointer with zero refcnt!", 1150 file, line); 1151 #if defined (DEBUG_RC_HISTORY) 1152 dump_rc_history (*h); 1153 #endif 1154 abort (); 1155 #else 1156 *h = 0; 1157 return DHCP_R_INVALIDARG; 1158 #endif 1159 } 1160 1161 --((*h) -> refcnt); 1162 rc_register (file, line, h, *h, (*h) -> refcnt, 1, RC_MISC); 1163 if ((*h) -> refcnt <= 0 ) { 1164 dfree (*h, file, line); 1165 } 1166 *h = 0; 1167 return ISC_R_SUCCESS; 1168 } 1169 1170