Skip to content

Commit 3922082

Browse files
committed
CPP: Tidy and simplify AV Rule 79.ql.
1 parent d5a48ad commit 3922082

File tree

3 files changed

+75
-75
lines changed

3 files changed

+75
-75
lines changed

cpp/ql/src/jsf/4.10 Classes/AV Rule 79.ql

Lines changed: 73 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,69 @@
1010
* external/cwe/cwe-404
1111
*/
1212
import cpp
13+
import Critical.NewDelete
1314

14-
// List pairs of functions that do resource acquisition/release
15-
// Extend this to add custom function pairs. As written the query
16-
// will only apply if the resource is the *return value* of the
17-
// first call and a *parameter* to the second. Other cases should
18-
// be handled differently.
19-
predicate resourceManagementPair(string acquire, string release) {
20-
21-
(acquire = "fopen" and release = "fclose")
22-
or
23-
(acquire = "open" and release = "close")
24-
or
25-
(acquire = "socket" and release = "close")
26-
27-
}
28-
29-
// List functions that return malloc-allocated memory. Customize
30-
// to list your own functions there
31-
predicate mallocFunction(Function malloc) {
32-
malloc.hasName("malloc") or malloc.hasName("calloc") or // Not realloc: doesn't acquire it, really
33-
malloc.hasName("strdup")
15+
/**
16+
* An expression that acquires a resource, and the kind of resource that is acquired. The
17+
* kind of a resource indicates which acquisition/release expressions can be paired.
18+
*/
19+
predicate acquireExpr(Expr acquire, string kind) {
20+
exists(FunctionCall fc, Function f, string name |
21+
fc = acquire and
22+
f = fc.getTarget() and
23+
name = f.getName() and
24+
(
25+
(
26+
name = "fopen" and
27+
kind = "file"
28+
) or (
29+
name = "open" and
30+
kind = "file descriptor"
31+
) or (
32+
name = "socket" and
33+
kind = "file descriptor"
34+
)
35+
)
36+
) or (
37+
allocExpr(acquire, kind)
38+
)
3439
}
3540

36-
private predicate isRelease(string release) {
37-
resourceManagementPair(_, release) or
38-
release = "free" or
39-
release = "delete"
41+
/**
42+
* An expression that releases a resource, and the kind of resource that is released. The
43+
* kind of a resource indicates which acquisition/release expressions can be paired.
44+
*/
45+
predicate releaseExpr(Expr release, Expr resource, string kind) {
46+
exists(FunctionCall fc, Function f, string name |
47+
fc = release and
48+
f = fc.getTarget() and
49+
name = f.getName() and
50+
(
51+
(
52+
name = "fclose" and
53+
resource = fc.getArgument(0) and
54+
kind = "file"
55+
) or (
56+
name = "close" and
57+
resource = fc.getArgument(0) and
58+
kind = "file descriptor"
59+
)
60+
)
61+
) or exists(string releaseKind |
62+
freeExpr(release, resource, releaseKind) and
63+
(
64+
(
65+
kind = "malloc" and
66+
releaseKind = "free"
67+
) or (
68+
kind = "new" and
69+
releaseKind = "delete"
70+
) or (
71+
kind = "new[]" and
72+
releaseKind = "delete[]"
73+
)
74+
)
75+
)
4076
}
4177

4278
/**
@@ -52,35 +88,23 @@ Expr exprOrDereference(Expr e) {
5288
* Holds if the expression `e` releases expression `released`, whether directly
5389
* or via one or more function call(s).
5490
*/
55-
private predicate exprReleases(Expr e, Expr released, string releaseType) {
91+
private predicate exprReleases(Expr e, Expr released, string kind) {
5692
(
57-
// `e` is a call to a release function and `released` is any argument
58-
e.(FunctionCall).getTarget().getName() = releaseType and
59-
isRelease(releaseType) and
60-
e.(FunctionCall).getAnArgument() = released
61-
) or (
62-
// `e` is a call to `delete` and `released` is the target
63-
e.(DeleteExpr).getExpr() = released and
64-
releaseType = "delete"
65-
) or (
66-
// `e` is a call to `delete[]` and `released` is the target
67-
e.(DeleteArrayExpr).getExpr() = released and
68-
releaseType = "delete"
93+
// `e` is a call to a release function and `released` is the released argument
94+
releaseExpr(e, released, kind)
6995
) or exists(Function f, int arg |
7096
// `e` is a call to a function that releases one of it's parameters,
7197
// and `released` is the corresponding argument
7298
e.(FunctionCall).getTarget() = f and
7399
e.(FunctionCall).getArgument(arg) = released and
74-
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), releaseType)
75-
) or exists(Function f, Expr innerThis |
100+
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), kind)
101+
) or exists(Function f, ThisExpr innerThis |
76102
// `e` is a call to a method that releases `this`, and `released`
77103
// is the object that is called
78104
e.(FunctionCall).getTarget() = f and
79105
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
80106
innerThis.getEnclosingFunction() = f and
81-
exprReleases(_, innerThis, releaseType) and
82-
innerThis instanceof ThisExpr and
83-
releaseType = "delete"
107+
exprReleases(_, innerThis, kind)
84108
)
85109
}
86110

@@ -109,42 +133,17 @@ class Resource extends MemberVariable {
109133
)
110134
}
111135

112-
predicate acquisitionWithRequiredRelease(Expr acquire, string releaseName) {
113-
acquire.(Assignment).getLValue() = this.getAnAccess() and
136+
predicate acquisitionWithRequiredRelease(Assignment acquireAssign, string kind) {
137+
// acquireAssign is an assignment to this resource
138+
acquireAssign.(Assignment).getLValue() = this.getAnAccess() and
114139
// Should be in this class, but *any* member method will do
115-
this.inSameClass(acquire) and
140+
this.inSameClass(acquireAssign) and
116141
// Check that it is an acquisition function and return the corresponding free
117-
(
118-
exists(Function f | f = acquire.(Assignment).getRValue().(FunctionCall).getTarget() and
119-
(resourceManagementPair(f.getName(), releaseName) or (mallocFunction(f) and (releaseName = "free" or releaseName = "delete")))
120-
)
121-
or
122-
(acquire = this.getANew() and releaseName = "delete")
123-
)
124-
}
125-
126-
private Assignment getANew() {
127-
result.getLValue() = this.getAnAccess() and
128-
(
129-
(
130-
result.getRValue() instanceof NewExpr and
131-
132-
// exclude placement new and custom overloads as they
133-
// may not conform to assumptions
134-
not result.getRValue().(NewExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
135-
) or (
136-
result.getRValue() instanceof NewArrayExpr and
137-
138-
// exclude placement new and custom overloads as they
139-
// may not conform to assumptions
140-
not result.getRValue().(NewArrayExpr).getAllocatorCall().getTarget().getNumberOfParameters() > 1
141-
)
142-
) and
143-
this.inSameClass(result)
142+
acquireExpr(acquireAssign.getRValue(), kind)
144143
}
145144

146-
Expr getAReleaseExpr(string releaseName) {
147-
exprReleases(result, this.getAnAccess(), releaseName)
145+
Expr getAReleaseExpr(string kind) {
146+
exprReleases(result, this.getAnAccess(), kind)
148147
}
149148
}
150149

cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/AV Rule 79.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
| Variants.cpp:25:3:25:13 | ... = ... | Resource f is acquired by class MyClass4 but not released anywhere in this class. |
1717
| Variants.cpp:65:3:65:17 | ... = ... | Resource a is acquired by class MyClass6 but not released anywhere in this class. |
1818
| Variants.cpp:66:3:66:36 | ... = ... | Resource b is acquired by class MyClass6 but not released anywhere in this class. |
19+
| Variants.cpp:67:3:67:41 | ... = ... | Resource c is acquired by class MyClass6 but not released anywhere in this class. |

cpp/ql/test/query-tests/jsf/4.10 Classes/AV Rule 79/Variants.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class MyClass6
6464
{
6565
a = new int[10]; // BAD
6666
b = (int *)calloc(10, sizeof(int)); // BAD
67-
c = (int *)realloc(0, 10 * sizeof(int)); // BAD [NOT DETECTED]
67+
c = (int *)realloc(0, 10 * sizeof(int)); // BAD
6868
}
6969

7070
~MyClass6()

0 commit comments

Comments
 (0)