13
13
import cpp
14
14
import codingstandards.c.cert
15
15
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
16
+ import semmle.code.cpp.ir.internal.ASTValueNumbering
16
17
import semmle.code.cpp.controlflow.Guards
17
18
18
19
/*
@@ -34,6 +35,21 @@ class PrecisionMacro extends Macro {
34
35
PrecisionMacro ( ) { this .getName ( ) .toLowerCase ( ) .matches ( "precision" ) }
35
36
}
36
37
38
+ class LiteralZero extends Literal {
39
+ LiteralZero ( ) { this .getValue ( ) = "0" }
40
+ }
41
+
42
+ class BitShiftExpr extends BinaryBitwiseOperation {
43
+ BitShiftExpr ( ) {
44
+ this instanceof LShiftExpr or
45
+ this instanceof RShiftExpr
46
+ }
47
+
48
+ override string toString ( ) {
49
+ if this instanceof LShiftExpr then result = "left-shift" else result = "right-shift"
50
+ }
51
+ }
52
+
37
53
int getPrecision ( BuiltInType type ) {
38
54
type .( CharType ) .isExplicitlyUnsigned ( ) and result = type .( CharType ) .getSize ( ) * 8
39
55
or
@@ -66,80 +82,53 @@ int getPrecision(BuiltInType type) {
66
82
result = type .( LongLongType ) .getSize ( ) * 8 - 1
67
83
}
68
84
69
- predicate isForbiddenLShiftExpr ( LShiftExpr binbitop , string message ) {
85
+ predicate isForbiddenShiftExpr ( BitShiftExpr shift , string message ) {
70
86
(
71
87
(
72
- getPrecision ( binbitop .getLeftOperand ( ) .getUnderlyingType ( ) ) <=
73
- upperBound ( binbitop .getRightOperand ( ) ) and
88
+ getPrecision ( shift .getLeftOperand ( ) .getUnderlyingType ( ) ) <=
89
+ upperBound ( shift .getRightOperand ( ) ) and
74
90
message =
75
- "The operand " + binbitop .getLeftOperand ( ) + " is left-shifted by an expression " +
76
- binbitop .getRightOperand ( ) + " which is greater than or equal to in precision."
91
+ "The operand " + shift .getLeftOperand ( ) + " is " + shift + "ed by an expression " +
92
+ shift .getRightOperand ( ) + " which is greater than or equal to in precision."
77
93
or
78
- lowerBound ( binbitop .getRightOperand ( ) ) < 0 and
94
+ lowerBound ( shift .getRightOperand ( ) ) < 0 and
79
95
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
- */
97
-
98
- not gc .ensuresLt ( binbitop .getRightOperand ( ) , precisionCall , 0 , block , true )
96
+ "The operand " + shift .getLeftOperand ( ) + " is " + shift + "ed by a negative expression " +
97
+ shift .getRightOperand ( ) + "."
99
98
) and
100
- message = "TODO"
101
- )
102
- }
99
+ /*
100
+ * Shift statement is not at a basic block where
101
+ * `shift_rhs < PRECISION(...)` is ensured
102
+ */
103
103
104
- predicate isForbiddenRShiftExpr ( RShiftExpr binbitop , string message ) {
105
- (
106
- (
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 ( ) + "."
117
- )
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
104
+ not exists ( GuardCondition gc , BasicBlock block , Expr precisionCall , Expr lTLhs |
105
+ block = shift .getBasicBlock ( ) and
122
106
(
123
107
precisionCall .( FunctionCall ) .getTarget ( ) instanceof PopCount
124
108
or
125
109
precisionCall = any ( PrecisionMacro pm ) .getAnInvocation ( ) .getExpr ( )
126
110
)
127
111
|
128
- /*
129
- * Shift statement is at a basic block where
130
- * `shift_rhs < PRECISION(...)` is ensured
131
- */
132
-
133
- not gc .ensuresLt ( binbitop .getRightOperand ( ) , precisionCall , 0 , block , true )
112
+ globalValueNumber ( lTLhs ) = globalValueNumber ( shift .getRightOperand ( ) ) and
113
+ gc .ensuresLt ( lTLhs , precisionCall , 0 , block , true )
134
114
) and
135
- message = "TODO"
115
+ /*
116
+ * Shift statement is not at a basic block where
117
+ * `shift_rhs < 0` is ensured
118
+ */
119
+
120
+ not exists ( GuardCondition gc , BasicBlock block , Expr literalZero , Expr lTLhs |
121
+ block = shift .getBasicBlock ( ) and
122
+ literalZero instanceof LiteralZero
123
+ |
124
+ globalValueNumber ( lTLhs ) = globalValueNumber ( shift .getRightOperand ( ) ) and
125
+ gc .ensuresLt ( lTLhs , literalZero , 0 , block , true )
126
+ )
136
127
)
137
128
}
138
129
139
130
from BinaryBitwiseOperation badShift , string message
140
131
where
141
132
not isExcluded ( badShift , TypesPackage:: exprShiftedbyNegativeOrGreaterPrecisionOperandQuery ( ) ) and
142
- isForbiddenLShiftExpr ( badShift , message )
143
- or
144
- isForbiddenRShiftExpr ( badShift , message )
133
+ isForbiddenShiftExpr ( badShift , message )
145
134
select badShift , message
0 commit comments