de-errno
[dragonfly.git] / contrib / libpam / libpam / pam_malloc.c
1 /*
2  * $Id: pam_malloc.c,v 1.2 1996/12/01 03:14:13 morgan Exp $
3  * $FreeBSD: src/contrib/libpam/libpam/pam_malloc.c,v 1.1.1.1.6.2 2001/06/11 15:28:12 markm Exp $
4  * $DragonFly: src/contrib/libpam/libpam/Attic/pam_malloc.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
5  *
6  * $Log: pam_malloc.c,v $
7  * Revision 1.2  1996/12/01 03:14:13  morgan
8  * use _pam_macros.h
9  *
10  * Revision 1.1  1996/11/10 21:26:11  morgan
11  * Initial revision
12  *
13  */
14
15 /*
16  * This pair of files helps to locate memory leaks. It is a wrapper for
17  * the malloc family of calls. (Actutally, it currently only deals
18  * with calloc, malloc, realloc, free and exit)
19  *
20  * To use these functions the header "pam_malloc.h" must be included
21  * in all parts of the code (that use the malloc functions) and this
22  * file must be linked with the result. The pam_malloc_flags can be
23  * set from another function and determine the level of logging.
24  *
25  * The output is via the macros defined in _pam_macros.h
26  *
27  * It is a debugging tool and should be turned off in released code.
28  *
29  * This suite was written by Andrew Morgan <morgan@parc.power.net> for
30  * Linux-PAM.
31  */
32
33 #ifndef DEBUG
34 #define DEBUG
35 #endif
36
37 #include "pam_private.h"
38
39 #include <security/pam_malloc.h>
40 #include <security/_pam_macros.h>
41
42 /* this must be done to stop infinite recursion! */
43 #undef malloc
44 #undef calloc
45 #undef free
46 #undef realloc
47 #undef exit
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52
53 /*
54  * default debugging level
55  */
56
57 int pam_malloc_flags = PAM_MALLOC_DEFAULT;
58 int pam_malloc_delay_length = 4;
59
60 #define on(x) ((pam_malloc_flags&(x))==(x))
61
62 /*
63  * the implementation
64  */
65
66 static const char *last_fn=NULL;
67 static const char *last_file=NULL;
68 static const char *last_call=NULL;
69 static int last_line = 1;
70
71 #define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; }
72
73 static void set_last_(const char *x, const char *f
74                       , const char *fn, const int l)
75 {
76      last_fn   = x  ? x : "error-in-pam_malloc..";
77      last_file = f  ? f : "*bad-file*";
78      last_call = fn ? fn: "*bad-fn*";
79      last_line = l;
80 }
81
82 static void _pam_output_xdebug_info(void)
83 {
84     FILE *logfile;
85     int must_close = 1;
86     
87     if (!(logfile = fopen(_PAM_LOGFILE,"a"))) {
88         logfile = stderr;
89         must_close = 0;
90     }
91     fprintf(logfile, "[%s:%s(%d)->%s()] ",
92            last_file, last_call, last_line, last_fn);
93     if (must_close) {
94         fflush(logfile);
95         fclose(logfile);
96     }
97 }
98
99 static void hinder(void)
100 {
101      if (on(PAM_MALLOC_PAUSE)) {
102           if (on(0)) err(("pause requested"));
103           sleep(pam_malloc_delay_length);
104      }
105
106      if (on(PAM_MALLOC_STOP)) {
107           if (on(0)) err(("stop requested"));
108           exit(1);
109      }
110 }
111
112 /*
113  * here are the memory pointer registering functions.. these actually
114  * use malloc(!) but that's ok! ;^)
115  */
116
117 struct reference {
118      void *ptr;          /* pointer */
119      int nelements;      /* number of elements */
120      int size;           /* - each of this size */
121      char *file;         /* where it was requested - filename */
122      char *function;     /*                        - function */
123      int line;           /*                        - line number */
124 /*
125  * linking info
126  */
127      struct reference *next;
128 };
129
130 static void _dump(const char *say, const struct reference *ref)
131 {
132     _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>\n"
133                       , say
134                       , ref->ptr,ref->nelements,ref->size
135                       , ref->function,ref->file,ref->line);
136 }
137
138 static struct reference *root=NULL;
139
140 static char *_strdup(const char *x)
141 {
142      char *s;
143
144      s = (char *)malloc(strlen(x)+1);
145      if (s == NULL) {
146           if (on(0)) err(("_strdup failed"));
147           exit(1);
148      }
149
150      strcpy(s,x);
151      return s;
152 }
153
154 static void add_new_ref(void *new, int n, int size)
155 {
156      struct reference *ref=NULL;
157
158      ref = (struct reference *) malloc( sizeof(struct reference) );
159      if (new == NULL || ref == NULL) {
160           if (on(0)) err(("internal error {add_new_ref}"));
161           exit(1);
162      }
163
164      ref->ptr = new;
165      ref->nelements = n;
166      ref->size = size;
167
168      ref->file = _strdup(last_file);
169      ref->function = _strdup(last_call);
170      ref->line = last_line;
171
172      ref->next = root;
173
174      if (on(PAM_MALLOC_REQUEST)) {
175           _dump("new_ptr", ref);
176      }
177
178      root = ref;
179 }
180
181 static void del_old_ref(void *old)
182 {
183      struct reference *this,*last;
184
185      if (old == NULL) {
186           if (on(0)) err(("internal error {del_old_ref}"));
187           exit(1);
188      }
189
190      /* locate old pointer */
191
192      last = NULL;
193      this = root;
194      while (this) {
195           if (this->ptr == old)
196                break;
197           last = this;
198           this = this->next;
199      }
200
201      /* Did we find a reference ? */
202
203      if (this) {
204           if (on(PAM_MALLOC_FREE)) {
205                _dump("free old_ptr", this);
206           }
207           if (last == NULL) {
208                root = this->next;
209           } else {
210                last->next = this->next;
211           }
212           free(this->file);
213           free(this->function);
214           free(this);
215      } else {
216           if (on(0)) err(("ERROR!: bad memory"));
217           hinder();
218      }
219 }
220
221 static void verify_old_ref(void *old)
222 {
223      struct reference *this;
224
225      if (old == NULL) {
226           if (on(0)) err(("internal error {verify_old_ref}"));
227           exit(1);
228      }
229
230      /* locate old pointer */
231
232      this = root;
233      while (this) {
234           if (this->ptr == old)
235                break;
236           this = this->next;
237      }
238
239      /* Did we find a reference ? */
240
241      if (this) {
242           if (on(PAM_MALLOC_VERIFY)) {
243                _dump("verify_ptr", this);
244           }
245      } else {
246           if (on(0)) err(("ERROR!: bad request"));
247           hinder();
248      }
249 }
250
251 static void dump_memory_list(const char *dump)
252 {
253      struct reference *this;
254
255      this = root;
256      if (this) {
257           if (on(0)) err(("un-free()'d memory"));
258           while (this) {
259                _dump(dump, this);
260                this = this->next;
261           }
262      } else {
263           if (on(0)) err(("no memory allocated"));
264      }
265 }
266
267 /* now for the wrappers */
268
269 #define _fn(x)  set_last_(x,file,fn,line)
270
271 void *pam_malloc(size_t size, const char *file, const char *fn, const int line)
272 {
273      void *new;
274
275      _fn("malloc");
276
277      if (on(PAM_MALLOC_FUNC)) err(("request for %d", size));
278
279      new = malloc(size);
280      if (new == NULL) {
281           if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
282      } else {
283           if (on(PAM_MALLOC_REQUEST)) err(("request new"));
284           add_new_ref(new, 1, size);
285      }
286
287      return new;
288 }
289
290 void *pam_calloc(size_t nelm, size_t size
291                 , const char *file, const char *fn, const int line)
292 {
293      void *new;
294
295      _fn("calloc");
296
297      if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size));
298
299      new = calloc(nelm,size);
300      if (new == NULL) {
301           if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
302      } else {
303           if (on(PAM_MALLOC_REQUEST)) err(("request new"));
304           add_new_ref(new, nelm, size);
305      }
306
307      return new;
308 }
309
310 void  pam_free(void *ptr
311               , const char *file, const char *fn, const int line)
312 {
313      _fn("free");
314
315      if (on(PAM_MALLOC_FUNC)) err(("request to free %p", ptr));
316
317      if (ptr == NULL) {
318           if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
319      } else {
320           if (on(PAM_MALLOC_FREE)) err(("deleted old"));
321           del_old_ref(ptr);
322           free(ptr);
323      }
324 }
325
326 void *pam_memalign(size_t ali, size_t size
327                   , const char *file, const char *fn, const int line)
328 {
329      _fn("memalign");
330      if (on(0)) err(("not implemented currently (Sorry)"));
331      exit(1);
332 }
333
334 void *pam_realloc(void *ptr, size_t size
335                 , const char *file, const char *fn, const int line)
336 {
337      void *new;
338
339      _fn("realloc");
340
341      if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size));
342
343      if (ptr == NULL) {
344           if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
345      } else {
346           verify_old_ref(ptr);
347      }
348
349      new = realloc(ptr, size);
350      if (new == NULL) {
351           if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
352      } else {
353           if (ptr) {
354                if (on(PAM_MALLOC_FREE)) err(("deleted old"));
355                del_old_ref(ptr);
356           } else {
357                if (on(PAM_MALLOC_NULL)) err(("old is NULL"));
358           }
359           if (on(PAM_MALLOC_REQUEST)) err(("request new"));
360           add_new_ref(new, 1, size);
361      }
362
363      return new;
364 }
365
366 void *pam_valloc(size_t size
367                 , const char *file, const char *fn, const int line)
368 {
369      _fn("valloc");
370      if (on(0)) err(("not implemented currently (Sorry)"));
371      exit(1);
372 }
373
374 #include <alloca.h>
375
376 void *pam_alloca(size_t size
377                 , const char *file, const char *fn, const int line)
378 {
379      _fn("alloca");
380      if (on(0)) err(("not implemented currently (Sorry)"));
381      exit(1);
382 }
383
384 void pam_exit(int i
385               , const char *file, const char *fn, const int line)
386 {
387      _fn("exit");
388
389      if (on(0)) err(("passed (%d)", i));
390      if (on(PAM_MALLOC_LEAKED)) {
391           dump_memory_list("leaked");
392      }
393      exit(i);
394 }
395
396 /* end of file */