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