Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import cpp
import codingstandards.c.cert
import codingstandards.cpp.SideEffect
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.dataflow.new.TaintTracking
import semmle.code.cpp.valuenumbering.GlobalValueNumbering

/** Holds if the function's return value is derived from the `AliasParamter` p. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
| test.c:45:17:45:30 | ... + ... | Buffer may access up to offset 101*1 which is greater than the fixed size 100 of the $@. | test.c:45:17:45:22 | buffer | buffer |
| test.c:55:5:55:13 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:55:5:55:9 | ptr16 | buffer |
| test.c:57:5:57:14 | ... + ... | Buffer accesses offset 22 which is greater than the fixed size 20 of the $@. | test.c:57:5:57:9 | ptr16 | buffer |
| test.c:58:5:58:14 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:55:5:55:9 | ptr16 | buffer |
| test.c:58:5:58:14 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:56:5:56:9 | ptr16 | buffer |
| test.c:58:5:58:14 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:57:5:57:9 | ptr16 | buffer |
| test.c:58:5:58:14 | ... - ... | Buffer access may be to a negative index in the buffer. | test.c:58:5:58:9 | ptr16 | buffer |
| test.c:63:3:63:9 | access to array | Buffer access may be to a negative index in the buffer. | test.c:63:3:63:5 | arr | buffer |
| test.c:65:3:65:9 | access to array | Buffer accesses offset 44 which is greater than the fixed size 40 of the $@. | test.c:65:3:65:5 | arr | buffer |
| test.c:66:3:66:10 | access to array | Buffer access may be to a negative index in the buffer. | test.c:63:3:63:5 | arr | buffer |
| test.c:66:3:66:10 | access to array | Buffer access may be to a negative index in the buffer. | test.c:64:3:64:5 | arr | buffer |
| test.c:66:3:66:10 | access to array | Buffer access may be to a negative index in the buffer. | test.c:65:3:65:5 | arr | buffer |
| test.c:66:3:66:10 | access to array | Buffer access may be to a negative index in the buffer. | test.c:66:3:66:5 | arr | buffer |
Original file line number Diff line number Diff line change
@@ -1,25 +1 @@
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,31-39)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,59-67)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,57-65)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,33-41)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,59-67)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,5-13)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,25-33)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,53-61)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,31-39)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,57-65)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,31-39)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,55-63)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,31-39)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,57-65)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,31-39)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,55-63)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,5-18)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,7-20)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,5-18)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,5-18)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,5-18)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,5-18)
| test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 |
82 changes: 45 additions & 37 deletions c/common/src/codingstandards/c/OutOfBounds.qll
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import codingstandards.cpp.Allocations
import codingstandards.cpp.Overflow
import codingstandards.cpp.PossiblyUnsafeStringOperation
import codingstandards.cpp.SimpleRangeAnalysisCustomizations
private import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.valuenumbering.GlobalValueNumbering

module OOB {
Expand Down Expand Up @@ -380,8 +379,13 @@ module OOB {
StrncatLibraryFunction() { this.getName() = getNameOrInternalName(["strncat", "wcsncat"]) }

override predicate getALengthParameterIndex(int i) {
// `strncat` and `wcsncat` exclude the size of a null terminator
i = 2
// The source need not contain a null terminator within the first `n` characters.
none()
}

override predicate getANullTerminatedParameterIndex(int i) {
// The destination must be null-terminated.
i = 0
}
}

Expand Down Expand Up @@ -645,42 +649,46 @@ module OOB {
}

/**
* A class for reasoning about the offset of a variable from the original value flowing to it
* as a result of arithmetic or pointer arithmetic expressions.
* Gets the offset of `expr` from `underlyingBase` due to arithmetic or pointer arithmetic.
*
* `underlyingBase` may be the arithmetic operand's base expression or `expr` itself, allowing
* callers to use whichever dataflow node is available.
*/
bindingset[expr]
private int getArithmeticOffsetValue(Expr expr, Expr base) {
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
base = expr.(PointerArithmeticExpr).getPointer()
or
// &(array[index]) expressions
result =
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
or
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
base = expr.(AddExpr).getLeftOperand()
or
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
base = expr.(SubExpr).getLeftOperand()
or
expr instanceof IncrementOperation and
result = 1 and
base = expr.(IncrementOperation).getOperand()
or
expr instanceof DecrementOperation and
result = -1 and
base = expr.(DecrementOperation).getOperand()
or
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
not expr instanceof PointerArithmeticExpr and
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
not expr instanceof AddExpr and
not expr instanceof SubExpr and
not expr instanceof IncrementOperation and
not expr instanceof DecrementOperation and
base = expr and
result = 0
private int getArithmeticOffsetValue(Expr expr, Expr underlyingBase) {
exists(Expr base | underlyingBase = [base, expr] |
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
base = expr.(PointerArithmeticExpr).getPointer()
or
// &(array[index]) expressions
result =
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
or
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
base = expr.(AddExpr).getLeftOperand()
or
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
base = expr.(SubExpr).getLeftOperand()
or
expr instanceof IncrementOperation and
result = 1 and
base = expr.(IncrementOperation).getOperand()
or
expr instanceof DecrementOperation and
result = -1 and
base = expr.(DecrementOperation).getOperand()
or
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
not expr instanceof PointerArithmeticExpr and
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
not expr instanceof AddExpr and
not expr instanceof SubExpr and
not expr instanceof IncrementOperation and
not expr instanceof DecrementOperation and
base = expr and
result = 0
)
}

private int constOrZero(Expr e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
problems
| test.c:11:7:11:12 | * ... | test.c:18:16:18:21 | call to getenv | test.c:11:7:11:12 | * ... | The object returned by the function getenv should not be modified. |
| test.c:11:8:11:12 | c_str | test.c:18:16:18:21 | call to getenv | test.c:11:7:11:12 | * ... | The object returned by the function getenv should not be modified. |
| test.c:67:5:67:9 | conv4 | test.c:64:11:64:20 | call to localeconv | test.c:67:5:67:9 | conv4 | The object returned by the function localeconv should not be modified. |
| test.c:76:5:76:8 | conv | test.c:72:25:72:34 | call to localeconv | test.c:76:5:76:8 | conv | The object returned by the function localeconv should not be modified. |
Expand Down
4 changes: 3 additions & 1 deletion c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ where
conditionAlwaysFalse(expr) and
not (
getEssentialTypeCategory(getEssentialType(expr)) instanceof EssentiallyBooleanType and
expr.getValue() = "0"
expr.getValue() = "0" and
// Only apply to expressions that do not reference variables.
not exists(VariableAccess va | va = expr.getAChild*())
)
or
conditionAlwaysTrue(expr) and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
| test.c:16:9:16:13 | ... > ... | Controlling expression in if statement has an invariant value. |
| test.c:20:20:20:24 | ... < ... | Controlling expression in loop statement has an invariant value. |
| test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has an invariant value. |
| test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has an invariant value. |
| test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has an invariant value. |
| test.c:45:10:45:26 | ... && ... | Controlling expression in loop statement has an invariant value. |
| test.c:35:12:35:12 | 0 | Controlling expression in loop statement has an invariant value. |
| test.c:39:3:39:6 | 1 | Controlling expression in conditional statement has an invariant value. |
| test.c:40:3:40:3 | 1 | Controlling expression in conditional statement has an invariant value. |
| test.c:47:10:47:26 | ... && ... | Controlling expression in loop statement has an invariant value. |
| test.c:49:10:49:21 | ... && ... | Controlling expression in loop statement has an invariant value. |
8 changes: 6 additions & 2 deletions c/misra/test/rules/RULE-14-3/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ void f1(int p1) {

void f2() {
while (20 > 10) { // NON_COMPLIANT
if (1 > 2) {
} // NON_COMPLIANT
if (1 > 2) { // NON_COMPLIANT
}
}

for (int i = 10; i < 5; i++) { // NON_COMPLIANT
Expand All @@ -31,6 +31,8 @@ void f3() {
void f4() {
do {
} while (0u == 1u); // COMPLIANT - by exception 2
do {
} while (0); // NON_COMPLIANT - a bare literal `0` is not essentially Boolean
}

void f5(bool b1) {
Expand All @@ -44,4 +46,6 @@ void f6(int p1) {
}
while (1 == 0 && p1 > 12) { // NON_COMPLIANT
}
while (0 && p1 > 12) { // NON_COMPLIANT
}
}
8 changes: 7 additions & 1 deletion c/misra/test/rules/RULE-21-18/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,10 @@ void test(void) {
strxfrm(buf + 1, buf2,
sizeof(buf) - 1); // NON_COMPLIANT - not null-terminated
}
}
}

void test_strncat_bounded_source(void) {
char destination[2] = {0};
char source[1] = {'x'};
strncat(destination, source, 1); // COMPLIANT
}
9 changes: 9 additions & 0 deletions change_notes/2026-08-28-cpp-all-upgrade-result-changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- `ENV30-C`, `RULE-21-19`, `RULE-25-5-2`: removed duplicate alerts for the same modification of a
pointer returned by an environment or locale function.
- `RULE-14-3`: loop controlling expressions with an invariant false value are now reported when
they use the integer literal `0`, including within compound expressions.
- `ARR30-C`: negative out-of-bounds accesses may now produce a result for each reaching buffer
expression.
- `ARR38-C`, `RULE-21-17`, `RULE-21-18`, `RULE-8-7-1`: corrected the modeling of `strncat` and
`wcsncat`. Their destination must be null-terminated, while their source does not need a null
terminator within the specified character limit.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import cpp
import codingstandards.cpp.autosar
import codingstandards.cpp.SmartPointers
import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.dataflow.new.TaintTracking
import SingleObjectSmartPointerArrayConstructionFlow::PathGraph

class AutosarSmartPointerArraySpecialisation extends AutosarSmartPointer {
Expand All @@ -32,7 +32,7 @@ module SingleObjectSmartPointerArrayConstructionConfig implements DataFlow::Conf
mf.getDeclaringType() instanceof AutosarSmartPointerArraySpecialisation and
mf instanceof AutosarSmartPointerReleaseMemberFunction
|
fc.getParent()
fc
)
}

Expand All @@ -47,21 +47,14 @@ module SingleObjectSmartPointerArrayConstructionConfig implements DataFlow::Conf
)
}

predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) {
exists(AutosarUniquePointer sp, FunctionCall fc |
fc = sp.getAReleaseCall() and
source.asExpr() = fc.getQualifier() and
sink.asExpr() = fc
)
}

predicate isBarrierIn(DataFlow::Node node) {
// Exclude flow into header files outside the source archive which are summarized by the
// additional taint steps above.
// Exclude flow through `release()` implementations summarized by its taint model.
exists(AutosarUniquePointer sp |
sp.getAReleaseCall().getTarget() = node.asExpr().(ThisExpr).getEnclosingFunction()
|
not exists(node.getLocation().getFile().getRelativePath())
sp.getAReleaseCall().getTarget() =
[
node.asExpr().(ThisExpr).getEnclosingFunction(),
node.asIndirectExpr().(ThisExpr).getEnclosingFunction()
]
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:26,67-75)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:27,22-30)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:39,20-28)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,34-42)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,57-65)
WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:58,25-33)
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:70,3-16)
edges
| test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | provenance | |
| test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | provenance | |
| test.cpp:3:36:3:45 | new[] | test.cpp:27:20:27:37 | call to allocate_int_array | provenance | |
| test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:27:12:28 | v2 | provenance | |
| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | |
| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | Config |
| test.cpp:3:6:3:23 | *allocate_int_array | test.cpp:19:27:19:44 | call to allocate_int_array | provenance | |
| test.cpp:3:6:3:23 | *allocate_int_array | test.cpp:23:12:23:29 | call to allocate_int_array | provenance | |
| test.cpp:3:6:3:23 | *allocate_int_array | test.cpp:27:20:27:37 | call to allocate_int_array | provenance | |
| test.cpp:3:36:3:45 | new[] | test.cpp:3:6:3:23 | *allocate_int_array | provenance | |
| test.cpp:3:36:3:45 | new[] | test.cpp:3:36:3:45 | new[] | provenance | |
| test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:27:20:27:37 | call to allocate_int_array | provenance | |
| test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:32:12:32:20 | int_array | provenance | |
nodes
| test.cpp:3:6:3:23 | *allocate_int_array | semmle.label | *allocate_int_array |
| test.cpp:3:36:3:45 | new[] | semmle.label | new[] |
| test.cpp:3:36:3:45 | new[] | semmle.label | new[] |
| test.cpp:11:29:11:41 | call to unique_ptr | semmle.label | call to unique_ptr |
| test.cpp:12:27:12:28 | v2 | semmle.label | v2 |
| test.cpp:12:30:12:36 | call to release | semmle.label | call to release |
| test.cpp:19:27:19:44 | call to allocate_int_array | semmle.label | call to allocate_int_array |
| test.cpp:23:12:23:29 | call to allocate_int_array | semmle.label | call to allocate_int_array |
| test.cpp:27:20:27:37 | call to allocate_int_array | semmle.label | call to allocate_int_array |
| test.cpp:27:20:27:37 | call to allocate_int_array | semmle.label | call to allocate_int_array |
| test.cpp:32:12:32:20 | int_array | semmle.label | int_array |
subpaths
#select
| test.cpp:12:30:12:36 | call to release | test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:30:12:36 | call to release | A pointer to an element of an array of objects flows to a smart pointer of a single object type. |
| test.cpp:12:30:12:36 | call to release | test.cpp:12:30:12:36 | call to release | test.cpp:12:30:12:36 | call to release | A pointer to an element of an array of objects flows to a smart pointer of a single object type. |
| test.cpp:19:27:19:44 | call to allocate_int_array | test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | A pointer to an element of an array of objects flows to a smart pointer of a single object type. |
| test.cpp:23:12:23:29 | call to allocate_int_array | test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | A pointer to an element of an array of objects flows to a smart pointer of a single object type. |
| test.cpp:32:12:32:20 | int_array | test.cpp:3:36:3:45 | new[] | test.cpp:32:12:32:20 | int_array | A pointer to an element of an array of objects flows to a smart pointer of a single object type. |
Loading
Loading