Skip to content

Implement InvalidMemory1 package #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@
"Includes",
"Initialization",
"IntegerConversion",
"InvalidMemory1",
"InvalidMemory2",
"Invariants",
"Iterators",
"Lambdas",
Expand All @@ -231,6 +233,8 @@
"Literals",
"Loops",
"Macros",
"Memory1",
"Memory2",
"Misc",
"MoveForward",
"Naming",
Expand Down
417 changes: 417 additions & 0 deletions c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.md

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @id c/cert/do-not-read-uninitialized-memory
* @name EXP33-C: Do not read uninitialized memory
* @description Using the value of an object with automatic storage duration while it is
* indeterminate is undefined behavior.
* @kind problem
* @precision medium
* @problem.severity error
* @tags external/cert/id/exp33-c
* correctness
* security
* external/cert/obligation/rule
*/

import cpp
import codingstandards.c.cert
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory

class DoNotReadUninitializedMemoryQuery extends ReadOfUninitializedMemorySharedQuery {
DoNotReadUninitializedMemoryQuery() {
this = InvalidMemory1Package::doNotReadUninitializedMemoryQuery()
}
}
219 changes: 219 additions & 0 deletions c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @id c/cert/do-not-dereference-null-pointers
* @name EXP34-C: Do not dereference null pointers
* @description Dereferencing a null pointer leads to undefined behavior.
* @kind problem
* @precision medium
* @problem.severity error
* @tags external/cert/id/exp34-c
* correctness
* external/cert/obligation/rule
*/

import cpp
import codingstandards.c.cert
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer

class DoNotDereferenceNullPointersQuery extends DereferenceOfNullPointerSharedQuery {
DoNotDereferenceNullPointersQuery() {
this = InvalidMemory1Package::doNotDereferenceNullPointersQuery()
}
}
258 changes: 258 additions & 0 deletions c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.md

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @id c/cert/do-not-access-freed-memory
* @name MEM30-C: Do not access freed memory
* @description Accessing memory that has been deallocated is undefined behavior.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/cert/id/mem30-c
* correctness
* security
* external/cert/obligation/rule
*/

import cpp
import codingstandards.c.cert
import codingstandards.cpp.Allocations
import semmle.code.cpp.controlflow.StackVariableReachability

/** `e` is an expression that frees the memory pointed to by `v`. */
predicate isFreeExpr(Expr e, StackVariable v) {
exists(VariableAccess va | va.getTarget() = v and freeExprOrIndirect(e, va, _))
}

/** `e` is an expression that accesses `v` but is not the lvalue of an assignment. */
predicate isAccessExpr(Expr e, StackVariable v) {
v.getAnAccess() = e and
not exists(Assignment a | a.getLValue() = e)
or
isDerefByCallExpr(_, _, e, v)
}

/**
* `va` is passed by value as (part of) the `i`th argument in
* call `c`. The target function is either a library function
* or a source code function that dereferences the relevant
* parameter.
*/
predicate isDerefByCallExpr(Call c, int i, VariableAccess va, StackVariable v) {
v.getAnAccess() = va and
va = c.getAnArgumentSubExpr(i) and
not c.passesByReference(i, va) and
(c.getTarget().hasEntryPoint() implies isAccessExpr(_, c.getTarget().getParameter(i)))
}

class UseAfterFreeReachability extends StackVariableReachability {
UseAfterFreeReachability() { this = "UseAfterFree" }

override predicate isSource(ControlFlowNode node, StackVariable v) { isFreeExpr(node, v) }

override predicate isSink(ControlFlowNode node, StackVariable v) { isAccessExpr(node, v) }

override predicate isBarrier(ControlFlowNode node, StackVariable v) {
definitionBarrier(v, node) or
isFreeExpr(node, v)
}
}

// This query is a modified version of the `UseAfterFree.ql`
// (cpp/use-after-free) query from the CodeQL standard library.
from UseAfterFreeReachability r, StackVariable v, Expr free, Expr e
where
not isExcluded(e, InvalidMemory1Package::doNotAccessFreedMemoryQuery()) and
r.reaches(free, v, e)
select e,
"Pointer '" + v.getName().toString() + "' accessed but may have been previously freed $@.", free,
"here"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/dereferenceofnullpointer/DereferenceOfNullPointer.ql
5 changes: 5 additions & 0 deletions c/cert/test/rules/MEM30-C/DoNotAccessFreedMemory.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
1 change: 1 addition & 0 deletions c/cert/test/rules/MEM30-C/DoNotAccessFreedMemory.qlref
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/MEM30-C/DoNotAccessFreedMemory.ql
38 changes: 38 additions & 0 deletions c/cert/test/rules/MEM30-C/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <stdlib.h>
#include <string.h>

struct node {
struct node *next;
};

void test_freed_loop_var(struct node *list1, struct node *list2) {
struct node *tmp;

for (struct node *p = list1; p != NULL; p = p->next) { // NON_COMPLIANT
free(p);
}

for (struct node *p = list2; p != NULL; p = tmp) { // COMPLIANT
tmp = p->next;
free(p);
}
}

void test_freed_arg(char *input) {
char *buf = (char *)malloc(strlen(input) + 1);
strcpy(buf, input); // COMPLIANT
free(buf);
strcpy(buf, input); // NON_COMPLIANT
}

void test_freed_access_no_deref(char *input) {
char *buf = (char *)malloc(strlen(input) + 1);
strcpy(buf, input); // COMPLIANT
free(buf);
char *tmp = buf; // NON_COMPLIANT
tmp = buf + 1; // NON_COMPLIANT
char *tmp2 = buf; // NON_COMPLIANT
buf = NULL; // COMPLIANT
(char *)buf; // COMPLIANT
tmp2 = buf + 1; // COMPLIANT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer
31 changes: 31 additions & 0 deletions c/common/test/rules/dereferenceofnullpointer/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdlib.h>

void test_null(int p1) {
int *l1 = (void *)0;

if (p1 > 10) {
// l1 is only conditionally initialized
l1 = malloc(10 * sizeof(int));
}

*l1; // NON_COMPLIANT - dereferenced and still null

if (l1) {
*l1; // COMPLIANT - null check before dereference
}

if (!l1) {
*l1; // NON_COMPLIANT - dereferenced and definitely null
} else {
*l1; // COMPLIANT - null check before dereference
}

free(l1); // COMPLIANT - free of `NULL` is not undefined behavior
}

void test_default_value_init() {
int *l1; // indeterminate and thus invalid but non-null state

*l1; // COMPLIANT - considered an uninitialized pointer,
// not a null pointer
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| 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 |
| 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 |
| 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 |
| 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 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory
97 changes: 97 additions & 0 deletions c/common/test/rules/readofuninitializedmemory/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include <stdlib.h>

struct A {
int m1;
};

void use_int(int a);
void use_struct_A(struct A a);
void use_int_ptr(int *a);
void use_struct_A_ptr(struct A *a);

void init_by_pointer(int *pointer_param);

void test_basic_init() {
int l1 = 0;
use_int(l1); // COMPLIANT
struct A l2 = {};
use_struct_A(l2); // COMPLIANT
int l3;
init_by_pointer(&l3);
use_int(l3); // COMPLIANT
struct A l4;
l4.m1 = 1; // COMPLIANT
use_struct_A(l4); // COMPLIANT
int l5[10] = {1, 0};
use_int_ptr(l5); // COMPLIANT
struct A l6;
use_struct_A(l6); // COMPLIANT[FALSE_NEGATIVE]
}

void test_basic_uninit() {
int l1;
use_int(l1); // NON_COMPLIANT
int *l2;
use_int_ptr(l2); // NON_COMPLIANT
struct A *l3;
use_struct_A_ptr(l3); // NON_COMPLIANT
struct A l4;
use_int(l4.m1); // NON_COMPLIANT[FALSE_NEGATIVE] - field is not initialized
int l5[10];
use_int(
l5[0]); // NON_COMPLIANT[FALSE_NEGATIVE] - array entry is not initialized
}

int run1();

void test_conditional(int x) {

int l1; // l1 is defined and used only when x is true
if (x) {
l1 = 0;
}
if (x) {
use_int(l1); // COMPLIANT
}

int l2; // l2 is defined and used only when x is false
if (!x) {
l2 = 0;
}
if (!x) {
use_int(l2); // COMPLIANT
}

int l3 = 0;
int l4;
if (x) {
l3 = 1;
l4 = 1;
}

if (l3) { // l3 true indicates l4 is initialized
use_int(l4); // COMPLIANT
}

int numElements = 0;
int *arrayPtr;
if (x) {
numElements = 5;
arrayPtr = malloc(sizeof(int) * numElements);
}

if (numElements > 0) { // numElements > 0 indicates arrayPtr is initialized
use_int_ptr(arrayPtr); // COMPLIANT[FALSE_POSITIVE]
}
}

void test_non_default_init() {
static int sl;
use_int(sl); // COMPLIANT - static int type variables are zero initialized
static int *slp;
use_int_ptr(
slp); // COMPLIANT - static pointer type variables are zero initialized
static struct A ss;
use_struct_A(
ss); // COMPLIANT - static struct type variables are zero initialized
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @id c/misra/object-with-auto-storage-duration-read-before-init
* @name RULE-9-1: The value of an object with automatic storage duration shall not be read before it has been set
* @description Accessing an object before it has been initialized can lead to undefined behavior.
* @kind problem
* @precision medium
* @problem.severity error
* @tags external/misra/id/rule-9-1
* correctness
* security
* external/misra/obligation/mandatory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory

class ObjectWithAutoStorageDurationReadBeforeInitQuery extends ReadOfUninitializedMemorySharedQuery {
ObjectWithAutoStorageDurationReadBeforeInitQuery() {
this = InvalidMemory1Package::objectWithAutoStorageDurationReadBeforeInitQuery()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql
13 changes: 6 additions & 7 deletions cpp/autosar/src/rules/A5-3-2/NullPointersDereferenced.ql
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@

import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.lifetimes.lifetimeprofile.LifetimeProfile
import codingstandards.cpp.rules.dereferenceofnullpointer.DereferenceOfNullPointer

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cpp/common/test/rules/dereferenceofnullpointer/DereferenceOfNullPointer.ql
2 changes: 1 addition & 1 deletion cpp/autosar/test/rules/M5-3-2/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ void f() {

std::uint16_t a = -K; // COMPLIANT
std::int16_t b = -a; // NON_COMPLIANT
std::uint64_t c = K; // COMPLIANTt
std::uint64_t c = K; // COMPLIANT
std::int64_t d = -c; // NON_COMPLIANT
}
Loading