dlerror.c raw

   1  #include <dlfcn.h>
   2  #include <stdlib.h>
   3  #include <stdarg.h>
   4  #include "pthread_impl.h"
   5  #include "dynlink.h"
   6  #include "lock.h"
   7  #include "fork_impl.h"
   8  
   9  #define malloc __libc_malloc
  10  #define calloc __libc_calloc
  11  #define realloc __libc_realloc
  12  #define free __libc_free
  13  
  14  char *dlerror()
  15  {
  16  	pthread_t self = __pthread_self();
  17  	if (!self->dlerror_flag) return 0;
  18  	self->dlerror_flag = 0;
  19  	char *s = self->dlerror_buf;
  20  	if (s == (void *)-1)
  21  		return "Dynamic linker failed to allocate memory for error message";
  22  	else
  23  		return s;
  24  }
  25  
  26  static volatile int freebuf_queue_lock[1];
  27  static void **freebuf_queue;
  28  volatile int *const __dlerror_lockptr = freebuf_queue_lock;
  29  
  30  void __dl_thread_cleanup(void)
  31  {
  32  	pthread_t self = __pthread_self();
  33  	if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
  34  		LOCK(freebuf_queue_lock);
  35  		void **p = (void **)self->dlerror_buf;
  36  		*p = freebuf_queue;
  37  		freebuf_queue = p;
  38  		UNLOCK(freebuf_queue_lock);
  39  	}
  40  }
  41  
  42  hidden void __dl_vseterr(const char *fmt, va_list ap)
  43  {
  44  	LOCK(freebuf_queue_lock);
  45  	void **q = freebuf_queue;
  46  	freebuf_queue = 0;
  47  	UNLOCK(freebuf_queue_lock);
  48  
  49  	while (q) {
  50  		void **p = *q;
  51  		free(q);
  52  		q = p;
  53  	}
  54  
  55  	va_list ap2;
  56  	va_copy(ap2, ap);
  57  	pthread_t self = __pthread_self();
  58  	if (self->dlerror_buf != (void *)-1)
  59  		free(self->dlerror_buf);
  60  	size_t len = vsnprintf(0, 0, fmt, ap2);
  61  	if (len < sizeof(void *)) len = sizeof(void *);
  62  	va_end(ap2);
  63  	char *buf = malloc(len+1);
  64  	if (buf) {
  65  		vsnprintf(buf, len+1, fmt, ap);
  66  	} else {
  67  		buf = (void *)-1;	
  68  	}
  69  	self->dlerror_buf = buf;
  70  	self->dlerror_flag = 1;
  71  }
  72  
  73  hidden void __dl_seterr(const char *fmt, ...)
  74  {
  75  	va_list ap;
  76  	va_start(ap, fmt);
  77  	__dl_vseterr(fmt, ap);
  78  	va_end(ap);
  79  }
  80  
  81  static int stub_invalid_handle(void *h)
  82  {
  83  	__dl_seterr("Invalid library handle %p", (void *)h);
  84  	return 1;
  85  }
  86  
  87  weak_alias(stub_invalid_handle, __dl_invalid_handle);
  88