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