Skip to content

Commit ec2a13c

Browse files
authored
Merge branch 'main' into lcartey/rule-5-8-no-linkage
2 parents 70f9756 + 015872e commit ec2a13c

File tree

8 files changed

+126
-22
lines changed

8 files changed

+126
-22
lines changed

c/misra/src/codingstandards/c/misra/EssentialTypes.qll

+11-7
Original file line numberDiff line numberDiff line change
@@ -355,13 +355,17 @@ class EssentialLiteral extends EssentialExpr, Literal {
355355
else (
356356
if this.(CharLiteral).getCharacter().length() = 1
357357
then result instanceof PlainCharType
358-
else (
359-
getStandardType().(IntegralType).isSigned() and
360-
result = stlr(this)
361-
or
362-
not getStandardType().(IntegralType).isSigned() and
363-
result = utlr(this)
364-
)
358+
else
359+
exists(Type underlyingStandardType |
360+
underlyingStandardType = getStandardType().getUnderlyingType()
361+
|
362+
if underlyingStandardType instanceof IntType
363+
then
364+
if underlyingStandardType.(IntType).isSigned()
365+
then result = stlr(this)
366+
else result = utlr(this)
367+
else result = underlyingStandardType
368+
)
365369
)
366370
}
367371
}

c/misra/src/rules/RULE-12-2/RightHandOperandOfAShiftRange.ql

+42-5
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,51 @@ class ShiftExpr extends BinaryBitwiseOperation {
2020
ShiftExpr() { this instanceof LShiftExpr or this instanceof RShiftExpr }
2121
}
2222

23-
from ShiftExpr e, Expr right, int max_val
23+
MacroInvocation getAMacroInvocation(ShiftExpr se) { result.getAnExpandedElement() = se }
24+
25+
Macro getPrimaryMacro(ShiftExpr se) {
26+
exists(MacroInvocation mi |
27+
mi = getAMacroInvocation(se) and
28+
not exists(MacroInvocation otherMi |
29+
otherMi = getAMacroInvocation(se) and otherMi.getParentInvocation() = mi
30+
) and
31+
result = mi.getMacro()
32+
)
33+
}
34+
35+
from
36+
ShiftExpr e, Expr right, int max_val, float lowerBound, float upperBound, Type essentialType,
37+
string extraMessage, Locatable optionalPlaceholderLocation, string optionalPlaceholderMessage
2438
where
2539
not isExcluded(right, Contracts7Package::rightHandOperandOfAShiftRangeQuery()) and
2640
right = e.getRightOperand().getFullyConverted() and
27-
max_val = (8 * getEssentialType(e.getLeftOperand()).getSize()) - 1 and
41+
essentialType = getEssentialType(e.getLeftOperand()) and
42+
max_val = (8 * essentialType.getSize()) - 1 and
43+
upperBound = upperBound(right) and
44+
lowerBound = lowerBound(right) and
45+
(
46+
lowerBound < 0 or
47+
upperBound > max_val
48+
) and
49+
// If this shift happens inside a macro, then report the macro as well
50+
// for easier validation
2851
(
29-
lowerBound(right) < 0 or
30-
upperBound(right) > max_val
52+
if exists(getPrimaryMacro(e))
53+
then
54+
extraMessage = " from expansion of macro $@" and
55+
exists(Macro m |
56+
m = getPrimaryMacro(e) and
57+
optionalPlaceholderLocation = m and
58+
optionalPlaceholderMessage = m.getName()
59+
)
60+
else (
61+
extraMessage = "" and
62+
optionalPlaceholderLocation = e and
63+
optionalPlaceholderMessage = ""
64+
)
3165
)
3266
select right,
33-
"The right hand operand of the shift operator shall lie in the range 0 to " + max_val + "."
67+
"The possible range of the right operand of the shift operator (" + lowerBound + ".." + upperBound
68+
+ ") is outside the the valid shift range (0.." + max_val +
69+
") for the essential type of the left operand (" + essentialType + ")" + extraMessage + ".",
70+
optionalPlaceholderLocation, optionalPlaceholderMessage

c/misra/test/c/misra/EssentialTypes.expected

+3
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@
3838
| test.c:26:3:26:3 | f | float | float | essentially Floating type |
3939
| test.c:27:3:27:5 | f32 | float32_t | float32_t | essentially Floating type |
4040
| test.c:28:3:28:6 | cf32 | float | float | essentially Floating type |
41+
| test.c:32:3:32:3 | 1 | signed char | signed char | essentially Signed type |
42+
| test.c:33:3:33:4 | 1 | unsigned char | unsigned char | essentially Unsigned type |
43+
| test.c:34:3:34:5 | 1 | unsigned long | unsigned long | essentially Unsigned type |

c/misra/test/c/misra/test.c

+6
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,10 @@ void testCategoriesForComplexTypes() {
2626
f; // Should be essentially Floating type
2727
f32; // Should be essentially Floating type
2828
cf32; // Should be essentially Floating type
29+
}
30+
31+
void testConstants() {
32+
1; // Essentially signed char
33+
1U; // Essentially unsigned char
34+
1UL; // Essentially unsigned long
2935
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
| test.c:8:10:8:10 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. |
2-
| test.c:9:10:9:11 | - ... | The right hand operand of the shift operator shall lie in the range 0 to 7. |
3-
| test.c:10:10:10:14 | ... + ... | The right hand operand of the shift operator shall lie in the range 0 to 7. |
4-
| test.c:11:10:11:14 | ... + ... | The right hand operand of the shift operator shall lie in the range 0 to 7. |
5-
| test.c:13:21:13:22 | 16 | The right hand operand of the shift operator shall lie in the range 0 to 15. |
6-
| test.c:16:9:16:9 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. |
7-
| test.c:21:9:21:10 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 63. |
8-
| test.c:25:10:25:10 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. |
9-
| test.c:26:10:26:11 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 7. |
10-
| test.c:30:16:30:17 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 63. |
1+
| test.c:8:10:8:10 | 8 | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:8:3:8:10 | ... >> ... | |
2+
| test.c:9:10:9:11 | - ... | The possible range of the right operand of the shift operator (-1..-1) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:9:3:9:11 | ... >> ... | |
3+
| test.c:10:10:10:14 | ... + ... | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:10:3:10:14 | ... >> ... | |
4+
| test.c:11:10:11:14 | ... + ... | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:11:3:11:14 | ... << ... | |
5+
| test.c:13:21:13:22 | 16 | The possible range of the right operand of the shift operator (16..16) is outside the the valid shift range (0..15) for the essential type of the left operand (uint16_t). | test.c:13:3:13:22 | ... << ... | |
6+
| test.c:16:9:16:9 | 8 | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (unsigned char). | test.c:16:3:16:9 | ... << ... | |
7+
| test.c:21:9:21:10 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:21:3:21:10 | ... << ... | |
8+
| test.c:26:10:26:11 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:26:3:26:11 | ... << ... | |
9+
| test.c:30:16:30:17 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:30:3:30:17 | ... << ... | |
10+
| test.c:34:8:34:8 | y | The possible range of the right operand of the shift operator (0..4294967295) is outside the the valid shift range (0..31) for the essential type of the left operand (unsigned int). | test.c:34:3:34:8 | ... >> ... | |
11+
| test.c:40:8:40:8 | y | The possible range of the right operand of the shift operator (-2147483648..2147483647) is outside the the valid shift range (0..31) for the essential type of the left operand (signed int). | test.c:40:3:40:8 | ... >> ... | |
12+
| test.c:42:8:42:8 | y | The possible range of the right operand of the shift operator (-31..31) is outside the the valid shift range (0..31) for the essential type of the left operand (signed int). | test.c:42:3:42:8 | ... >> ... | |

c/misra/test/rules/RULE-12-2/test.c

+12
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,15 @@ void f1() {
2929
ULONG_MAX << 8; // COMPLIANT
3030
ULONG_MAX << 64; // NON_COMPLIANT
3131
}
32+
33+
void unsignedRemAssign(unsigned int y, unsigned int x) {
34+
x >> y; // NON_COMPLIANT
35+
y %= 32;
36+
x >> y; // COMPLIANT
37+
}
38+
39+
void signedRemAssign(signed int y, signed int x) {
40+
x >> y; // NON_COMPLIANT
41+
y %= 32;
42+
x >> y; // NON_COMPLIANT - may be negative
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- `RULE-12-2` - `RightHandOperandOfAShiftRange.ql`:
2+
- Reduce false positives related to ranges determined by `%=`.
3+
- Reduce false positives for integer constants with explicit size suffix were incorrectly identified as smaller types.
4+
- Improve explanation of results, providing additional information on types and size ranges.
5+
- Combine results stemming from the expansion of a macro, where the result is not dependent on the context.
6+

cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll

+34
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,40 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast
151151
override predicate dependsOnChild(Expr child) { child = getExpr() }
152152
}
153153

154+
/**
155+
* A range analysis extension that supports `%=`.
156+
*/
157+
private class RemAssignSimpleRange extends SimpleRangeAnalysisExpr, AssignRemExpr {
158+
override float getLowerBounds() {
159+
exists(float maxDivisorNegated, float dividendLowerBounds |
160+
// Find the max divisor, negated e.g. `%= 32` would be `-31`
161+
maxDivisorNegated = (getFullyConvertedUpperBounds(getRValue()).abs() - 1) * -1 and
162+
// Find the lower bounds of the dividend
163+
dividendLowerBounds = getFullyConvertedLowerBounds(getLValue()) and
164+
// The lower bound is calculated in two steps:
165+
// 1. Determine the maximum of the dividend lower bound and maxDivisorNegated.
166+
// When the dividend is negative this will result in a negative result
167+
// 2. Find the minimum with 0. If the divided is always >0 this will produce 0
168+
// otherwise it will produce the lowest negative number that can be held
169+
// after the modulo.
170+
result = 0.minimum(dividendLowerBounds.maximum(maxDivisorNegated))
171+
)
172+
}
173+
174+
override float getUpperBounds() {
175+
exists(float maxDivisor, float maxDividend |
176+
// The maximum divisor value is the absolute value of the divisor minus 1
177+
maxDivisor = getFullyConvertedUpperBounds(getRValue()).abs() - 1 and
178+
// value if > 0 otherwise 0
179+
maxDividend = getFullyConvertedUpperBounds(getLValue()).maximum(0) and
180+
// In the case the numerator is definitely less than zero, the result could be negative
181+
result = maxDividend.minimum(maxDivisor)
182+
)
183+
}
184+
185+
override predicate dependsOnChild(Expr expr) { expr = getAChild() }
186+
}
187+
154188
/**
155189
* <stdio.h> functions that read a character from the STDIN,
156190
* or return EOF if it fails to do so.

0 commit comments

Comments
 (0)