Skip to content

Commit e82f522

Browse files
committed
work
1 parent 16f46f2 commit e82f522

File tree

3 files changed

+160
-99
lines changed

3 files changed

+160
-99
lines changed

cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import codingstandards.cpp.Concurrency
1717
import semmle.code.cpp.dataflow.DataFlow
1818
import semmle.code.cpp.dataflow.TaintTracking
1919

20+
2021
/*
2122
* This query finds potential misuse of mutexes passed to threads by considering
2223
* cases where the underlying mutex may be destroyed. The scope of this query is
@@ -39,7 +40,12 @@ where
3940
and
4041
(
4142
// firstly, we assume it is never safe to destroy a global mutex, but it is
42-
// difficult to make assumptions about the intended control flow.
43+
// difficult to make assumptions about the intended control flow. Note that
44+
// this means the point at where the mutex is defined -- not where the variable
45+
// that contains it is scoped -- a `ThreadDependentMutex` is bound to the
46+
// function that creates an initialized mutex. For example, in `C`
47+
// `mtx_init` is called to initialize the mutex and in C++, the constructor
48+
// of std::mutex is called.
4349
not exists(dm.asExpr().getEnclosingFunction()) or
4450
// secondly, we assume it is never safe to destroy a mutex created by
4551
// another function scope -- which includes trying to destroy a mutex that
@@ -50,4 +56,4 @@ where
5056
// synchronize the threads prior to destroying the mutex.
5157
not exists(ThreadWait tw | tw = md.getAPredecessor*())
5258
)
53-
select dm, "Mutex used by thread potentially $@ while in use.", md, "deleted"
59+
select dm, "Mutex used by thread potentially $@ while in use.", md, "destroyed"

cpp/cert/test/rules/CON50-CPP/test.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
#include <mutex>
22
#include <thread>
33

4+
std::mutex *m4 = new std::mutex(); // NON_COMPLIANT
5+
std::mutex m5; // COMPLIANT
6+
std::mutex *m6 = new std::mutex(); // COMPLIANT
7+
48
void t1(int i, std::mutex *pm) {}
59
void t2(int i, std::mutex **pm) {}
610
void t3(int i, std::mutex *pm) { delete pm; }
11+
void t4(int i) { delete m4; }
12+
void t5(int i) { std::lock_guard<std::mutex> lk(m5); }
713

814
void f1() {
915
std::thread threads[5];
@@ -16,7 +22,7 @@ void f1() {
1622

1723
void f2() {
1824
std::thread threads[5];
19-
std::mutex m1; // COMPLIANT - due to check below
25+
std::mutex m1; // COMPLIANT
2026

2127
for (int i = 0; i < 5; ++i) {
2228
threads[i] = std::thread(t1, i, &m1);
@@ -27,7 +33,8 @@ void f2() {
2733
}
2834
}
2935

30-
std::mutex m2; // COMPLIANT - since m2 will not go out of scope.
36+
std::mutex m2; // COMPLIANT - m2 is not deleted and never goes out of scope.
37+
// There is no delete
3138

3239
void f3() {
3340
std::thread threads[5];
@@ -106,4 +113,34 @@ void f9() {
106113
std::mutex m; // COMPLIANT
107114
}
108115

109-
std::mutex *m4 = new std::mutex(); // COMPLIANT
116+
// f10 does not wait but it is OK since m5 is global and doesn't go out of
117+
// scope -- the destructor isn't called until the program exists.
118+
void f10() {
119+
std::thread threads[5];
120+
121+
for (int i = 0; i < 5; ++i) {
122+
threads[i] = std::thread(t5, i);
123+
}
124+
}
125+
126+
// f11 represents an invalid usage of the global mutex `m4` since it attempts to
127+
// delete it from within the thread.
128+
void f11() {
129+
std::thread threads[5];
130+
131+
for (int i = 0; i < 5; ++i) {
132+
threads[i] = std::thread(t4, i);
133+
}
134+
}
135+
136+
// f12 represents a valid but tricky usage of the global mutex `m6` since it is
137+
// not deleted/accessed from the thread
138+
void f12() {
139+
std::thread threads[5];
140+
141+
for (int i = 0; i < 5; ++i) {
142+
threads[i] = std::thread(t4, i);
143+
}
144+
145+
delete m6;
146+
}

0 commit comments

Comments
 (0)