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