1 /* $NetBSD: alloc.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */
2
3 /* alloc.c
4
5 Functions supporting memory allocation for the object management
6 protocol... */
7
8 /*
9 * Copyright (C) 2004-2022 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 * PO Box 360
26 * Newmarket, NH 03857 USA
27 * <info@isc.org>
28 * https://www.isc.org/
29 *
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: alloc.c,v 1.3 2022/04/03 01:10:59 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 *
dmalloc(size_t size,const char * file,int line)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
dfree(void * ptr,const char * file,int line)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
dmalloc_reuse(void * foo,const char * file,int line,int justref)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
dmalloc_dump_outstanding()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)
print_rc_hist_entry(int i)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
dump_rc_history(void * addr)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 }
rc_history_next(int d)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
dmalloc_find_entry(struct dmalloc_preamble * dp,struct caller * array,int min,int max)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
omapi_print_dmalloc_usage_by_caller()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
omapi_object_allocate(omapi_object_t ** o,omapi_object_type_t * type,size_t size,const char * file,int line)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
omapi_object_initialize(omapi_object_t * o,omapi_object_type_t * type,size_t usize,size_t psize,const char * file,int line)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
omapi_object_reference(omapi_object_t ** r,omapi_object_t * h,const char * file,int line)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
omapi_object_dereference(omapi_object_t ** h,const char * file,int line)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
omapi_buffer_new(omapi_buffer_t ** h,const char * file,int line)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
omapi_buffer_reference(omapi_buffer_t ** r,omapi_buffer_t * h,const char * file,int line)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
omapi_buffer_dereference(omapi_buffer_t ** h,const char * file,int line)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
omapi_typed_data_new(const char * file,int line,omapi_typed_data_t ** t,omapi_datatype_t type,...)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
omapi_typed_data_reference(omapi_typed_data_t ** r,omapi_typed_data_t * h,const char * file,int line)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
omapi_typed_data_dereference(omapi_typed_data_t ** h,const char * file,int line)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
omapi_data_string_new(omapi_data_string_t ** d,unsigned len,const char * file,int line)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
omapi_data_string_reference(omapi_data_string_t ** r,omapi_data_string_t * h,const char * file,int line)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
omapi_data_string_dereference(omapi_data_string_t ** h,const char * file,int line)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
omapi_value_new(omapi_value_t ** d,const char * file,int line)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
omapi_value_reference(omapi_value_t ** r,omapi_value_t * h,const char * file,int line)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
omapi_value_dereference(omapi_value_t ** h,const char * file,int line)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
omapi_addr_list_new(omapi_addr_list_t ** d,unsigned count,const char * file,int line)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
omapi_addr_list_reference(omapi_addr_list_t ** r,omapi_addr_list_t * h,const char * file,int line)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
omapi_addr_list_dereference(omapi_addr_list_t ** h,const char * file,int line)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