Skip to content

Commit cd36b7f

Browse files
committed
fix OutOfBounds behavior with new dataflow
1 parent aaabfc3 commit cd36b7f

11 files changed

Lines changed: 108 additions & 88 deletions

File tree

‎c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ where
9191
) and
9292
// A conversion of `-1` to `time_t` is permitted by the standard
9393
not (
94-
c.getType().hasName("time_t") and
94+
c.getType().getUnspecifiedType().hasName("time_t") and
9595
preConversionExpr.getValue() = "-1"
9696
) and
9797
// Conversion to unsigned char is permitted from the range [SCHAR_MIN..UCHAR_MAX], as those can

‎c/cert/test/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.expected‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
| 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 |
66
| 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 |
77
| 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 |
8+
| 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 |
9+
| 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 |
10+
| 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 |
811
| 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 |
912
| 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 |
1013
| 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 |
14+
| 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 |
15+
| 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 |
16+
| 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 |
1117
| 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 |

‎c/common/src/codingstandards/c/OutOfBounds.qll‎

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,13 @@ module OOB {
379379
StrncatLibraryFunction() { this.getName() = getNameOrInternalName(["strncat", "wcsncat"]) }
380380

381381
override predicate getALengthParameterIndex(int i) {
382-
// `strncat` and `wcsncat` exclude the size of a null terminator
383-
i = 2
382+
// The source need not contain a null terminator within the first `n` characters.
383+
none()
384+
}
385+
386+
override predicate getANullTerminatedParameterIndex(int i) {
387+
// The destination must be null-terminated.
388+
i = 0
384389
}
385390
}
386391

@@ -644,42 +649,46 @@ module OOB {
644649
}
645650

646651
/**
647-
* A class for reasoning about the offset of a variable from the original value flowing to it
648-
* as a result of arithmetic or pointer arithmetic expressions.
652+
* Gets the offset of `expr` from `underlyingBase` due to arithmetic or pointer arithmetic.
653+
*
654+
* `underlyingBase` may be the arithmetic operand's base expression or `expr` itself, allowing
655+
* callers to use whichever dataflow node is available.
649656
*/
650657
bindingset[expr]
651-
private int getArithmeticOffsetValue(Expr expr, Expr base) {
652-
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
653-
base = expr.(PointerArithmeticExpr).getPointer()
654-
or
655-
// &(array[index]) expressions
656-
result =
657-
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
658-
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
659-
or
660-
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
661-
base = expr.(AddExpr).getLeftOperand()
662-
or
663-
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
664-
base = expr.(SubExpr).getLeftOperand()
665-
or
666-
expr instanceof IncrementOperation and
667-
result = 1 and
668-
base = expr.(IncrementOperation).getOperand()
669-
or
670-
expr instanceof DecrementOperation and
671-
result = -1 and
672-
base = expr.(DecrementOperation).getOperand()
673-
or
674-
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
675-
not expr instanceof PointerArithmeticExpr and
676-
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
677-
not expr instanceof AddExpr and
678-
not expr instanceof SubExpr and
679-
not expr instanceof IncrementOperation and
680-
not expr instanceof DecrementOperation and
681-
base = expr and
682-
result = 0
658+
private int getArithmeticOffsetValue(Expr expr, Expr underlyingBase) {
659+
exists(Expr base | underlyingBase = [base, expr] |
660+
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
661+
base = expr.(PointerArithmeticExpr).getPointer()
662+
or
663+
// &(array[index]) expressions
664+
result =
665+
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
666+
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
667+
or
668+
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
669+
base = expr.(AddExpr).getLeftOperand()
670+
or
671+
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
672+
base = expr.(SubExpr).getLeftOperand()
673+
or
674+
expr instanceof IncrementOperation and
675+
result = 1 and
676+
base = expr.(IncrementOperation).getOperand()
677+
or
678+
expr instanceof DecrementOperation and
679+
result = -1 and
680+
base = expr.(DecrementOperation).getOperand()
681+
or
682+
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
683+
not expr instanceof PointerArithmeticExpr and
684+
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
685+
not expr instanceof AddExpr and
686+
not expr instanceof SubExpr and
687+
not expr instanceof IncrementOperation and
688+
not expr instanceof DecrementOperation and
689+
base = expr and
690+
result = 0
691+
)
683692
}
684693

685694
private int constOrZero(Expr e) {

‎c/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
problems
2-
| 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. |
32
| 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. |
43
| 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. |
54
| 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. |

‎c/misra/test/rules/RULE-21-18/test.c‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,10 @@ void test(void) {
103103
strxfrm(buf + 1, buf2,
104104
sizeof(buf) - 1); // NON_COMPLIANT - not null-terminated
105105
}
106-
}
106+
}
107+
108+
void test_strncat_bounded_source(void) {
109+
char destination[2] = {0};
110+
char source[1] = {'x'};
111+
strncat(destination, source, 1); // COMPLIANT
112+
}
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,2 @@
1-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:64,5-13)
2-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:87,46-54)
3-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:88,22-30)
4-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:92,20-28)
5-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:97,35-43)
6-
WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:102,38-46)
71
| test.cpp:24:7:24:34 | new | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:24:7:24:34 | new | StructA * |
82
| test.cpp:40:17:40:38 | call to allocate_without_check | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:35:17:35:44 | new | StructA * |

‎cpp/common/src/codingstandards/cpp/OutOfBounds.qll‎

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -384,16 +384,13 @@ module OOB {
384384
StrncatLibraryFunction() { this.getName() = getNameOrInternalName(["strncat", "wcsncat"]) }
385385

386386
override predicate getALengthParameterIndex(int i) {
387-
// `strncat` and `wcsncat` exclude the size of a null terminator, but
388-
// both stops copying right after the null terminator is encountered.
389-
// In fact, they don't care if the source buffer is null-terminated
390-
// or not.
387+
// The source need not contain a null terminator within the first `n` characters.
391388
none()
392389
}
393390

394391
override predicate getANullTerminatedParameterIndex(int i) {
395-
// `strncat` does not require null-terminated parameters
396-
none()
392+
// The destination must be null-terminated.
393+
i = 0
397394
}
398395
}
399396

@@ -657,42 +654,46 @@ module OOB {
657654
}
658655

659656
/**
660-
* A class for reasoning about the offset of a variable from the original value flowing to it
661-
* as a result of arithmetic or pointer arithmetic expressions.
657+
* Gets the offset of `expr` from `underlyingBase` due to arithmetic or pointer arithmetic.
658+
*
659+
* `underlyingBase` may be the arithmetic operand's base expression or `expr` itself, allowing
660+
* callers to use whichever dataflow node is available.
662661
*/
663662
bindingset[expr]
664-
private int getArithmeticOffsetValue(Expr expr, Expr base) {
665-
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
666-
base = expr.(PointerArithmeticExpr).getPointer()
667-
or
668-
// &(array[index]) expressions
669-
result =
670-
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
671-
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
672-
or
673-
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
674-
base = expr.(AddExpr).getLeftOperand()
675-
or
676-
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
677-
base = expr.(SubExpr).getLeftOperand()
678-
or
679-
expr instanceof IncrementOperation and
680-
result = 1 and
681-
base = expr.(IncrementOperation).getOperand()
682-
or
683-
expr instanceof DecrementOperation and
684-
result = -1 and
685-
base = expr.(DecrementOperation).getOperand()
686-
or
687-
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
688-
not expr instanceof PointerArithmeticExpr and
689-
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
690-
not expr instanceof AddExpr and
691-
not expr instanceof SubExpr and
692-
not expr instanceof IncrementOperation and
693-
not expr instanceof DecrementOperation and
694-
base = expr and
695-
result = 0
663+
private int getArithmeticOffsetValue(Expr expr, Expr underlyingBase) {
664+
exists(Expr base | underlyingBase = [base, expr] |
665+
result = getMinStatedValue(expr.(PointerArithmeticExpr).getOperand()) and
666+
base = expr.(PointerArithmeticExpr).getPointer()
667+
or
668+
// &(array[index]) expressions
669+
result =
670+
getMinStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) and
671+
base = expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getPointer()
672+
or
673+
result = getMinStatedValue(expr.(AddExpr).getRightOperand()) and
674+
base = expr.(AddExpr).getLeftOperand()
675+
or
676+
result = -getMinStatedValue(expr.(SubExpr).getRightOperand()) and
677+
base = expr.(SubExpr).getLeftOperand()
678+
or
679+
expr instanceof IncrementOperation and
680+
result = 1 and
681+
base = expr.(IncrementOperation).getOperand()
682+
or
683+
expr instanceof DecrementOperation and
684+
result = -1 and
685+
base = expr.(DecrementOperation).getOperand()
686+
or
687+
// fall-back if `expr` is not an arithmetic or pointer arithmetic expression
688+
not expr instanceof PointerArithmeticExpr and
689+
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
690+
not expr instanceof AddExpr and
691+
not expr instanceof SubExpr and
692+
not expr instanceof IncrementOperation and
693+
not expr instanceof DecrementOperation and
694+
base = expr and
695+
result = 0
696+
)
696697
}
697698

698699
private int constOrZero(Expr e) {

‎cpp/common/src/codingstandards/cpp/Overflow.qll‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import cpp
66
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
77
import SimpleRangeAnalysisCustomizations
88
import semmle.code.cpp.controlflow.Guards
9-
import semmle.code.cpp.dataflow.TaintTracking
9+
import semmle.code.cpp.dataflow.new.TaintTracking
1010
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
1111
import codingstandards.cpp.Expr
1212
import codingstandards.cpp.UndefinedBehavior

‎cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
problems
2-
| test.cpp:11:7:11:12 | * ... | test.cpp:18:16:18:21 | call to getenv | test.cpp:11:7:11:12 | * ... | The object returned by the function getenv should not be modified. |
32
| test.cpp:11:8:11:12 | c_str | test.cpp:18:16:18:21 | call to getenv | test.cpp:11:7:11:12 | * ... | The object returned by the function getenv should not be modified. |
43
| test.cpp:67:5:67:9 | conv4 | test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | The object returned by the function localeconv should not be modified. |
54
| test.cpp:76:5:76:8 | conv | test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | The object returned by the function localeconv should not be modified. |

‎cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.expected‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@
3737
| test.cpp:477:5:477:10 | call to memcpy | The size of the $@ passed to memcpy is 63 bytes, but the $@ is 128 bytes. | test.cpp:477:17:477:24 | ... + ... | read buffer | test.cpp:477:27:477:41 | ... * ... | size argument |
3838
| test.cpp:477:5:477:10 | call to memcpy | The size of the $@ passed to memcpy is 64 bytes, but the $@ is 128 bytes. | test.cpp:477:12:477:14 | buf | write buffer | test.cpp:477:27:477:41 | ... * ... | size argument |
3939
| test.cpp:484:3:484:8 | call to memcpy | The $@ passed to memcpy is accessed at an excessive offset of 1 element(s) from the $@. | test.cpp:484:10:484:10 | p | write buffer | test.cpp:482:30:482:50 | ... * ... | allocation size base |
40+
| test.cpp:552:3:552:9 | call to strncat | The $@ passed to strncat might not be null-terminated. | test.cpp:552:11:552:21 | destination | argument | test.cpp:552:11:552:21 | destination | |

0 commit comments

Comments
 (0)