Repository navigation
Update dataflow library #1154
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
base: main
Are you sure you want to change the base?
Update dataflow library #1154
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 { | ||
|
|
@@ -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 | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -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] | | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't love relying on this. It doesn't make sense to me why we would say that The missing node is from the definition of I think this is worth probing into more. |
||
| 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) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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*()) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch, and great test case to go with this! Note that this will cause false positives for c17 defines:
It looks like we can basically add |
||
| ) | ||
| or | ||
| conditionAlwaysTrue(expr) and | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we add a test for |
||
| } | ||
|
|
||
| void f5(bool b1) { | ||
|
|
@@ -44,4 +46,6 @@ void f6(int p1) { | |
| } | ||
| while (1 == 0 && p1 > 12) { // NON_COMPLIANT | ||
| } | ||
| while (0 && p1 > 12) { // NON_COMPLIANT | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, nice catch! |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we test an overflowing source? And overflowing dest? |
||
| } | ||
| 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 |
|---|---|---|
| @@ -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. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be wrong. It's worth noting that
StrncatLibraryFunctionis the only class that overrides this predicate, and it's none() for all others, so it appears this was added forstrncatspecifically.