Skip to content

Commit 99a21b1

Browse files
committed
Checkpoint: INT34-C
1 parent 3bec0e6 commit 99a21b1

File tree

2 files changed

+3226
-559
lines changed

2 files changed

+3226
-559
lines changed

c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,72 +12,134 @@
1212

1313
import cpp
1414
import codingstandards.c.cert
15+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
16+
import semmle.code.cpp.controlflow.Guards
1517

1618
/*
17-
* Precision predicate based on a sample implementaion from
19+
* Precision predicate based on a sample implementation from
1820
* https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions
1921
*/
2022

23+
/**
24+
* A function whose name is suggestive that it counts the number of bits set.
25+
*/
26+
class PopCount extends Function {
27+
PopCount() { this.getName().toLowerCase().matches("%popc%nt%") }
28+
}
29+
30+
/**
31+
* A macro which is suggestive that it is used to determine the precision of an integer.
32+
*/
33+
class PrecisionMacro extends Macro {
34+
PrecisionMacro() { this.getName().toLowerCase().matches("precision") }
35+
}
36+
2137
int getPrecision(BuiltInType type) {
22-
type.(CharType).isExplicitlyUnsigned() and result = 8
38+
type.(CharType).isExplicitlyUnsigned() and result = type.(CharType).getSize() * 8
2339
or
24-
type.(ShortType).isExplicitlyUnsigned() and result = 16
40+
type.(ShortType).isExplicitlyUnsigned() and result = type.(ShortType).getSize() * 8
2541
or
26-
type.(IntType).isExplicitlyUnsigned() and result = 32
42+
type.(IntType).isExplicitlyUnsigned() and result = type.(IntType).getSize() * 8
2743
or
28-
type.(LongType).isExplicitlyUnsigned() and result = 32
44+
type.(LongType).isExplicitlyUnsigned() and result = type.(LongType).getSize() * 8
2945
or
30-
type.(LongLongType).isExplicitlyUnsigned() and result = 64
46+
type.(LongLongType).isExplicitlyUnsigned() and result = type.(LongLongType).getSize() * 8
3147
or
32-
type instanceof CharType and not type.(CharType).isExplicitlyUnsigned() and result = 7
48+
type instanceof CharType and
49+
not type.(CharType).isExplicitlyUnsigned() and
50+
result = type.(CharType).getSize() * 8 - 1
3351
or
34-
type instanceof ShortType and not type.(ShortType).isExplicitlyUnsigned() and result = 15
52+
type instanceof ShortType and
53+
not type.(ShortType).isExplicitlyUnsigned() and
54+
result = type.(ShortType).getSize() * 8 - 1
3555
or
36-
type instanceof IntType and not type.(IntType).isExplicitlyUnsigned() and result = 31
56+
type instanceof IntType and
57+
not type.(IntType).isExplicitlyUnsigned() and
58+
result = type.(IntType).getSize() * 8 - 1
3759
or
38-
type instanceof LongType and not type.(LongType).isExplicitlyUnsigned() and result = 31
60+
type instanceof LongType and
61+
not type.(LongType).isExplicitlyUnsigned() and
62+
result = type.(LongType).getSize() * 8 - 1
3963
or
40-
type instanceof LongLongType and not type.(LongLongType).isExplicitlyUnsigned() and result = 63
64+
type instanceof LongLongType and
65+
not type.(LongLongType).isExplicitlyUnsigned() and
66+
result = type.(LongLongType).getSize() * 8 - 1
4167
}
4268

43-
/* The -1 number literal. */
44-
class MinusNumberLiteral extends UnaryMinusExpr {
45-
MinusNumberLiteral() { this.getOperand() instanceof Literal }
69+
predicate isForbiddenLShiftExpr(LShiftExpr binbitop, string message) {
70+
(
71+
(
72+
getPrecision(binbitop.getLeftOperand().getUnderlyingType()) <=
73+
upperBound(binbitop.getRightOperand()) and
74+
message =
75+
"The operand " + binbitop.getLeftOperand() + " is left-shifted by an expression " +
76+
binbitop.getRightOperand() + " which is greater than or equal to in precision."
77+
or
78+
lowerBound(binbitop.getRightOperand()) < 0 and
79+
message =
80+
"The operand " + binbitop.getLeftOperand() + " is left-shifted by a negative expression " +
81+
binbitop.getRightOperand() + "."
82+
)
83+
or
84+
/* Check a guard condition protecting the shift statement: heuristic (not an iff query) */
85+
exists(GuardCondition gc, BasicBlock block, Expr precisionCall |
86+
block = binbitop.getBasicBlock() and
87+
(
88+
precisionCall.(FunctionCall).getTarget() instanceof PopCount
89+
or
90+
precisionCall = any(PrecisionMacro pm).getAnInvocation().getExpr()
91+
)
92+
|
93+
/*
94+
* Shift statement is at a basic block where
95+
* `shift_rhs < PRECISION(...)` is ensured
96+
*/
4697

47-
override string toString() { result = "-" + this.getOperand().toString() }
98+
not gc.ensuresLt(binbitop.getRightOperand(), precisionCall, 0, block, true)
99+
) and
100+
message = "TODO"
101+
)
48102
}
49103

50-
class ForbiddenShiftExpr extends BinaryBitwiseOperation {
51-
ForbiddenShiftExpr() {
104+
predicate isForbiddenRShiftExpr(RShiftExpr binbitop, string message) {
105+
(
52106
(
53-
/* First Case: Precision mismatch between operands */
54-
getPrecision(this.(LShiftExpr).getLeftOperand().getUnderlyingType()) <=
55-
getPrecision(this.(LShiftExpr).getRightOperand().getUnderlyingType()) or
56-
getPrecision(this.(RShiftExpr).getLeftOperand().getUnderlyingType()) <=
57-
getPrecision(this.(RShiftExpr).getRightOperand().getUnderlyingType()) or
58-
/* Second Case: Shifting by a negative number literal */
59-
this.(LShiftExpr).getRightOperand() instanceof MinusNumberLiteral or
60-
this.(RShiftExpr).getRightOperand() instanceof MinusNumberLiteral
107+
getPrecision(binbitop.getLeftOperand().getUnderlyingType()) <=
108+
upperBound(binbitop.getRightOperand()) and
109+
message =
110+
"The operand " + binbitop.getLeftOperand() + " is right-shifted by an expression " +
111+
binbitop.getRightOperand() + " which is greater than or equal to in precision."
112+
or
113+
lowerBound(binbitop.getRightOperand()) < 0 and
114+
message =
115+
"The operand " + binbitop.getLeftOperand() + " is right-shifted by a negative expression " +
116+
binbitop.getRightOperand() + "."
61117
)
62-
}
118+
or
119+
/* Check a guard condition protecting the shift statement: heuristic (not an iff query) */
120+
exists(GuardCondition gc, BasicBlock block, Expr precisionCall |
121+
block = binbitop.getBasicBlock() and
122+
(
123+
precisionCall.(FunctionCall).getTarget() instanceof PopCount
124+
or
125+
precisionCall = any(PrecisionMacro pm).getAnInvocation().getExpr()
126+
)
127+
|
128+
/*
129+
* Shift statement is at a basic block where
130+
* `shift_rhs < PRECISION(...)` is ensured
131+
*/
63132

64-
/* Second Case: Shifting by a negative number literal */
65-
predicate hasNegativeOperand() {
66-
this.(LShiftExpr).getRightOperand() instanceof MinusNumberLiteral or
67-
this.(RShiftExpr).getRightOperand() instanceof MinusNumberLiteral
68-
}
133+
not gc.ensuresLt(binbitop.getRightOperand(), precisionCall, 0, block, true)
134+
) and
135+
message = "TODO"
136+
)
69137
}
70138

71-
from ForbiddenShiftExpr badShift, string message
139+
from BinaryBitwiseOperation badShift, string message
72140
where
73141
not isExcluded(badShift, TypesPackage::exprShiftedbyNegativeOrGreaterPrecisionOperandQuery()) and
74-
if badShift.hasNegativeOperand()
75-
then
76-
message =
77-
"The operand " + badShift.getLeftOperand() + " is shifted by a negative expression " +
78-
badShift.getRightOperand() + "."
79-
else
80-
message =
81-
"The operand " + badShift.getLeftOperand() + " is shifted by an expression " +
82-
badShift.getRightOperand() + " which is greater than or equal to in precision."
142+
isForbiddenLShiftExpr(badShift, message)
143+
or
144+
isForbiddenRShiftExpr(badShift, message)
83145
select badShift, message

0 commit comments

Comments
 (0)