Skip to content

Commit dae8162

Browse files
Address feedback
1 parent e1a0d6d commit dae8162

15 files changed

+140
-92
lines changed

Diff for: c/common/src/codingstandards/c/SubObjects.qll

+35
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
/**
2+
* A library that expands upon the `Objects.qll` library, to support nested "Objects" such as
3+
* `x.y.z` or `x[i][j]` within an object `x`.
4+
*
5+
* Objects in C are values in memory, that have a type and a storage duration. In the case of
6+
* array objects and struct objects, the object will contain other objects. The these subobjects
7+
* will share properties of the root object such as storage duration. This library can be used to,
8+
* for instance, find all usages of a struct member to ensure that member is initialized before it
9+
* is used.
10+
*
11+
* To use this library, select `SubObject` and find its usages in the AST via `getAnAccess()` (to
12+
* find usages of the subobject by value) or `getAnAddressOfExpr()` (to find usages of the object
13+
* by address).
14+
*
15+
* Note that a struct or array object may contain a pointer. In this case, the pointer itself is
16+
* a subobject of the struct or array object, but the object that the pointer points to is not.
17+
* This is because the pointed-to object does not necessarily have the same storage duration,
18+
* lifetime, or linkage as the pointer and the object containing the pointer.
19+
*
20+
* Note as well that `getAnAccess()` on an array subobject will return all accesses to the array,
21+
* not just accesses to a particular index. For this reason, `SubObject` exposes the predicate
22+
* `isPrecise()`. If a subobject is precise, that means all results of `getAnAccess()` will
23+
* definitely refer to the same object in memory. If it is not precise, the different accesses
24+
* may refer to the same or different objects in memory. For instance, `x[i].y` and `x[j].y` are
25+
* the same object if `i` and `j` are the same, but they are different objects if `i` and `j` are
26+
* different.
27+
*/
28+
129
import codingstandards.c.Objects
230

331
newtype TSubObject =
@@ -70,6 +98,8 @@ class SubObject extends TSubObject {
7098
exists(MemberVariable m |
7199
this = TObjectMember(_, m) and
72100
result = m.getAnAccess() and
101+
// Only consider `DotFieldAccess`es, not `PointerFieldAccess`es, as the latter
102+
// are not subobjects of the root object:
73103
result.(DotFieldAccess).getQualifier() = getParent().getAnAccess()
74104
)
75105
or
@@ -79,6 +109,11 @@ class SubObject extends TSubObject {
79109

80110
AddressOfExpr getAnAddressOfExpr() { result.getOperand() = this.getAnAccess() }
81111

112+
/**
113+
* Get the "root" object identity to which this subobject belongs. For instance, in the
114+
* expression `x.y.z`, the root object is `x`. This subobject will share properties with the root
115+
* object such as storage duration, lifetime, and linkage.
116+
*/
82117
ObjectIdentity getRootIdentity() {
83118
exists(ObjectIdentity i |
84119
this = TObjectRoot(i) and

Diff for: c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ signature module GlobalInitializationAnalysisConfigSig {
77
/** A function which is not called or started as a thread */
88
default predicate isRootFunction(Function f) {
99
not exists(Function f2 | f2.calls(f)) and
10-
not f instanceof ThreadedFunction
10+
not f instanceof ThreadedFunction and
11+
// Exclude functions which are used as function pointers.
12+
not exists(FunctionAccess access | f = access.getTarget())
1113
}
1214

1315
ObjectIdentity getAnInitializedObject(Expr e);

Diff for: c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql

+22-18
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class NonReentrantOperation extends TNonReentrantOperation {
4747
)
4848
}
4949

50-
Expr getARead() {
50+
Expr getAReadExpr() {
5151
exists(SubObject object |
5252
this = TReadWrite(object) and
5353
result = object.getAnAccess()
@@ -56,7 +56,7 @@ class NonReentrantOperation extends TNonReentrantOperation {
5656
this = TStdFunctionCall(result)
5757
}
5858

59-
Expr getAWrite() {
59+
Expr getAWriteExpr() {
6060
exists(SubObject object, Assignment assignment |
6161
this = TReadWrite(object) and
6262
result = assignment and
@@ -94,39 +94,43 @@ class NonReentrantOperation extends TNonReentrantOperation {
9494

9595
class WritingThread extends ThreadedFunction {
9696
NonReentrantOperation aWriteObject;
97-
Expr aWrite;
97+
Expr aWriteExpr;
9898

9999
WritingThread() {
100-
aWrite = aWriteObject.getAWrite() and
101-
this.calls*(aWrite.getEnclosingFunction()) and
102-
not aWrite instanceof LockProtectedControlFlowNode and
103-
not aWrite.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"])
100+
aWriteExpr = aWriteObject.getAWriteExpr() and
101+
// This function directly contains the write expression, or transitively calls the function
102+
// that contains the write expression.
103+
this.calls*(aWriteExpr.getEnclosingFunction()) and
104+
// The write isn't synchronized with a mutex or condition object.
105+
not aWriteExpr instanceof LockProtectedControlFlowNode and
106+
// The write doesn't seem to be during a special initialization phase of the program.
107+
not aWriteExpr.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"])
104108
}
105109

106-
Expr getAWrite() { result = aWrite }
110+
Expr getAWriteExpr() { result = aWriteExpr }
107111
}
108112

109113
class ReadingThread extends ThreadedFunction {
110114
Expr aReadExpr;
111115

112116
ReadingThread() {
113117
exists(NonReentrantOperation op |
114-
aReadExpr = op.getARead() and
118+
aReadExpr = op.getAReadExpr() and
115119
this.calls*(aReadExpr.getEnclosingFunction()) and
116120
not aReadExpr instanceof LockProtectedControlFlowNode
117121
)
118122
}
119123

120-
Expr getARead() { result = aReadExpr }
124+
Expr getAReadExpr() { result = aReadExpr }
121125
}
122126

123127
predicate mayBeDataRace(Expr write, Expr read, NonReentrantOperation operation) {
124128
exists(WritingThread wt |
125-
wt.getAWrite() = write and
126-
write = operation.getAWrite() and
129+
wt.getAWriteExpr() = write and
130+
write = operation.getAWriteExpr() and
127131
exists(ReadingThread rt |
128-
read = rt.getARead() and
129-
read = operation.getARead() and
132+
read = rt.getAReadExpr() and
133+
read = operation.getAReadExpr() and
130134
(
131135
wt.isMultiplySpawned() or
132136
not wt = rt
@@ -141,18 +145,18 @@ from
141145
where
142146
not isExcluded(write, Concurrency9Package::possibleDataRaceBetweenThreadsQuery()) and
143147
mayBeDataRace(write, read, operation) and
144-
wt = min(WritingThread f | f.getAWrite() = write | f order by f.getName()) and
145-
rt = min(ReadingThread f | f.getARead() = read | f order by f.getName()) and
148+
wt = min(WritingThread f | f.getAWriteExpr() = write | f order by f.getName()) and
149+
rt = min(ReadingThread f | f.getAReadExpr() = read | f order by f.getName()) and
146150
writeString = operation.getWriteString() and
147151
readString = operation.getReadString() and
148152
if wt.isMultiplySpawned()
149153
then
150154
message =
151155
"Threaded " + writeString +
152-
" $@ not synchronized, for example from thread function $@ spawned from a loop."
156+
" $@ not synchronized from thread function $@ spawned from a loop."
153157
else
154158
message =
155159
"Threaded " + writeString +
156-
" $@, for example from thread function $@, not synchronized with $@, for example from thread function $@."
160+
" $@ from thread function $@ is not synchronized with $@ from thread function $@."
157161
select write, message, operation.getSourceElement(), operation.toString(), wt, wt.getName(), read,
158162
"concurrent " + readString, rt, rt.getName()

Diff for: c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ where
6464
not isExcluded(operation, Concurrency9Package::invalidOperationOnUnlockedMutexQuery()) and
6565
mutex = operation.getMutex() and
6666
not DominatingSet::isDominatedByBehavior(operation)
67-
select operation, "Invalid operation on mutex '$@' not locked by the current thread",
67+
select operation, "Invalid operation on mutex '$@' not locked by the current thread.",
6868
mutex.getRootIdentity(), mutex.toString()

Diff for: c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @id c/misra/non-recursive-mutex-recursively-locked-audit
33
* @name RULE-22-18: (Audit) Non-recursive mutexes shall not be recursively locked
44
* @description Mutex that may be initialized without mtx_recursive shall not be locked by a thread
5-
* that has previous may havec locked it.
5+
* that may have previously locked it.
66
* @kind problem
77
* @precision high
88
* @problem.severity error
@@ -57,4 +57,4 @@ where
5757
isTrackableMutex(lockCall, true) or
5858
isTrackableMutex(coveredByLock, true)
5959
)
60-
select n, "Mutex locked after previous $@.", coveredByLock, "already locked"
60+
select n, "Mutex locked after it was already $@.", coveredByLock, "previously locked"

Diff for: c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ where
6464
useOne = firstCallForConditionMutex(cond, mutexOne) and
6565
useTwo = firstCallForConditionMutex(cond, mutexOne)
6666
select useOne,
67-
"Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@",
67+
"Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@.",
6868
cond.getRootIdentity(), cond.toString(), mutexOne.getRootIdentity(), mutexOne.toString(), useTwo,
6969
"another operation", mutexTwo.getRootIdentity(), mutexTwo.toString()

Diff for: c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,5 @@ where
4040
not isExcluded(objUse, Concurrency9Package::threadStorageNotInitializedBeforeUseQuery()) and
4141
InitAnalysis::uninitializedFrom(objUse, obj, callRoot)
4242
select objUse,
43-
"Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'.",
43+
"Thread specific storage pointer '$@' used before initialization from entry point function '$@'.",
4444
obj, obj.toString(), callRoot, callRoot.getName()

0 commit comments

Comments
 (0)