
The tss_create()
function creates a thread-specific storage pointed to by a key. Threads can allocated thread specific storage and associated it with a key by calling the tss_set()
function. If not properly freed, this memory may be leaked. Ensure that thread specific memory is freed.
Noncompliant Code Example
In this noncompliant code example, each thread dynamically allocates storage in the get_data()
function which is then associated with the global key by the call to tss_set()
in the add_data()
function. This memory is subsequently leaked when the threads return.
#include <threads.h> #include <stdlib.h> /* Global key to the thread-specific storage. */ tss_t key; enum { MAX_THREADS = 3 }; int *get_data(void) { int *arr = (int *)malloc(2 * sizeof(int)); if (arr == NULL) { return arr; /* Report error */ } arr[0] = 10; arr[1] = 42; return arr; } int add_data(void) { int *data = get_data(); if (data == NULL) { return -1; /* Report error */ } if (thrd_success != tss_set(key, (void *)data)) { /* Handle Error */ } return 0; } void print_data(void) { /* Get this thread's global data from key. */ int *data = tss_get(key); if (data != NULL) { /* Print data */ } } int function(void *dummy) { if (add_data() != 0) { return -1; /* Report error */ } print_data(); return 0; } int main(void) { thrd_t thread_id[MAX_THREADS]; /* Create the key before creating the threads. */ if (thrd_success != tss_create(&key, NULL)) { /* Handle error */ } /* Create threads that would store specific storage. */ for (size_t i = 0; i < MAX_THREADS; i++) { if (thrd_success != thrd_create(&thread_id[i], function, NULL)) { /* Handle error */ } } for (size_t i = 0; i < MAX_THREADS; i++) { if (thrd_success != thrd_join(thread_id[i], NULL)) { /* Handle error */ } } tss_delete(key); return 0; }
Compliant Solution
In this compliant solution, each thread explicitly frees the thread-specific storage returned by the tss_get()
function before completing.
#include <threads.h> #include <stdlib.h> /* Global key to the thread-specific storage. */ tss_t key; int function(void *dummy) { if (add_data() != 0) { return -1; /* Report error */ } print_data(); free(tss_get(key)); return 0; } /* ... Other functions are unchanged. */ int main(void) { /* ... */ tss_delete(key); return 0; }
Compliant Solution
This compliant solution invokes a destructor function registered during the call to tss_create()
to automatically free any thread-specific storage.
#include <threads.h> #include <stdlib.h> /* Global key to the thread-specific storage. */ tss_t key; enum { MAX_THREADS = 3 }; /* ... Other functions are unchanged. */ void destructor(void *data) { free(data); return 0; } int main(void) { thrd_t thread_id[MAX_THREADS]; /* Create the key before creating the threads. */ if (thrd_success != tss_create(&key, destructor)) { /* Handle error */ } /* Create threads that would store specific storage. */ for (size_t i = 0; i < MAX_THREADS; i++) { if (thrd_success != thrd_create(&thread_id[i], function, NULL)) { /* Handle error */ } } for (size_t i = 0; i < MAX_THREADS; i++) { if (thrd_success != thrd_join(thread_id[i], NULL)) { /* Handle error */ } } tss_delete(key); return 0; }
Risk Assessment
Failing to destroy thread-specific objects could lead to memory leaks.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON30-C | medium | unlikely | medium | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.