This code was taken from the 3rd edition of Advanced Programming in the UNIX Environment, written by Richard Stevens. This is an example of how to make a reentrant version of getenv()
. It is demostrated here only for a learning purpose.
/* Copyright (c) W.R.Stevens */
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
extern char **environ;
pthread_mutex_t env_mutex;
static pthread_once_t init_done = PTHREAD_ONCE_INIT;
static void
thread_init(void)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&env_mutex, &attr);
pthread_mutexattr_destroy(&attr);
}
int
getenv_r(const char *name, char *buf, int buflen)
{
int i, len, olen;
pthread_once(&init_done, thread_init);
len = strlen(name);
pthread_mutex_lock(&env_mutex);
for (i = 0; environ[i] != NULL; i++) {
if ((strncmp(name, environ[i], len) == 0) &&
(environ[i][len] == '=')) {
olen = strlen(&environ[i][len+1]);
if (olen >= buflen) {
pthread_mutex_unlock(&env_mutex);
return(ENOSPC);
}
strcpy(buf, &environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
return(0);
}
}
pthread_mutex_unlock(&env_mutex);
return(ENOENT);
}
This code is easy to understand. I have a question though. We're never calling pthread_mutex_destroy()
, which means that there may be a memory leak on exit (I guess it may differ between platforms).
First thing that comes to mind is that one may use PTHREAD_MUTEX_INITIALIZER
. Does it require pthread_mutex_init()
call? If no, there is no need to call pthread_mutex_destroy()
. However, the mutex will be non-recursive.
One could write a simple C++ class that could destroy mutex in destructor. However, it is not suitable for anyone who has only C compiler (and it seems to be a bullshit to use C++ compiler because of one function).
The other thing that comes to mind are compiler-specific extensions like __attribute__((destructor))
in GCC (and hopefully clang). However, it is non-portable.
Is it possible to avoid a memory leak? If yes, how can that be done in C?
UPDATE
As appears in "Programming with POSIX threads" written by David Butenhof, we never need to destroy PTHREAD_MUTEX_INITIALIZER
variant. How about mutexes with other attributes?
No memory leak because
pthread_mutex_t
variables live in user memory, on process exit all user allocated memory is reclaimed. Memory leaks occur when something allocates heap memory, like strdup. And then you do not clean it up.If it were allocated like
And then not released with free that creates a memory leak -- if then foo got allocated to more new memory. However at process termination ALL memory the process requested including heap is reclaimed by the OS. Stevens explains this in the chapter on processes. That code does not leak.