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