Skip to content

Commit c4ff2de

Browse files
committed
IntegerOverflow: Implement INT33-C
Adds a query to find div/rem by zero errors.
1 parent 03cb601 commit c4ff2de

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# INT33-C: Ensure that division and remainder operations do not result in divide-by-zero errors
2+
3+
This query implements the CERT-C rule INT33-C:
4+
5+
> Ensure that division and remainder operations do not result in divide-by-zero errors
6+
## CERT
7+
8+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
10+
## Implementation notes
11+
12+
None
13+
14+
## References
15+
16+
* CERT-C: [INT33-C: Ensure that division and remainder operations do not result in divide-by-zero errors](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @id c/cert/div-or-rem-by-zero
3+
* @name INT33-C: Ensure that division and remainder operations do not result in divide-by-zero errors
4+
* @description Dividing or taking the remainder by zero is undefined behavior.
5+
* @kind problem
6+
* @precision high
7+
* @problem.severity error
8+
* @tags external/cert/id/int33-c
9+
* correctness
10+
* external/cert/obligation/rule
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.cert
15+
import semmle.code.cpp.controlflow.Guards
16+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
17+
18+
from BinaryArithmeticOperation divOrMod, Expr divisor
19+
where
20+
not isExcluded(divOrMod, IntegerOverflowPackage::divOrRemByZeroQuery()) and
21+
divOrMod.getOperator() = ["/", "%"] and
22+
divisor = divOrMod.getRightOperand() and
23+
divisor.getType() instanceof IntegralType and
24+
// Range includes 0
25+
upperBound(divisor) >= 0 and
26+
lowerBound(divisor) <= 0 and
27+
// And an explicit check for 0 does not exist
28+
not exists(GuardCondition gc, Expr left, Expr right |
29+
gc.ensuresEq(left, right, 0, divOrMod.getBasicBlock(), false) and
30+
globalValueNumber(left) = globalValueNumber(divisor) and
31+
right.getValue().toInt() = 0
32+
) and
33+
// Uninstantiated templates may not have an accurate reflection of the range
34+
not divOrMod.getEnclosingFunction().isFromUninstantiatedTemplate(_)
35+
select divOrMod,
36+
"Division or remainder expression with divisor that may be zero (divisor range " +
37+
lowerBound(divisor) + "..." + upperBound(divisor) + ")."
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| test.c:4:3:4:9 | ... / ... | Division or remainder expression with divisor that may be zero (divisor range -2147483648...2147483647). |
2+
| test.c:5:3:5:9 | ... % ... | Division or remainder expression with divisor that may be zero (divisor range -2147483648...2147483647). |
3+
| test.c:12:5:12:11 | ... / ... | Division or remainder expression with divisor that may be zero (divisor range -2147483648...2147483647). |
4+
| test.c:13:5:13:11 | ... % ... | Division or remainder expression with divisor that may be zero (divisor range -2147483648...2147483647). |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/INT33-C/DivOrRemByZero.ql

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <limits.h>
2+
3+
void test_simple(signed int i1, signed int i2) {
4+
i1 / i2; // NON_COMPLIANT
5+
i1 % i2; // NON_COMPLIANT
6+
}
7+
8+
void test_incomplete_check(signed int i1, signed int i2) {
9+
if (i1 == INT_MIN && i2 == -1) {
10+
// handle error
11+
} else {
12+
i1 / i2; // NON_COMPLIANT
13+
i1 % i2; // NON_COMPLIANT
14+
}
15+
}
16+
17+
void test_complete_check(signed int i1, signed int i2) {
18+
if (i2 == 0 || (i1 == INT_MIN && i2 == -1)) {
19+
// handle error
20+
} else {
21+
i1 / i2; // COMPLIANT
22+
i1 % i2; // COMPLIANT
23+
}
24+
}
25+
26+
void test_unsigned(unsigned int i1, unsigned int i2) {
27+
if (i2 == 0) {
28+
// handle error
29+
} else {
30+
i1 / i2; // COMPLIANT
31+
i1 % i2; // COMPLIANT
32+
}
33+
}

0 commit comments

Comments
 (0)