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