While using pthread_key_create() to prepare a key to be used by various threads to maintain thread specific data, ensure that the thread specific data stored for a key is cleaned up after the key is no longer used, while the thread finishes otherwise there could be potential memory leaks or misuse of data at the memory locations pointed to by the value.
Noncompliant Code Example
The dynamically allocated block of memory for every thread results in a memory leak and is not destroyed in the noncompliant code example. This also leads to a potential vulnerability to access the one thread's specific data even after it exits apart from a memory leak.
| Code Block |
|---|
|
#include <pthread.h>
#include <stdio.h>
#include<malloc.h>
#define MAX_NUMBER_OF_THREADS 3
/* function prototypes */
void destructor(void * data);
void* function();
void add_data();
void print_data();
/* global key to the thread specific data */
pthread_key_t key;
enum {max_threads = 3};
int main( void )
{
   int i,ret;
   pthread_t thread_id[MAX_NUMBER_OF_THREADSmax_threads];
   /* create the thread specific data key before creating the threads */
   pthread_key_create( &key, NULL );
   /* create threads that willwould usestore thespecific key data*/
   for(i =0; i < MAX_NUMBER_OF_THREADSmax_threads; i++){
       pthread_create( &thread_id[i], NULL, function, NULL );
   }
   for(i=0;i < MAX_NUMBER_OF_THREADSmax_threads; i++){
       int ret = pthread_join(thread_id[i], NULL);
       printf("Join return value for thread[%d] = %d",i,ret);
   }
   pthread_key_delete(key);
}
/* Getting some random data */
int *get_data()
{
   int *arr = malloc(2*sizeof(int));
   *arr = rand();
   *(arr+1) = rand();
   return arr if(ret !=0){
/*Handle Error */
}
   }
   pthread_key_delete(key);
}
void *function(void)
{
   add_data();
   print_data();
   pthread_exit(NULL);
}
void add_data(void)
{
   int *data = get_data();
   printfpthread_setspecific("some data = %p\n", key,(void *)data);
   pthread_setspecific( key,
   (void *) data);
}
int *get_data()
{
   int *arr = malloc(2*sizeof(int));
   *arr = rand();
   *(arr+1) = rand();
   return arr;
}
void print_data()
{
   /* get this thread's global data from
   * priority_key */
   int *data = pthread_getspecific(
   key );
   printf("thread id = %u, data[0] = %d, data[1] = %d \n",(size_t)pthread_self(),*data,*(data+1));
}
Â
|
Compliant Solution
Noncompliant Code Example
This code example is an improvement over the above sample where we try to avoid a memory leak. However if the address of the data is known it could still lead to a potential vulnerability. If for any reason the data received from an arbitrary function get_data() is NULL, a call to free(pthread_getspecific(key) would be equivalent to free(NULL) which most compilers would ignore but is definitely not a good practice.
| Code Block |
|---|
|
| Code Block |
|---|
|
#include <pthread.h>
#include <stdio.h>
#include<malloc.h>
#define MAX_NUMBER_OF_THREADS 3
/* function prototypes */
void destructor(void * data);
void* function();
void add_data();
void print_data();
/* global key to the thread specific data */
pthread_key_t key;
void destructor(void * data){enum {max_threads = 3};
int main( void )
{
   int i,ret;
   pthread_setspecific(key, NULL); // thread specific should be cleared (could be sensitive)
   free(data);
}
/* Getting some random data */
int *get_data(){
   int *arr = malloc(2*sizeof(int));
   *arr = rand();
   *(arr+1) = rand();
   return arrt thread_id[max_threads];
   /* create the key before creating the threads */
   pthread_key_create( &key, NULL );
   /* create threads that would store specific data*/
   for(i =0; i < max_threads; i++){
       pthread_create( &thread_id[i], NULL, function, NULL );
   }
   for(i=0;i < max_threads; i++){
        ret = pthread_join(thread_id[i], NULL);
if(ret !=0){
/*Handle Error */
}
   }
   pthread_key_delete(key);
}
void *function(void)
{
   add_data();
   print_data();
free(pthread_getspecific(key));
   pthread_exit(NULL);
}
void add_data(void)
{
   int *data = get_data();
   printfpthread_setspecific("some data = %p\n", key,(void *)data);
}
   int pthread*get_setspecificdata( key,
   (void *) data);
)
{
   int *arr = malloc(2*sizeof(int));
   *arr = rand();
   *(arr+1) = rand();
   return arr;
}
void print_data()
{
   /* get this thread's global data from
   * priority_key */
   int *data = pthread_getspecific(key);
   printf("thread id = %u, data[0] = %d,
}
|
Compliant Solution
The compliant solution attempts to avoid the memory leak and sets the thread specific data to NULL. An explicit destructor should be used to free memory resources and clean thread specific data. In case the thread specific data is NULL the destructor would not be executed which eliminates the case of free(NULL) in case of second noncompliant code sample.
| Code Block |
|---|
|
#include <pthread.h>
#include <stdio.h>
#include<malloc.h>
/* function prototypes */
void destructor(void * data);
void* function();
void add_data();
void print_data();
/* global key to the thread specific data */
pthread_key_t key;
enum {max_threads = 3};
void destructor(void * data){
   pthread_setspecific(key, NULL); // thread specific should be cleared (could be sensitive)
   free(data) data[1] = %d \n",(size_t)pthread_self(),*data,*(data+1));
}
int main( void )
{
   int i;
   pthread_t thread_id[MAX_NUMBER_OF_THREADSmax_threads];
   /* create the thread specific data key before creating the threads */
   pthread_key_create( &key, destructor );
   /* create thread that will use the key */
   for(i =0; i < MAX_NUMBER_OF_THREADSmax_threads; i++){
       pthread_create( &thread_id[i], NULL, function, NULL );
   }
Â
   for(i=0;i < MAX_NUMBER_OF_THREADSmax_threads; i++){
       int ret = pthread_join(thread_id[i], NULL);
       if(ret !=0){
           /* Handle Error */
       }
   }
   pthread_key_delete(key);
}
void *function()
{
   add_data();
   print_data();
   pthread_exit(NULL);
}
void add_data()
{
   int *data = get_data();
/* set current thread's data */
   pthread_setspecific( key,(void *) data);
}
int *get_data(){
   int *arr = malloc(2*sizeof(int)); /* Not handling the integer overflow */
   *arr = rand();
   *(arr+1) = rand();
   return arr;
}
void print_data()
{
   /* retrieve current thread's data from key */
   int *data = pthread_getspecific(key);
}
|