Skip to content

Commit 07495b3

Browse files
author
Nikita Kraiouchkine
authored
Merge pull request #176 from kraiouchkine/InvalidMemory1
Implement InvalidMemory1 package
2 parents b18a89e + a92f73a commit 07495b3

33 files changed

+1440
-31
lines changed

.vscode/tasks.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@
223223
"Includes",
224224
"Initialization",
225225
"IntegerConversion",
226+
"InvalidMemory1",
227+
"InvalidMemory2",
226228
"Invariants",
227229
"Iterators",
228230
"Lambdas",
@@ -231,6 +233,8 @@
231233
"Literals",
232234
"Loops",
233235
"Macros",
236+
"Memory1",
237+
"Memory2",
234238
"Misc",
235239
"MoveForward",
236240
"Naming",

c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.md

Lines changed: 417 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @id c/cert/do-not-read-uninitialized-memory
3+
* @name EXP33-C: Do not read uninitialized memory
4+
* @description Using the value of an object with automatic storage duration while it is
5+
* indeterminate is undefined behavior.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity error
9+
* @tags external/cert/id/exp33-c
10+
* correctness
11+
* security
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory
18+
19+
class DoNotReadUninitializedMemoryQuery extends ReadOfUninitializedMemorySharedQuery {
20+
DoNotReadUninitializedMemoryQuery() {
21+
this = InvalidMemory1Package::doNotReadUninitializedMemoryQuery()
22+
}
23+
}

c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.md

Lines changed: 219 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @id c/cert/do-not-dereference-null-pointers
3+
* @name EXP34-C: Do not dereference null pointers
4+
* @description Dereferencing a null pointer leads to undefined behavior.
5+
* @kind problem
6+
* @precision medium
7+
* @problem.severity error
8+
* @tags external/cert/id/exp34-c
9+
* correctness
10+
* external/cert/obligation/rule
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.cert
15+
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
16+
17+
class DoNotDereferenceNullPointersQuery extends DereferenceOfNullPointerSharedQuery {
18+
DoNotDereferenceNullPointersQuery() {
19+
this = InvalidMemory1Package::doNotDereferenceNullPointersQuery()
20+
}
21+
}

c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.md

Lines changed: 258 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @id c/cert/do-not-access-freed-memory
3+
* @name MEM30-C: Do not access freed memory
4+
* @description Accessing memory that has been deallocated is undefined behavior.
5+
* @kind problem
6+
* @precision high
7+
* @problem.severity error
8+
* @tags external/cert/id/mem30-c
9+
* correctness
10+
* security
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.cpp.Allocations
17+
import semmle.code.cpp.controlflow.StackVariableReachability
18+
19+
/** `e` is an expression that frees the memory pointed to by `v`. */
20+
predicate isFreeExpr(Expr e, StackVariable v) {
21+
exists(VariableAccess va | va.getTarget() = v and freeExprOrIndirect(e, va, _))
22+
}
23+
24+
/** `e` is an expression that accesses `v` but is not the lvalue of an assignment. */
25+
predicate isAccessExpr(Expr e, StackVariable v) {
26+
v.getAnAccess() = e and
27+
not exists(Assignment a | a.getLValue() = e)
28+
or
29+
isDerefByCallExpr(_, _, e, v)
30+
}
31+
32+
/**
33+
* `va` is passed by value as (part of) the `i`th argument in
34+
* call `c`. The target function is either a library function
35+
* or a source code function that dereferences the relevant
36+
* parameter.
37+
*/
38+
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
39+
v.getAnAccess() = va and
40+
va = c.getAnArgumentSubExpr(i) and
41+
not c.passesByReference(i, va) and
42+
(c.getTarget().hasEntryPoint() implies isAccessExpr(_, c.getTarget().getParameter(i)))
43+
}
44+
45+
class UseAfterFreeReachability extends StackVariableReachability {
46+
UseAfterFreeReachability() { this = "UseAfterFree" }
47+
48+
override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }
49+
50+
override predicate isSink(ControlFlowNode node, StackVariable v) { isAccessExpr(node, v) }
51+
52+
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
53+
definitionBarrier(v, node) or
54+
isFreeExpr(node, v)
55+
}
56+
}
57+
58+
// This query is a modified version of the `UseAfterFree.ql`
59+
// (cpp/use-after-free) query from the CodeQL standard library.
60+
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
61+
where
62+
not isExcluded(e, InvalidMemory1Package::doNotAccessFreedMemoryQuery()) and
63+
r.reaches(free, v, e)
64+
select e,
65+
"Pointer '" + v.getName().toString() + "' accessed but may have been previously freed $@.", free,
66+
"here"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/dereferenceofnullpointer/DereferenceOfNullPointer.ql
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| test.c:11:47:11:47 | p | Pointer 'p' accessed but may have been previously freed $@. | test.c:12:5:12:8 | call to free | here |
2+
| test.c:25:10:25:12 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:24:3:24:6 | call to free | here |
3+
| test.c:32:15:32:17 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
4+
| test.c:33:9:33:11 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
5+
| test.c:34:16:34:18 | buf | Pointer 'buf' accessed but may have been previously freed $@. | test.c:31:3:31:6 | call to free | here |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/MEM30-C/DoNotAccessFreedMemory.ql

c/cert/test/rules/MEM30-C/test.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include <stdlib.h>
2+
#include <string.h>
3+
4+
struct node {
5+
struct node *next;
6+
};
7+
8+
void test_freed_loop_var(struct node *list1, struct node *list2) {
9+
struct node *tmp;
10+
11+
for (struct node *p = list1; p != NULL; p = p->next) { // NON_COMPLIANT
12+
free(p);
13+
}
14+
15+
for (struct node *p = list2; p != NULL; p = tmp) { // COMPLIANT
16+
tmp = p->next;
17+
free(p);
18+
}
19+
}
20+
21+
void test_freed_arg(char *input) {
22+
char *buf = (char *)malloc(strlen(input) + 1);
23+
strcpy(buf, input); // COMPLIANT
24+
free(buf);
25+
strcpy(buf, input); // NON_COMPLIANT
26+
}
27+
28+
void test_freed_access_no_deref(char *input) {
29+
char *buf = (char *)malloc(strlen(input) + 1);
30+
strcpy(buf, input); // COMPLIANT
31+
free(buf);
32+
char *tmp = buf; // NON_COMPLIANT
33+
tmp = buf + 1; // NON_COMPLIANT
34+
char *tmp2 = buf; // NON_COMPLIANT
35+
buf = NULL; // COMPLIANT
36+
(char *)buf; // COMPLIANT
37+
tmp2 = buf + 1; // COMPLIANT
38+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:11:4:11:5 | l1 | Null may be dereferenced here because a null value was assigned $@. | test.c:4:21:4:21 | 0 | here |
2+
| test.c:18:6:18:7 | l1 | Null may be dereferenced here because a null value was assigned $@. | test.c:4:21:4:21 | 0 | here |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <stdlib.h>
2+
3+
void test_null(int p1) {
4+
int *l1 = (void *)0;
5+
6+
if (p1 > 10) {
7+
// l1 is only conditionally initialized
8+
l1 = malloc(10 * sizeof(int));
9+
}
10+
11+
*l1; // NON_COMPLIANT - dereferenced and still null
12+
13+
if (l1) {
14+
*l1; // COMPLIANT - null check before dereference
15+
}
16+
17+
if (!l1) {
18+
*l1; // NON_COMPLIANT - dereferenced and definitely null
19+
} else {
20+
*l1; // COMPLIANT - null check before dereference
21+
}
22+
23+
free(l1); // COMPLIANT - free of `NULL` is not undefined behavior
24+
}
25+
26+
void test_default_value_init() {
27+
int *l1; // indeterminate and thus invalid but non-null state
28+
29+
*l1; // COMPLIANT - considered an uninitialized pointer,
30+
// not a null pointer
31+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:33:11:33:12 | l1 | Local variable $@ is read here and may not be initialized on all paths. | test.c:32:7:32:8 | l1 | l1 |
2+
| test.c:35:15:35:16 | l2 | Local variable $@ is read here and may not be initialized on all paths. | test.c:34:8:34:9 | l2 | l2 |
3+
| test.c:37:20:37:21 | l3 | Local variable $@ is read here and may not be initialized on all paths. | test.c:36:13:36:14 | l3 | l3 |
4+
| test.c:84:17:84:24 | arrayPtr | Local variable $@ is read here and may not be initialized on all paths. | test.c:77:8:77:15 | arrayPtr | arrayPtr |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// GENERATED FILE - DO NOT MODIFY
2+
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include <stdlib.h>
2+
3+
struct A {
4+
int m1;
5+
};
6+
7+
void use_int(int a);
8+
void use_struct_A(struct A a);
9+
void use_int_ptr(int *a);
10+
void use_struct_A_ptr(struct A *a);
11+
12+
void init_by_pointer(int *pointer_param);
13+
14+
void test_basic_init() {
15+
int l1 = 0;
16+
use_int(l1); // COMPLIANT
17+
struct A l2 = {};
18+
use_struct_A(l2); // COMPLIANT
19+
int l3;
20+
init_by_pointer(&l3);
21+
use_int(l3); // COMPLIANT
22+
struct A l4;
23+
l4.m1 = 1; // COMPLIANT
24+
use_struct_A(l4); // COMPLIANT
25+
int l5[10] = {1, 0};
26+
use_int_ptr(l5); // COMPLIANT
27+
struct A l6;
28+
use_struct_A(l6); // COMPLIANT[FALSE_NEGATIVE]
29+
}
30+
31+
void test_basic_uninit() {
32+
int l1;
33+
use_int(l1); // NON_COMPLIANT
34+
int *l2;
35+
use_int_ptr(l2); // NON_COMPLIANT
36+
struct A *l3;
37+
use_struct_A_ptr(l3); // NON_COMPLIANT
38+
struct A l4;
39+
use_int(l4.m1); // NON_COMPLIANT[FALSE_NEGATIVE] - field is not initialized
40+
int l5[10];
41+
use_int(
42+
l5[0]); // NON_COMPLIANT[FALSE_NEGATIVE] - array entry is not initialized
43+
}
44+
45+
int run1();
46+
47+
void test_conditional(int x) {
48+
49+
int l1; // l1 is defined and used only when x is true
50+
if (x) {
51+
l1 = 0;
52+
}
53+
if (x) {
54+
use_int(l1); // COMPLIANT
55+
}
56+
57+
int l2; // l2 is defined and used only when x is false
58+
if (!x) {
59+
l2 = 0;
60+
}
61+
if (!x) {
62+
use_int(l2); // COMPLIANT
63+
}
64+
65+
int l3 = 0;
66+
int l4;
67+
if (x) {
68+
l3 = 1;
69+
l4 = 1;
70+
}
71+
72+
if (l3) { // l3 true indicates l4 is initialized
73+
use_int(l4); // COMPLIANT
74+
}
75+
76+
int numElements = 0;
77+
int *arrayPtr;
78+
if (x) {
79+
numElements = 5;
80+
arrayPtr = malloc(sizeof(int) * numElements);
81+
}
82+
83+
if (numElements > 0) { // numElements > 0 indicates arrayPtr is initialized
84+
use_int_ptr(arrayPtr); // COMPLIANT[FALSE_POSITIVE]
85+
}
86+
}
87+
88+
void test_non_default_init() {
89+
static int sl;
90+
use_int(sl); // COMPLIANT - static int type variables are zero initialized
91+
static int *slp;
92+
use_int_ptr(
93+
slp); // COMPLIANT - static pointer type variables are zero initialized
94+
static struct A ss;
95+
use_struct_A(
96+
ss); // COMPLIANT - static struct type variables are zero initialized
97+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @id c/misra/object-with-auto-storage-duration-read-before-init
3+
* @name RULE-9-1: The value of an object with automatic storage duration shall not be read before it has been set
4+
* @description Accessing an object before it has been initialized can lead to undefined behavior.
5+
* @kind problem
6+
* @precision medium
7+
* @problem.severity error
8+
* @tags external/misra/id/rule-9-1
9+
* correctness
10+
* security
11+
* external/misra/obligation/mandatory
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.misra
16+
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory
17+
18+
class ObjectWithAutoStorageDurationReadBeforeInitQuery extends ReadOfUninitializedMemorySharedQuery {
19+
ObjectWithAutoStorageDurationReadBeforeInitQuery() {
20+
this = InvalidMemory1Package::objectWithAutoStorageDurationReadBeforeInitQuery()
21+
}
22+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
c/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql

cpp/autosar/src/rules/A5-3-2/NullPointersDereferenced.ql

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@
1414

1515
import cpp
1616
import codingstandards.cpp.autosar
17-
import codingstandards.cpp.lifetimes.lifetimeprofile.LifetimeProfile
17+
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
1818

19-
from NullDereference nd, NullReason nr, string message, Element explanation, string explanationDesc
20-
where
21-
not isExcluded(nd, NullPackage::nullPointersDereferencedQuery()) and
22-
nr = nd.getAnInvalidReason() and
23-
nr.hasMessage(message, explanation, explanationDesc)
24-
select nd, "Null may be dereferenced here " + message, explanation, explanationDesc
19+
class NullPointersDereferencedQuery extends DereferenceOfNullPointerSharedQuery {
20+
NullPointersDereferencedQuery() {
21+
this = NullPackage::nullPointersDereferencedQuery()
22+
}
23+
}

cpp/autosar/test/rules/A5-3-2/NullPointersDereferenced.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cpp/common/test/rules/dereferenceofnullpointer/DereferenceOfNullPointer.ql

cpp/autosar/test/rules/M5-3-2/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ void f() {
88

99
std::uint16_t a = -K; // COMPLIANT
1010
std::int16_t b = -a; // NON_COMPLIANT
11-
std::uint64_t c = K; // COMPLIANTt
11+
std::uint64_t c = K; // COMPLIANT
1212
std::int64_t d = -c; // NON_COMPLIANT
1313
}

0 commit comments

Comments
 (0)