6 * This pair of files helps to locate memory leaks. It is a wrapper for
7 * the malloc family of calls. (Actutally, it currently only deals
8 * with calloc, malloc, realloc, free, strdup and exit)
10 * To use these functions the header "pam_malloc.h" must be included
11 * in all parts of the code (that use the malloc functions) and this
12 * file must be linked with the result. The pam_malloc_flags can be
13 * set from another function and determine the level of logging.
15 * The output is via the macros defined in _pam_macros.h
17 * It is a debugging tool and should be turned off in released code.
19 * This suite was written by Andrew Morgan <morgan@kernel.org> for
26 #include "pam_private.h"
28 #include <security/pam_malloc.h>
29 #include <security/_pam_macros.h>
31 /* this must be done to stop infinite recursion! */
44 * default debugging level
47 int pam_malloc_flags = PAM_MALLOC_ALL;
48 int pam_malloc_delay_length = 4;
50 #define on(x) ((pam_malloc_flags&(x))==(x))
56 static const char *last_fn=NULL;
57 static const char *last_file=NULL;
58 static const char *last_call=NULL;
59 static int last_line = 1;
61 #define err(x) { _pam_output_xdebug_info(); _pam_output_debug x ; }
63 static void set_last_(const char *x, const char *f
64 , const char *fn, const int l)
66 last_fn = x ? x : "error-in-pam_malloc..";
67 last_file = f ? f : "*bad-file*";
68 last_call = fn ? fn: "*bad-fn*";
72 static void _pam_output_xdebug_info(void)
75 int must_close = 1, fd;
78 if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_NOFOLLOW|O_APPEND)) != -1) {
80 if ((fd = open(_PAM_LOGFILE, O_WRONLY|O_APPEND)) != -1) {
82 if (!(logfile = fdopen(fd,"a"))) {
91 fprintf(logfile, "[%s:%s(%d)->%s()] ",
92 last_file, last_call, last_line, last_fn);
98 static void hinder(void)
100 if (on(PAM_MALLOC_PAUSE)) {
101 if (on(0)) err(("pause requested"));
102 sleep(pam_malloc_delay_length);
105 if (on(PAM_MALLOC_STOP)) {
106 if (on(0)) err(("stop requested"));
112 * here are the memory pointer registering functions.. these actually
113 * use malloc(!) but that's ok! ;^)
117 void *ptr; /* pointer */
118 int nelements; /* number of elements */
119 int size; /* - each of this size */
120 char *file; /* where it was requested - filename */
121 char *function; /* - function */
122 int line; /* - line number */
126 struct reference *next;
129 static void _dump(const char *say, const struct reference *ref)
131 _pam_output_debug(" <%s: %p (#%d of %d) req. by %s(); %s line %d>"
133 , ref->ptr,ref->nelements,ref->size
134 , ref->function,ref->file,ref->line);
137 static struct reference *root=NULL;
139 static char *_strdup(const char *x)
143 s = (char *)malloc(strlen(x)+1);
145 if (on(0)) err(("_strdup failed"));
153 static void add_new_ref(void *new, int n, int size)
155 struct reference *ref=NULL;
157 ref = (struct reference *) malloc( sizeof(struct reference) );
158 if (new == NULL || ref == NULL) {
159 if (on(0)) err(("internal error {add_new_ref}"));
167 ref->file = _strdup(last_file);
168 ref->function = _strdup(last_call);
169 ref->line = last_line;
173 if (on(PAM_MALLOC_REQUEST)) {
174 _dump("new_ptr", ref);
180 static void del_old_ref(void *old)
182 struct reference *this,*last;
185 if (on(0)) err(("internal error {del_old_ref}"));
189 /* locate old pointer */
194 if (this->ptr == old)
200 /* Did we find a reference ? */
203 if (on(PAM_MALLOC_FREE)) {
204 _dump("free old_ptr", this);
209 last->next = this->next;
212 free(this->function);
215 if (on(0)) err(("ERROR!: bad memory"));
220 static void verify_old_ref(void *old)
222 struct reference *this;
225 if (on(0)) err(("internal error {verify_old_ref}"));
229 /* locate old pointer */
233 if (this->ptr == old)
238 /* Did we find a reference ? */
241 if (on(PAM_MALLOC_VERIFY)) {
242 _dump("verify_ptr", this);
245 if (on(0)) err(("ERROR!: bad request"));
250 static void dump_memory_list(const char *dump)
252 struct reference *this;
256 if (on(0)) err(("un-free()'d memory"));
262 if (on(0)) err(("no memory allocated"));
266 /* now for the wrappers */
268 #define _fn(x) set_last_(x,file,fn,line)
270 void *pam_malloc(size_t size, const char *file, const char *fn, const int line)
276 if (on(PAM_MALLOC_FUNC)) err(("request for %d", size));
280 if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
282 if (on(PAM_MALLOC_REQUEST)) err(("request new"));
283 add_new_ref(new, 1, size);
289 void *pam_calloc(size_t nelm, size_t size
290 , const char *file, const char *fn, const int line)
296 if (on(PAM_MALLOC_FUNC)) err(("request for %d of %d", nelm, size));
298 new = calloc(nelm,size);
300 if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
302 if (on(PAM_MALLOC_REQUEST)) err(("request new"));
303 add_new_ref(new, nelm, size);
309 void pam_free(void *ptr
310 , const char *file, const char *fn, const int line)
314 if (on(PAM_MALLOC_FUNC))
315 err(("request (%s:%s():%d) to free %p", file, fn, line, ptr));
318 if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
320 if (on(PAM_MALLOC_FREE)) err(("deleted old"));
326 void *pam_memalign(size_t ali, size_t size
327 , const char *file, const char *fn, const int line)
330 if (on(0)) err(("not implemented currently (Sorry)"));
334 void *pam_realloc(void *ptr, size_t size
335 , const char *file, const char *fn, const int line)
341 if (on(PAM_MALLOC_FUNC)) err(("resize %p to %d", ptr, size));
344 if (on(PAM_MALLOC_NULL)) err(("passed NULL pointer"));
349 new = realloc(ptr, size);
351 if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
354 if (on(PAM_MALLOC_FREE)) err(("deleted old"));
357 if (on(PAM_MALLOC_NULL)) err(("old is NULL"));
359 if (on(PAM_MALLOC_REQUEST)) err(("request new"));
360 add_new_ref(new, 1, size);
366 void *pam_valloc(size_t size
367 , const char *file, const char *fn, const int line)
370 if (on(0)) err(("not implemented currently (Sorry)"));
376 void *pam_alloca(size_t size
377 , const char *file, const char *fn, const int line)
380 if (on(0)) err(("not implemented currently (Sorry)"));
385 , const char *file, const char *fn, const int line)
391 if (on(0)) err(("passed (%d)", i));
392 if (on(PAM_MALLOC_LEAKED)) {
393 dump_memory_list("leaked");
398 char *pam_strdup(const char *orig,
399 const char *file, const char *fn, const int line)
405 if (on(PAM_MALLOC_FUNC)) err(("request for dup of [%s]", orig));
409 if (on(PAM_MALLOC_FAIL)) err(("returned NULL"));
411 if (on(PAM_MALLOC_REQUEST)) err(("request dup of [%s]", orig));
412 add_new_ref(new, 1, strlen(new)+1);