Skip to content

Commit 528afc5

Browse files
authored
Merge pull request #3788 from geoffw0/callderef
C++: Add bcopy to models and use it.
2 parents 4cc7138 + f9987cf commit 528afc5

File tree

7 files changed

+130
-63
lines changed

7 files changed

+130
-63
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2626
* The models library now models many taint flows through `std::istream` and `std::ostream`.
2727
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2828
* The models library now models many taint flows through `std::pair`, `std::map`, `std::unordered_map`, `std::set` and `std::unordered_set`.
29+
* The models library now models `bcopy`.
2930
* The `SimpleRangeAnalysis` library now supports multiplications of the form
3031
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

cpp/ql/src/semmle/code/cpp/controlflow/Dereferenced.qll

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,25 @@
44

55
import cpp
66
import Nullness
7+
import semmle.code.cpp.models.interfaces.ArrayFunction
78

89
/**
910
* Holds if the call `fc` will dereference argument `i`.
1011
*/
1112
predicate callDereferences(FunctionCall fc, int i) {
12-
exists(string name |
13-
fc.getTarget().hasGlobalOrStdName(name) and
13+
exists(ArrayFunction af |
14+
fc.getTarget() = af and
1415
(
15-
name = "bcopy" and i in [0 .. 1]
16-
or
17-
name = "memcpy" and i in [0 .. 1]
18-
or
19-
name = "memmove" and i in [0 .. 1]
20-
or
21-
name = "strcpy" and i in [0 .. 1]
22-
or
23-
name = "strncpy" and i in [0 .. 1]
24-
or
25-
name = "strdup" and i = 0
26-
or
27-
name = "strndup" and i = 0
28-
or
29-
name = "strlen" and i = 0
30-
or
31-
name = "printf" and fc.getArgument(i).getType() instanceof PointerType
32-
or
33-
name = "fprintf" and fc.getArgument(i).getType() instanceof PointerType
34-
or
35-
name = "sprintf" and fc.getArgument(i).getType() instanceof PointerType
36-
or
37-
name = "snprintf" and fc.getArgument(i).getType() instanceof PointerType
38-
or
39-
name = "vprintf" and fc.getArgument(i).getType() instanceof PointerType
40-
or
41-
name = "vfprintf" and fc.getArgument(i).getType() instanceof PointerType
42-
or
43-
name = "vsprintf" and fc.getArgument(i).getType() instanceof PointerType
44-
or
45-
name = "vsnprintf" and fc.getArgument(i).getType() instanceof PointerType
16+
af.hasArrayInput(i) or
17+
af.hasArrayOutput(i)
4618
)
4719
)
20+
or
21+
exists(FormattingFunction ff |
22+
fc.getTarget() = ff and
23+
i >= ff.getFirstFormatArgumentIndex() and
24+
fc.getArgument(i).getType() instanceof PointerType
25+
)
4826
}
4927

5028
/**

cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,64 +10,76 @@ import semmle.code.cpp.models.interfaces.SideEffect
1010
import semmle.code.cpp.models.interfaces.Taint
1111

1212
/**
13-
* The standard functions `memcpy` and `memmove`, and the gcc variant
14-
* `__builtin___memcpy_chk`
13+
* The standard functions `memcpy`, `memmove` and `bcopy`; and the gcc variant
14+
* `__builtin___memcpy_chk`.
1515
*/
16-
class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, TaintFunction {
16+
class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction {
1717
MemcpyFunction() {
18-
this.hasName("memcpy") or
19-
this.hasName("memmove") or
20-
this.hasName("__builtin___memcpy_chk")
18+
// memcpy(dest, src, num)
19+
// memmove(dest, src, num)
20+
// memmove(dest, src, num, remaining)
21+
this.hasName(["memcpy", "memmove", "__builtin___memcpy_chk"])
22+
or
23+
// bcopy(src, dest, num)
24+
this.hasGlobalOrStdName("bcopy")
2125
}
2226

23-
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
27+
/**
28+
* Gets the index of the parameter that is the source buffer for the copy.
29+
*/
30+
int getParamSrc() { if this.hasGlobalOrStdName("bcopy") then result = 0 else result = 1 }
31+
32+
/**
33+
* Gets the index of the parameter that is the destination buffer for the
34+
* copy.
35+
*/
36+
int getParamDest() { if this.hasGlobalOrStdName("bcopy") then result = 1 else result = 0 }
37+
38+
/**
39+
* Gets the index of the parameter that is the size of the copy (in bytes).
40+
*/
41+
int getParamSize() { result = 2 }
42+
43+
override predicate hasArrayInput(int bufParam) { bufParam = getParamSrc() }
2444

25-
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
45+
override predicate hasArrayOutput(int bufParam) { bufParam = getParamDest() }
2646

2747
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
28-
input.isParameterDeref(1) and
29-
output.isParameterDeref(0)
48+
input.isParameterDeref(getParamSrc()) and
49+
output.isParameterDeref(getParamDest())
3050
or
31-
input.isParameterDeref(1) and
51+
input.isParameterDeref(getParamSrc()) and
3252
output.isReturnValueDeref()
3353
or
34-
input.isParameter(0) and
54+
input.isParameter(getParamDest()) and
3555
output.isReturnValue()
3656
}
3757

38-
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
39-
input.isParameter(2) and
40-
output.isParameterDeref(0)
41-
or
42-
input.isParameter(2) and
43-
output.isReturnValueDeref()
44-
}
45-
4658
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
4759
(
48-
bufParam = 0 or
49-
bufParam = 1
60+
bufParam = getParamDest() or
61+
bufParam = getParamSrc()
5062
) and
51-
countParam = 2
63+
countParam = getParamSize()
5264
}
5365

5466
override predicate hasOnlySpecificReadSideEffects() { any() }
5567

5668
override predicate hasOnlySpecificWriteSideEffects() { any() }
5769

5870
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
59-
i = 0 and buffer = true and mustWrite = true
71+
i = getParamDest() and buffer = true and mustWrite = true
6072
}
6173

6274
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
63-
i = 1 and buffer = true
75+
i = getParamSrc() and buffer = true
6476
}
6577

6678
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
67-
result = 2 and
79+
result = getParamSize() and
6880
(
69-
i = 0 or
70-
i = 1
81+
i = getParamDest() or
82+
i = getParamSrc()
7183
)
7284
}
7385
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5507,8 +5507,6 @@
55075507
| taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | |
55085508
| taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT |
55095509
| taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
5510-
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:2:194:7 | call to memcpy | TAINT |
5511-
| taint.cpp:194:21:194:31 | sizeof(int) | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
55125510
| taint.cpp:207:6:207:11 | call to source | taint.cpp:207:2:207:13 | ... = ... | |
55135511
| taint.cpp:207:6:207:11 | call to source | taint.cpp:210:7:210:7 | x | |
55145512
| taint.cpp:207:6:207:11 | call to source | taint.cpp:213:12:213:12 | x | |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.cpp:23:8:23:8 | p | Value may be null; it should be checked before dereferencing. |
2+
| test.cpp:35:10:35:10 | q | Value may be null; it should be checked before dereferencing. |
3+
| test.cpp:43:13:43:13 | q | Value may be null; it should be checked before dereferencing. |
4+
| test.cpp:51:17:51:17 | q | Value may be null; it should be checked before dereferencing. |
5+
| test.cpp:58:8:58:8 | p | Value may be null; it should be checked before dereferencing. |
6+
| test.cpp:67:8:67:8 | p | Value may be null; it should be checked before dereferencing. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Critical/MissingNullTest.ql
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
#define NULL (0)
3+
4+
typedef unsigned long size_t;
5+
6+
void *memcpy(void *s1, const void *s2, size_t n);
7+
void bcopy(const void *source, void *dest, size_t amount);
8+
9+
void mycopyint(const int *source, int *dest)
10+
{
11+
*dest = *source;
12+
}
13+
14+
void test1(bool cond)
15+
{
16+
int x, y;
17+
18+
{
19+
int *p, *q;
20+
21+
y = *p; // BAD (p is uninitialized and could be 0) [NOT DETECTED]
22+
p = NULL;
23+
y = *p; // BAD (p is 0)
24+
p = &x;
25+
y = *p; // GOOD (p points to x)
26+
p = q;
27+
y = *p; // BAD (p is uninitialized and could be 0) [NOT DETECTED]
28+
}
29+
30+
{
31+
int *p = &x;
32+
int *q = 0;
33+
34+
memcpy(p, &y, sizeof(int)); // GOOD (p points to x)
35+
memcpy(q, &y, sizeof(int)); // BAD (p is 0)
36+
}
37+
38+
{
39+
int *p = &x;
40+
int *q = 0;
41+
42+
bcopy(&y, p, sizeof(int)); // GOOD (p points to x)
43+
bcopy(&y, q, sizeof(int)); // BAD (p is 0)
44+
}
45+
46+
{
47+
int *p = &x;
48+
int *q = 0;
49+
50+
mycopyint(&y, p); // GOOD (p points to x)
51+
mycopyint(&y, q); // BAD (p is 0)
52+
}
53+
54+
{
55+
int *p = 0;
56+
int *q = &x;
57+
58+
y = *p; // BAD (p is 0)
59+
memcpy(&p, &q, sizeof(p));
60+
y = *p; // GOOD (p points to x)
61+
}
62+
63+
{
64+
int *p = 0;
65+
int *q = &x;
66+
67+
y = *p; // BAD (p is 0)
68+
bcopy(&q, &p, sizeof(p));
69+
y = *p; // GOOD (p points to x)
70+
}
71+
}

0 commit comments

Comments
 (0)