Skip to content

Commit 4be1395

Browse files
committed
Rule 7.0.6: Use BigInt for constant expressions
- Use IntegerConstantExpr to determine both the expressions which are constant, and the BigInt value of those constants (before final conversion). - Implement a BigInt type upper/lower bound to determine whether a constant assignment is valid.
1 parent 04613cd commit 4be1395

File tree

3 files changed

+42
-13
lines changed

3 files changed

+42
-13
lines changed

cpp/common/src/codingstandards/cpp/types/Type.qll

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,20 @@ int getPrecision(IntegralType type) {
9494
or
9595
type.isExplicitlySigned() and result = type.getSize() * 8 - 1
9696
}
97+
98+
/**
99+
* Determines the lower and upper bounds of an integral type.
100+
*/
101+
predicate integralTypeBounds(IntegralType integralType, QlBuiltins::BigInt lb, QlBuiltins::BigInt ub) {
102+
exists(QlBuiltins::BigInt limit | limit = 2.toBigInt().pow(8 * integralType.getSize()) |
103+
if integralType instanceof BoolType
104+
then lb = 0.toBigInt() and ub = 1.toBigInt()
105+
else
106+
if integralType.isSigned()
107+
then (
108+
lb = -(limit / 2.toBigInt()) and ub = (limit / 2.toBigInt()) - 1.toBigInt()
109+
) else (
110+
lb = 0.toBigInt() and ub = limit - 1.toBigInt()
111+
)
112+
)
113+
}

cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cpp
22
import codingstandards.cpp.misra
3+
import codingstandards.cpp.Type
34

45
/**
56
* A MISRA C++ 2023 type category.
@@ -95,9 +96,15 @@ class NumericType extends Type {
9596

9697
TypeCategory getTypeCategory() { result = getTypeCategory(realType) }
9798

98-
float getUpperBound() { result = typeUpperBound(realType) }
99+
/**
100+
* Gets the integeral upper bound of the numeric type, if it represents an integer type.
101+
*/
102+
QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(realType, _, result) }
99103

100-
float getLowerBound() { result = typeLowerBound(realType) }
104+
/**
105+
* Gets the integeral lower bound of the numeric type, if it represents an integer type.
106+
*/
107+
QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(realType, result, _) }
101108

102109
Type getRealType() { result = realType }
103110
}

cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,39 @@
1515

1616
import cpp
1717
import codingstandards.cpp.misra
18+
import codingstandards.cpp.ConstantExpressions
1819
import codingstandards.cpp.misra.StandardConversions
20+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1921

20-
predicate isValidConstantAssignment(Expr source, NumericType targetType) {
22+
predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targetType) {
2123
isAssignment(source, targetType, _) and
22-
// Source is an integer constant expression
23-
source.isConstant() and
24-
source.getType().(NumericType).getTypeCategory() = Integral() and
25-
exists(float val | val = source.getValue().toFloat() |
24+
exists(QlBuiltins::BigInt val | val = source.getConstantValue() |
2625
// Bit field assignment: check if the value fits in the bit field
2726
exists(BitField bf, int numBits |
2827
isAssignedToBitfield(source, bf) and
2928
numBits = bf.getNumBits() and
3029
if targetType.getSignedness() = Signed()
3130
then
3231
// Signed bit field: value must be in the range of signed bit field
33-
val >= -2.pow(numBits - 1) and
34-
val < 2.pow(numBits - 1)
32+
val >= -2.toBigInt().pow(numBits - 1) and
33+
val < 2.toBigInt().pow(numBits - 1)
3534
else (
3635
// Unsigned bit field: value must be in the range of unsigned bit field
37-
val >= 0 and
38-
val < 2.pow(numBits)
36+
val >= 0.toBigInt() and
37+
val < 2.toBigInt().pow(numBits)
3938
)
4039
)
4140
or
4241
// Regular assignment: check if the value fits in the target type range
4342
not isAssignedToBitfield(source, _) and
44-
targetType.getLowerBound() <= val and
45-
val <= targetType.getUpperBound()
43+
(
44+
// Integer types: check if the value fits in the target type range
45+
targetType.getIntegralLowerBound() <= val and
46+
val <= targetType.getIntegralUpperBound()
47+
or
48+
// All floating point types can represent all integer values
49+
targetType.getTypeCategory() = FloatingPoint()
50+
)
4651
)
4752
}
4853

0 commit comments

Comments
 (0)