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