The tss_create() function creates a thread-specific storage pointed to pointer identified by a key. Threads can allocated thread allocate thread-specific storage and associated it associate the storage with a key that uniquely identifies the storage by calling the tss_set() function. If not properly freed, this memory may be leaked. Ensure that thread-specific memory storage 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 This memory is subsequently leaked when the threads returnterminate.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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 Errorerror */ } 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; } |
...
In this compliant solution, each thread explicitly frees the thread-specific storage returned by by the tss_get() function before completing.terminating:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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.:
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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 free thread-specific objects could lead to results in memory leaks and could result in a denial-of-service attack.
Rule | Severity | Likelihood | Detectable |
|---|
Repairable | Priority | Level |
|---|---|---|
CON30-C | Medium |
Unlikely |
No |
No |
P4
L3
P2 | L3 |
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée |
| Supported, but no explicit checker | |||||||
| CodeSonar |
| ALLOC.LEAK | Leak | ||||||
| Coverity |
| ALLOC_FREE_MISMATCH | Partially implemented, correct implementation is more involved | ||||||
| Cppcheck Premium |
| premium-cert-con30-c | |||||||
| Helix QAC |
| C1780, C1781, C1782, C1783, C1784 | |||||||
| Parasoft C/C++test |
| CERT_C-CON30-a | Ensure resources are freed | ||||||
| CERT C: Rule CON30-C | Checks for thread-specific memory leak (rule fully covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...