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