CWE Rule 826
Description
Rule Description
The product releases a resource that is still intended to be used by itself or another actor.
Polyspace Implementation
The rule checker checks for these issues:
Closing previously closed resource
Destruction of locked mutex
Use of previously closed resource
Examples
Closing previously closed resource
This issue occurs when a function attempts to close a stream that was closed earlier in your code and not reopened later.
The standard states that the value of a FILE*
pointer is
indeterminate after you close the stream associated with it. Performing the close
operation on the FILE*
pointer again can cause unwanted
behavior.
Remove the redundant close operation.
#include <stdio.h> void func(char* data) { FILE* fp = fopen("file.txt", "w"); if(fp!=NULL) { if(data) fputc(*data,fp); else fclose(fp); } fclose(fp); //Noncompliant }
In this example, if fp
is not NULL
and data
is NULL
,
the fclose
operation occurs on fp
twice
in succession.
One possible correction is to remove the last fclose
operation.
To avoid a resource leak, you must also place an fclose
operation
in the if(data)
block.
#include <stdio.h> void func(char* data) { FILE* fp = fopen("file.txt", "w"); if(fp!=NULL) { if(data) { fputc(*data,fp); fclose(fp); } else fclose(fp); } }
Destruction of locked mutex
This checker is deactivated in a default Polyspace® as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).
This issue occurs when a task destroys a mutex after it is locked (and before it is unlocked). The locking and destruction can happen in the same task or different tasks.
A mutex is locked to protect shared variables from concurrent access. If a mutex is destroyed in the locked state, the protection does not apply.
To fix this defect, destroy the mutex only after you unlock it. It is a good design practice to:
Initialize a mutex before creating the threads where you use the mutex.
Destroy a mutex after joining the threads that you created.
On the Result Details pane, you see two events, the locking and destruction of the mutex, and the tasks that initiated the events. To navigate to the corresponding line in your source code, click the event.
#include <pthread.h> pthread_mutex_t lock1; pthread_mutex_t lock2; pthread_mutex_t lock3; void t0 (void) { pthread_mutex_lock (&lock1); pthread_mutex_lock (&lock2); pthread_mutex_lock (&lock3); pthread_mutex_unlock (&lock2); pthread_mutex_unlock (&lock1); pthread_mutex_unlock (&lock3); } void t1 (void) { pthread_mutex_lock (&lock1); pthread_mutex_lock (&lock2); pthread_mutex_destroy (&lock3); //Noncompliant pthread_mutex_unlock (&lock2); pthread_mutex_unlock (&lock1); }
In this example, after task t0
locks the
mutex lock3
, task t1
can destroy
it. The destruction occurs if the following events happen in sequence:
t0
acquireslock3
.t0
releaseslock2
.t0
releaseslock1
.t1
acquires the locklock1
released byt0
.t1
acquires the locklock2
released byt0
.t1
destroyslock3
.
For simplicity, this example uses a mix of automatic and
manual concurrency detection. The tasks t0
and t1
are
manually specified as entry points by using the option Tasks (-entry-points)
. The critical sections are implemented through primitives
pthread_mutex_lock
and pthread_mutex_unlock
that the
software detects automatically. In practice, for entry point specification (thread creation),
you will use primitives such as pthread_create
. The next example shows how
the defect can appear when you use pthread_create
.
The locking and destruction of lock3
occurs
inside the critical section imposed by lock1
and lock2
,
but the unlocking occurs outside. One possible correction is to place
the lock-unlock pair in the same critical section as the destruction
of the mutex. Use one of these critical sections:
Critical section imposed by
lock1
alone.Critical section imposed by
lock1
andlock2
.
In this corrected code, the lock-unlock pair and the destruction
is placed in the critical section imposed by lock1
and lock2
.
When t0
acquires lock1
and lock2
, t1
has
to wait for their release before it executes the instruction pthread_mutex_destroy
(&lock3);
. Therefore, t1
cannot destroy
mutex lock3
in the locked state.
#include <pthread.h> pthread_mutex_t lock1; pthread_mutex_t lock2; pthread_mutex_t lock3; void t0 (void) { pthread_mutex_lock (&lock1); pthread_mutex_lock (&lock2); pthread_mutex_lock (&lock3); pthread_mutex_unlock (&lock3); pthread_mutex_unlock (&lock2); pthread_mutex_unlock (&lock1); } void t1 (void) { pthread_mutex_lock (&lock1); pthread_mutex_lock (&lock2); pthread_mutex_destroy (&lock3); pthread_mutex_unlock (&lock2); pthread_mutex_unlock (&lock1); }
#include <pthread.h> /* Define globally accessible variables and a mutex */ #define NUMTHREADS 4 pthread_t callThd[NUMTHREADS]; pthread_mutex_t lock; void atomic_operation(void); void *do_create(void *arg) { /* Creation thread */ pthread_mutex_init(&lock, NULL); pthread_exit((void*) 0); } void *do_work(void *arg) { /* Worker thread */ pthread_mutex_lock (&lock); atomic_operation(); pthread_mutex_unlock (&lock); pthread_exit((void*) 0); } void *do_destroy(void *arg) { /* Destruction thread */ pthread_mutex_destroy(&lock); //Noncompliant pthread_exit((void*) 0); } int main (int argc, char *argv[]) { int i; void *status; pthread_attr_t attr; /* Create threads */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* Thread that initializes mutex */ pthread_create(&callThd[0], &attr, do_create, NULL); /* Threads that use mutex for atomic operation*/ for(i=0; i<NUMTHREADS-1; i++) { pthread_create(&callThd[i], &attr, do_work, (void *)i); } /* Thread that destroys mutex */ pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL); pthread_attr_destroy(&attr); /* Join threads */ for(i=0; i<NUMTHREADS; i++) { pthread_join(callThd[i], &status); } pthread_exit(NULL); }
In this example, four threads are created. The threads are assigned different actions.
The first thread
callThd[0]
initializes the mutexlock
.The second and third threads,
callThd[1]
andcallThd[2]
, perform an atomic operation protected by the mutexlock
.The fourth thread
callThd[3]
destroys the mutexlock
.
The threads can interrupt each other. Therefore, immediately after the second or third thread locks the mutex, the fourth thread can destroy it.
One possible correction is to initialize and destroy the mutex
in the main
function outside the start routine
of the threads. The threads perform only the atomic operation. You
need two fewer threads because the mutex initialization and destruction
threads are not required.
#include <pthread.h> /* Define globally accessible variables and a mutex */ #define NUMTHREADS 2 pthread_t callThd[NUMTHREADS]; pthread_mutex_t lock; void atomic_operation(void); void *do_work(void *arg) { pthread_mutex_lock (&lock); atomic_operation(); pthread_mutex_unlock (&lock); pthread_exit((void*) 0); } int main (int argc, char *argv[]) { int i; void *status; pthread_attr_t attr; /* Create threads */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* Initialize mutex */ pthread_mutex_init(&lock, NULL); for(i=0; i<NUMTHREADS; i++) { pthread_create(&callThd[i], &attr, do_work, (void *)i); } pthread_attr_destroy(&attr); /* Join threads */ for(i=0; i<NUMTHREADS; i++) { pthread_join(callThd[i], &status); } /* Destroy mutex */ pthread_mutex_destroy(&lock); pthread_exit(NULL); }
Another possible correction is to use a second mutex and protect
the lock-unlock pair from the destruction. This corrected code uses
the mutex lock2
to achieve this protection. The
second mutex is initialized in the main
function
outside the start routine of the threads.
#include <pthread.h> /* Define globally accessible variables and a mutex */ #define NUMTHREADS 4 pthread_t callThd[NUMTHREADS]; pthread_mutex_t lock; pthread_mutex_t lock2; void atomic_operation(void); void *do_create(void *arg) { /* Creation thread */ pthread_mutex_init(&lock, NULL); pthread_exit((void*) 0); } void *do_work(void *arg) { /* Worker thread */ pthread_mutex_lock (&lock2); pthread_mutex_lock (&lock); atomic_operation(); pthread_mutex_unlock (&lock); pthread_mutex_unlock (&lock2); pthread_exit((void*) 0); } void *do_destroy(void *arg) { /* Destruction thread */ pthread_mutex_lock (&lock2); pthread_mutex_destroy(&lock); pthread_mutex_unlock (&lock2); pthread_exit((void*) 0); } int main (int argc, char *argv[]) { int i; void *status; pthread_attr_t attr; /* Create threads */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); /* Initialize second mutex */ pthread_mutex_init(&lock2, NULL); /* Thread that initializes first mutex */ pthread_create(&callThd[0], &attr, do_create, NULL); /* Threads that use first mutex for atomic operation */ /* The threads use second mutex to protect first from destruction in locked state*/ for(i=0; i<NUMTHREADS-1; i++) { pthread_create(&callThd[i], &attr, do_work, (void *)i); } /* Thread that destroys first mutex */ /* The thread uses the second mutex to prevent destruction of locked mutex */ pthread_create(&callThd[NUMTHREADS -1], &attr, do_destroy, NULL); pthread_attr_destroy(&attr); /* Join threads */ for(i=0; i<NUMTHREADS; i++) { pthread_join(callThd[i], &status); } /* Destroy second mutex */ pthread_mutex_destroy(&lock2); pthread_exit(NULL); }
Use of previously closed resource
This issue occurs when a function operates on a stream that you closed earlier in your code.
The standard states that the value of a FILE*
pointer
is indeterminate after you close the stream associated with it. Operations
using the FILE*
pointer can produce unintended
results.
One possible fix is to close the stream only at the end of operations. Another fix is to reopen the stream before using it again.
#include <stdio.h> void func(void) { FILE *fp; void *ptr; fp = fopen("tmp","w"); if(fp != NULL) { fclose(fp); fprintf(fp,"text"); //Noncompliant } }
In this example, fclose
closes the stream
associated with fp
. When you use fprintf
on fp
after fclose
,
the Use of previously closed resource defect
appears.
One possible correction is to reverse the order of the fprintf
and fclose
operations.
#include <stdio.h> void func(void) { FILE *fp; void *ptr; fp = fopen("tmp","w"); if(fp != NULL) { fprintf(fp,"text"); fclose(fp); } }
Check Information
Category: Resource Management Errors |
Version History
Introduced in R2024a
See Also
External Websites
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)