1313import cpp
1414import codingstandards.c.cert
1515import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
16+ import semmle.code.cpp.ir.internal.ASTValueNumbering
1617import semmle.code.cpp.controlflow.Guards
1718
1819/*
@@ -34,6 +35,21 @@ class PrecisionMacro extends Macro {
3435 PrecisionMacro ( ) { this .getName ( ) .toLowerCase ( ) .matches ( "precision" ) }
3536}
3637
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+
3753int getPrecision ( BuiltInType type ) {
3854 type .( CharType ) .isExplicitlyUnsigned ( ) and result = type .( CharType ) .getSize ( ) * 8
3955 or
@@ -66,80 +82,53 @@ int getPrecision(BuiltInType type) {
6682 result = type .( LongLongType ) .getSize ( ) * 8 - 1
6783}
6884
69- predicate isForbiddenLShiftExpr ( LShiftExpr binbitop , string message ) {
85+ predicate isForbiddenShiftExpr ( BitShiftExpr shift , string message ) {
7086 (
7187 (
72- getPrecision ( binbitop .getLeftOperand ( ) .getUnderlyingType ( ) ) <=
73- upperBound ( binbitop .getRightOperand ( ) ) and
88+ getPrecision ( shift .getLeftOperand ( ) .getUnderlyingType ( ) ) <=
89+ upperBound ( shift .getRightOperand ( ) ) and
7490 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."
7793 or
78- lowerBound ( binbitop .getRightOperand ( ) ) < 0 and
94+ lowerBound ( shift .getRightOperand ( ) ) < 0 and
7995 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 ( ) + "."
9998 ) and
100- message = "TODO"
101- )
102- }
99+ /*
100+ * Shift statement is not at a basic block where
101+ * `shift_rhs < PRECISION(...)` is ensured
102+ */
103103
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
122106 (
123107 precisionCall .( FunctionCall ) .getTarget ( ) instanceof PopCount
124108 or
125109 precisionCall = any ( PrecisionMacro pm ) .getAnInvocation ( ) .getExpr ( )
126110 )
127111 |
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 )
134114 ) 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+ )
136127 )
137128}
138129
139130from BinaryBitwiseOperation badShift , string message
140131where
141132 not isExcluded ( badShift , TypesPackage:: exprShiftedbyNegativeOrGreaterPrecisionOperandQuery ( ) ) and
142- isForbiddenLShiftExpr ( badShift , message )
143- or
144- isForbiddenRShiftExpr ( badShift , message )
133+ isForbiddenShiftExpr ( badShift , message )
145134select badShift , message
0 commit comments