From f8b7805652e22402a10a16baf2063fae75794150 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 27 Sep 2024 08:21:00 -0700 Subject: [PATCH 01/17] save work --- .../InvalidIntegerConstantMacroArgument.ql | 86 ++++++++++ .../UseOfBannedSmallIntegerConstantMacro.ql | 25 +++ ...validIntegerConstantMacroArgument.expected | 55 ++++++ .../InvalidIntegerConstantMacroArgument.qlref | 1 + c/misra/test/rules/RULE-7-5/test.c | 156 ++++++++++++++++++ ...OfBannedSmallIntegerConstantMacro.expected | 4 + ...UseOfBannedSmallIntegerConstantMacro.qlref | 1 + c/misra/test/rules/RULE-7-6/test.c | 10 ++ .../cpp/IntegerConstantMacro.qll | 35 ++++ .../cpp/exclusions/c/RuleMetadata.qll | 7 +- .../cpp/exclusions/c/Types2.qll | 44 +++++ rule_packages/c/Types2.json | 42 +++++ 12 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql create mode 100644 c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql create mode 100644 c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected create mode 100644 c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref create mode 100644 c/misra/test/rules/RULE-7-5/test.c create mode 100644 c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected create mode 100644 c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref create mode 100644 c/misra/test/rules/RULE-7-6/test.c create mode 100644 cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll create mode 100644 rule_packages/c/Types2.json diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..b58f87a5ca --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -0,0 +1,86 @@ +/** + * @id c/misra/invalid-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall have an appropriate form + * @description Integer constant macros should be given appropriate values for the size of the + * integer type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Cpp14Literal +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +abstract class PossiblyNegativeLiteral extends Expr { + abstract Cpp14Literal::IntegerLiteral getBaseLiteral(); + + predicate isNegative() { + this instanceof NegativeLiteral + } +} + +class NegativeLiteral extends PossiblyNegativeLiteral, UnaryMinusExpr { + Cpp14Literal::IntegerLiteral literal; + + NegativeLiteral() { + literal = getOperand() + } + + override Cpp14Literal::IntegerLiteral getBaseLiteral() { + result = literal + } +} + +class PositiveLiteral extends PossiblyNegativeLiteral, Cpp14Literal::IntegerLiteral { + PositiveLiteral() { + not exists(UnaryMinusExpr l | l.getOperand() = this) + } + + override Cpp14Literal::IntegerLiteral getBaseLiteral() { + result = this + } +} + +predicate validExpr(Expr expr) { + expr instanceof PossiblyNegativeLiteral +} + +predicate usesSuffix(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch(".*[uUlL]") +} + +predicate matchedSign(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + literal.isNegative() implies macro.isSigned() +} + +predicate validLiteralType(PossiblyNegativeLiteral expr) { + expr.getBaseLiteral() instanceof Cpp14Literal::DecimalLiteral or + expr.getBaseLiteral() instanceof Cpp14Literal::OctalLiteral or + expr.getBaseLiteral() instanceof Cpp14Literal::HexLiteral +} + +predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + // Note: upperBound should equal lowerBound. + upperBound(literal) <= macro.maxValue() and + lowerBound(literal) >= macro.minValue() and exists("123".toBigInt()) +} + +from MacroInvocation invoke, IntegerConstantMacro macro, string explanation +where + not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() = macro and + ( + (not validExpr(invoke.getExpr()) and explanation = "invalid expression") or + (validLiteralType(invoke.getExpr()) and explanation = "invalid literal type" + invoke.getExpr().getAQlClass()) or + (usesSuffix(invoke) and explanation = "literal suffixes not allowed") or + (not matchedSign(macro, invoke.getExpr()) and explanation = "signed/unsigned mismatch") or + (not matchesSize(macro, invoke.getExpr()) and explanation = "invalid size") + ) + +select invoke.getExpr(), "Invalid integer constant macro: " + explanation diff --git a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql new file mode 100644 index 0000000000..cac7f091a8 --- /dev/null +++ b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql @@ -0,0 +1,25 @@ +/** + * @id c/misra/use-of-banned-small-integer-constant-macro + * @name RULE-7-6: The small integer variants of the minimum-width integer constant macros shall not be used + * @description Small integer constant macros expression are promoted to type int, which can lead to + * unexpected results. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-7-6 + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro + + +from MacroInvocation macroInvoke, IntegerConstantMacro macro +where + not isExcluded(macroInvoke, Types2Package::useOfBannedSmallIntegerConstantMacroQuery()) and + macroInvoke.getMacro() = macro + and macro.isSmall() +select + macroInvoke, "Usage of small integer constant macro " + macro.getName() + " is not allowed." diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..b38863eccd --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -0,0 +1,55 @@ +| test.c:12:13:12:15 | 1.0 | Invalid integer constant macro: invalid literal type | +| test.c:13:13:12:15 | 0b111 | Invalid integer constant macro: invalid literal type | +| test.c:16:13:16:14 | 1 | Invalid integer constant macro: literal suffixes not allowed | +| test.c:17:13:17:14 | 2 | Invalid integer constant macro: literal suffixes not allowed | +| test.c:18:13:18:14 | 3 | Invalid integer constant macro: literal suffixes not allowed | +| test.c:19:13:19:14 | 4 | Invalid integer constant macro: literal suffixes not allowed | +| test.c:20:13:20:15 | 5 | Invalid integer constant macro: literal suffixes not allowed | +| test.c:26:13:26:15 | 256 | Invalid integer constant macro: invalid size | +| test.c:27:13:27:16 | 256 | Invalid integer constant macro: invalid size | +| test.c:28:13:28:17 | 256 | Invalid integer constant macro: invalid size | +| test.c:31:13:31:14 | - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:32:13:32:15 | - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:33:13:33:15 | - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:34:13:34:17 | - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:37:13:37:17 | ... + ... | Invalid integer constant macro: invalid expression | +| test.c:38:13:38:18 | access to array | Invalid integer constant macro: invalid expression | +| test.c:39:13:39:18 | access to array | Invalid integer constant macro: invalid expression | +| test.c:40:13:39:18 | UINT8_MAX | Invalid integer constant macro: invalid expression | +| test.c:54:12:54:15 | 191 | Invalid integer constant macro: invalid size | +| test.c:55:12:55:14 | 255 | Invalid integer constant macro: invalid size | +| test.c:56:12:56:15 | 192 | Invalid integer constant macro: invalid size | +| test.c:57:12:57:15 | 128 | Invalid integer constant macro: invalid size | +| test.c:61:12:57:15 | -129 | Invalid integer constant macro: invalid size | +| test.c:62:12:57:15 | -129 | Invalid integer constant macro: invalid size | +| test.c:63:12:57:15 | -201 | Invalid integer constant macro: invalid size | +| test.c:64:12:57:15 | -0x81 | Invalid integer constant macro: invalid size | +| test.c:76:14:76:18 | 65536 | Invalid integer constant macro: invalid size | +| test.c:78:14:78:20 | 65536 | Invalid integer constant macro: invalid size | +| test.c:91:13:91:17 | 32768 | Invalid integer constant macro: invalid size | +| test.c:93:13:93:18 | 32768 | Invalid integer constant macro: invalid size | +| test.c:97:13:93:18 | -32769 | Invalid integer constant macro: invalid size | +| test.c:98:13:93:18 | -040001 | Invalid integer constant macro: invalid size | +| test.c:99:13:93:18 | -0x8001 | Invalid integer constant macro: invalid size | +| test.c:109:14:109:24 | 4294967296 | Invalid integer constant macro: invalid size | +| test.c:110:14:110:25 | 4294967296 | Invalid integer constant macro: invalid size | +| test.c:120:13:120:22 | 2147483648 | Invalid integer constant macro: invalid size | +| test.c:121:13:121:23 | 34359738368 | Invalid integer constant macro: invalid size | +| test.c:130:14:130:15 | 0 | Invalid integer constant macro: invalid size | +| test.c:133:14:133:34 | 18446744073709551615 | Invalid integer constant macro: invalid size | +| test.c:134:14:134:32 | 18446744073709551615 | Invalid integer constant macro: invalid size | +| test.c:140:13:140:14 | 0 | Invalid integer constant macro: invalid size | +| test.c:143:13:143:32 | 9223372036854775807 | Invalid integer constant macro: invalid size | +| test.c:147:13:147:33 | - ... | Invalid integer constant macro: invalid size | +| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid expression | +| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid literal type | +| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid size | +| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid expression | +| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid literal type | +| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid size | +| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: signed/unsigned mismatch | +| test.c:152:13:152:31 | 9223372036854775807 | Invalid integer constant macro: invalid size | +| test.c:153:13:153:31 | 9223372036854775808 | Invalid integer constant macro: invalid size | +| test.c:154:13:154:31 | - ... | Invalid integer constant macro: invalid size | +| test.c:155:13:155:30 | - ... | Invalid integer constant macro: invalid size | diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..802f415bc9 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c new file mode 100644 index 0000000000..4412bdf82f --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -0,0 +1,156 @@ +#include "stdint.h" + +uint_least8_t g1[] = { + // Basic valid + UINT8_C(0), // COMPLIANT + UINT8_C(1), // COMPLIANT + UINT8_C(8), // COMPLIANT + UINT8_C(0x23), // COMPLIANT + UINT8_C(034), // COMPLIANT + + // Incorrect literal types + UINT8_C(1.0), // NON-COMPLIANT + UINT8_C(0b111), // NON-COMPLIANT + + // Suffixes disallowed + UINT8_C(1u), // NON-COMPLIANT + UINT8_C(2U), // NON-COMPLIANT + UINT8_C(3l), // NON-COMPLIANT + UINT8_C(4L), // NON-COMPLIANT + UINT8_C(5ul), // NON-COMPLIANT + + // Range tests + UINT8_C(255), // COMPLIANT + UINT8_C(0xFF), // COMPLIANT + UINT8_C(0377), // COMPLIANT + UINT8_C(256), // NON-COMPLIANT + UINT8_C(0400), // NON-COMPLIANT + UINT8_C(0x100), // NON-COMPLIANT + + // Signage tests + UINT8_C(-1), // NON-COMPLIANT + UINT8_C(-20), // NON-COMPLIANT + UINT8_C(-33), // NON-COMPLIANT + UINT8_C(-0x44), // NON-COMPLIANT + + // Invalid nonliteral expressions + UINT8_C(0 + 0), // NON-COMPLIANT + UINT8_C("a"[0]), // NON-COMPLIANT + UINT8_C(0["a"]), // NON-COMPLIANT + UINT8_C(UINT8_MAX), // NON-COMPLIANT +}; + +int_least8_t g2[] = { + // Basic valid + INT8_C(0), // COMPLIANT + INT8_C(1), // COMPLIANT + INT8_C(8), // COMPLIANT + INT8_C(0x23), // COMPLIANT + INT8_C(034), // COMPLIANT + + // Range tests + INT8_C(127), // COMPLIANT + INT8_C(0x79), // COMPLIANT + INT8_C(0177), // COMPLIANT + INT8_C(128), // NON-COMPLIANT + INT8_C(0200), // NON-COMPLIANT + INT8_C(0x80), // NON-COMPLIANT + INT8_C(-128), // COMPLIANT + INT8_C(-0x80), // COMPLIANT + INT8_C(-0200), // COMPLIANT + INT8_C(-129), // NON-COMPLIANT + INT8_C(-0201), // NON-COMPLIANT + INT8_C(-0x81), // NON-COMPLIANT +}; + +uint_least16_t g3[] = { + // Basic valid + UINT16_C(0), // COMPLIANT + UINT16_C(0x23), // COMPLIANT + UINT16_C(034), // COMPLIANT + + // Range tests + UINT16_C(65535), // COMPLIANT + UINT16_C(0xFFFF), // COMPLIANT + UINT16_C(0177777), // COMPLIANT + UINT16_C(65536), // NON-COMPLIANT + UINT16_C(0200000), // NON-COMPLIANT + UINT16_C(0x10000), // NON-COMPLIANT +}; + +int_least16_t g4[] = { + // Basic valid + INT16_C(0), // COMPLIANT + INT16_C(0x23), // COMPLIANT + INT16_C(034), // COMPLIANT + + // Range tests + INT16_C(32767), // COMPLIANT + INT16_C(0x7FFF), // COMPLIANT + INT16_C(077777), // COMPLIANT + INT16_C(32768), // NON-COMPLIANT + INT16_C(0100000), // NON-COMPLIANT + INT16_C(0x8000), // NON-COMPLIANT + INT16_C(-32768), // COMPLIANT + INT16_C(-040000), // COMPLIANT + INT16_C(-0x8000), // COMPLIANT + INT16_C(-32769), // NON-COMPLIANT + INT16_C(-040001), // NON-COMPLIANT + INT16_C(-0x8001), // NON-COMPLIANT +}; + +uint_least32_t g5[] = { + // Basic valid + UINT32_C(0), // COMPLIANT + + // Range tests + UINT32_C(4294967295), // COMPLIANT + UINT32_C(0xFFFFFFFF), // COMPLIANT + UINT32_C(4294967296), // NON-COMPLIANT + UINT32_C(0x100000000), // NON-COMPLIANT +}; + +int_least32_t g6[] = { + // Basic valid + INT32_C(0), // COMPLIANT + + // Range tests + INT32_C(2147483647), // COMPLIANT + INT32_C(0x7FFFFFFF), // COMPLIANT + INT32_C(2147483648), // NON-COMPLIANT + INT32_C(0x800000000), // NON-COMPLIANT + INT32_C(-2147483648), // COMPLIANT + INT32_C(-0x80000000), // COMPLIANT + INT32_C(-2147483647), // NON-COMPLIANT + INT32_C(-0x800000001), // NON-COMPLIANT +}; + +uint_least64_t g7[] = { + // Basic valid + UINT64_C(0), // COMPLIANT + + // Range tests + UINT64_C(18446744073709551615), // COMPLIANT + UINT64_C(0xFFFFFFFFFFFFFFFF), // COMPLIANT + // Compile time error if we try to create integer literals beyond this. +}; + +int_least64_t g8[] = { + // Basic valid + INT64_C(0), // COMPLIANT + + // Range tests + INT64_C(9223372036854775807), // COMPLIANT + // INT64_C(9223372036854775808) is a compile-time error + + // -9223372036854775808 allowed, but cannot be created via unary- without compile time errors. + INT64_C(-9223372036854775807), // COMPLIANT + INT64_C(-9223372036854775807 - 1), // COMPLIANT + // -9223372036854775809 is not allowed, and cannot be created via unary- without compile time errors. + INT64_C(-9223372036854775807 - 2), // NON-COMPLIANT + + INT64_C(0x7FFFFFFFFFFFFFFF), // COMPLIANT + INT64_C(0x8000000000000000), // NON-COMPLIANT + INT64_C(-0x8000000000000000), // COMPLIANT + INT64_C(-0x8000000000000001), // NON-COMPLIANT +}; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected new file mode 100644 index 0000000000..ddf517ed9e --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected @@ -0,0 +1,4 @@ +| test.c:3:13:3:24 | INT8_C(c) | Usage of small integer constant macro INT8_C is not allowed. | +| test.c:4:14:4:26 | UINT8_C(c) | Usage of small integer constant macro UINT8_C is not allowed. | +| test.c:5:14:5:28 | INT16_C(c) | Usage of small integer constant macro INT16_C is not allowed. | +| test.c:6:15:6:30 | UINT16_C(c) | Usage of small integer constant macro UINT16_C is not allowed. | diff --git a/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref new file mode 100644 index 0000000000..e41e2912d8 --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref @@ -0,0 +1 @@ +rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-6/test.c b/c/misra/test/rules/RULE-7-6/test.c new file mode 100644 index 0000000000..f2b783e800 --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/test.c @@ -0,0 +1,10 @@ +#include "stdint.h" + +int8_t g1 = INT8_C(0x12); // NON-COMPLIANT +uint8_t g2 = UINT8_C(0x12); // NON-COMPLIANT +int16_t g3 = INT16_C(0x1234); // NON-COMPLIANT +uint16_t g4 = UINT16_C(0x1234); // NON-COMPLIANT +int32_t g5 = INT32_C(0x1234); // COMPLIANT +uint32_t g6 = UINT32_C(0x1234); // COMPLIANT +int64_t g7 = INT64_C(0x1234); // COMPLIANT +uint64_t g8 = UINT64_C(0x1234); // COMPLIANT \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll new file mode 100644 index 0000000000..472866fdea --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -0,0 +1,35 @@ +import cpp + +class IntegerConstantMacro extends Macro { + boolean signed; + int size; + IntegerConstantMacro() { + ( + signed = true and size = getName().regexpCapture("INT(8|16|32|64)_C", 1).toInt() + ) or ( + signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() + ) + } + + predicate isSmall() { + size < 32 + } + + int getSize() { + result = size + } + + predicate isSigned() { + signed = true + } + + int maxValue() { + (signed = true and result = 2.pow(getSize() - 1) - 1) or + (signed = false and result = 2.pow(getSize()) - 1) + } + + int minValue() { + (signed = true and result = -(2.0.pow(getSize() - 1))) or + (signed = false and result = 0) + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index b10fbf0a2f..e4b7c88563 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -72,6 +72,7 @@ import Strings2 import Strings3 import Syntax import Types1 +import Types2 /** The TQuery type representing this language * */ newtype TCQuery = @@ -144,7 +145,8 @@ newtype TCQuery = TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or TSyntaxPackageQuery(SyntaxQuery q) or - TTypes1PackageQuery(Types1Query q) + TTypes1PackageQuery(Types1Query q) or + TTypes2PackageQuery(Types2Query q) /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { @@ -217,5 +219,6 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or isSyntaxQueryMetadata(query, queryId, ruleId, category) or - isTypes1QueryMetadata(query, queryId, ruleId, category) + isTypes1QueryMetadata(query, queryId, ruleId, category) or + isTypes2QueryMetadata(query, queryId, ruleId, category) } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll new file mode 100644 index 0000000000..fbb5d06ee4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Types2Query = + TInvalidIntegerConstantMacroArgumentQuery() or + TUseOfBannedSmallIntegerConstantMacroQuery() + +predicate isTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `invalidIntegerConstantMacroArgument` query + Types2Package::invalidIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `invalidIntegerConstantMacroArgument` query + "c/misra/invalid-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `useOfBannedSmallIntegerConstantMacro` query + Types2Package::useOfBannedSmallIntegerConstantMacroQuery() and + queryId = + // `@id` for the `useOfBannedSmallIntegerConstantMacro` query + "c/misra/use-of-banned-small-integer-constant-macro" and + ruleId = "RULE-7-6" and + category = "required" +} + +module Types2Package { + Query invalidIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TInvalidIntegerConstantMacroArgumentQuery())) + } + + Query useOfBannedSmallIntegerConstantMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useOfBannedSmallIntegerConstantMacro` query + TQueryC(TTypes2PackageQuery(TUseOfBannedSmallIntegerConstantMacroQuery())) + } +} diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json new file mode 100644 index 0000000000..9468af278c --- /dev/null +++ b/rule_packages/c/Types2.json @@ -0,0 +1,42 @@ +{ + "MISRA-C-2012": { + "RULE-7-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Integer constant macros should be given appropriate values for the size of the integer type.", + "kind": "problem", + "name": "The argument of an integer constant macro shall have an appropriate form", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidIntegerConstantMacroArgument", + "tags": [ + "correctness" + ] + } + ], + "title": "The argument of an integer constant macro shall have an appropriate form" + }, + "RULE-7-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Small integer constant macros expression are promoted to type int, which can lead to unexpected results.", + "kind": "problem", + "name": "The small integer variants of the minimum-width integer constant macros shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "UseOfBannedSmallIntegerConstantMacro", + "tags": [ + "readability" + ] + } + ], + "title": "The small integer variants of the minimum-width integer constant macros shall not be used" + } + } +} \ No newline at end of file From 581366094b70e13905c602470a6b699c868fde13 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 16:41:15 -0700 Subject: [PATCH 02/17] Implement Types2 package. Break up integer constant macro rules into several queries to make it easier to handle exceptions and deviations. --- ...rectlySizedIntegerConstantMacroArgument.ql | 44 ++++++ .../IntegerConstantMacroArgumentUsesSuffix.ql | 29 ++++ .../InvalidIntegerConstantMacroArgument.ql | 87 +++-------- ...dLiteralForIntegerConstantMacroArgument.ql | 47 ++++++ ...SizedIntegerConstantMacroArgument.expected | 28 ++++ ...tlySizedIntegerConstantMacroArgument.qlref | 1 + ...erConstantMacroArgumentUsesSuffix.expected | 5 + ...tegerConstantMacroArgumentUsesSuffix.qlref | 1 + ...validIntegerConstantMacroArgument.expected | 60 +------- ...alForIntegerConstantMacroArgument.expected | 2 + ...teralForIntegerConstantMacroArgument.qlref | 1 + c/misra/test/rules/RULE-7-5/test.c | 142 +++++++++--------- .../cpp/IntegerConstantMacro.qll | 38 ++--- .../src/codingstandards/cpp/Literals.qll | 44 ++++++ .../cpp/exclusions/c/Types2.qll | 51 +++++++ rule_packages/c/Types2.json | 41 ++++- 16 files changed, 410 insertions(+), 211 deletions(-) create mode 100644 c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql create mode 100644 c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql create mode 100644 c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql create mode 100644 c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected create mode 100644 c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref create mode 100644 c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected create mode 100644 c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref create mode 100644 c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected create mode 100644 c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..dd1417c2a6 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -0,0 +1,44 @@ +/** + * @id c/misra/incorrectly-sized-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall have an appropriate size + * @description Integer constant macros argument values should be values of a compatible size + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +predicate matchesSign(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + literal.isNegative() implies macro.isSigned() +} + +predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + // Wait for BigInt support to check 64 bit macro types. + (macro.getSize() < 64 and matchesSign(macro, literal)) + implies + ( + literal.getRawValue() <= macro.maxValue() and + literal.getRawValue() >= macro.minValue() + ) +} + +from + PossiblyNegativeLiteral literal, MacroInvocation invoke, IntegerConstantMacro macro, + string explanation +where + not isExcluded(invoke, Types2Package::incorrectlySizedIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() = macro and + literal = invoke.getExpr() and + ( + not matchesSign(macro, invoke.getExpr()) and explanation = "cannot be negative" + or + not matchesSize(macro, invoke.getExpr()) and explanation = "is too large for the specified type" + ) +select invoke.getExpr(), "Integer constant macro value " + explanation diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql new file mode 100644 index 0000000000..f4ca73e16c --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -0,0 +1,29 @@ +/** + * @id c/misra/integer-constant-macro-argument-uses-suffix + * @name RULE-7-5: The argument of an integer constant macro shall not use literal suffixes u, l, or ul + * @description Integer constant macros should be used integer literal values with no u/l suffix. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +predicate usesSuffix(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch(".*[uUlL]") +} + +from MacroInvocation invoke, PossiblyNegativeLiteral argument +where + not isExcluded(invoke, Types2Package::integerConstantMacroArgumentUsesSuffixQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + invoke.getExpr() = argument and + usesSuffix(invoke) +select invoke.getExpr(), "Integer constant macro arguments should not have 'u'/'l' suffix." diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index b58f87a5ca..33ec266b51 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -1,8 +1,7 @@ /** * @id c/misra/invalid-integer-constant-macro-argument - * @name RULE-7-5: The argument of an integer constant macro shall have an appropriate form - * @description Integer constant macros should be given appropriate values for the size of the - * integer type. + * @name RULE-7-5: The argument of an integer constant macro shall be a literal + * @description Integer constant macros should be given a literal value as an argument * @kind problem * @precision very-high * @problem.severity error @@ -14,73 +13,29 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.IntegerConstantMacro -import codingstandards.cpp.Cpp14Literal +import codingstandards.cpp.Literals import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -abstract class PossiblyNegativeLiteral extends Expr { - abstract Cpp14Literal::IntegerLiteral getBaseLiteral(); - - predicate isNegative() { - this instanceof NegativeLiteral - } -} - -class NegativeLiteral extends PossiblyNegativeLiteral, UnaryMinusExpr { - Cpp14Literal::IntegerLiteral literal; - - NegativeLiteral() { - literal = getOperand() - } - - override Cpp14Literal::IntegerLiteral getBaseLiteral() { - result = literal - } -} - -class PositiveLiteral extends PossiblyNegativeLiteral, Cpp14Literal::IntegerLiteral { - PositiveLiteral() { - not exists(UnaryMinusExpr l | l.getOperand() = this) - } - - override Cpp14Literal::IntegerLiteral getBaseLiteral() { - result = this - } -} - -predicate validExpr(Expr expr) { - expr instanceof PossiblyNegativeLiteral -} - -predicate usesSuffix(MacroInvocation invoke) { - invoke.getUnexpandedArgument(0).regexpMatch(".*[uUlL]") -} - -predicate matchedSign(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { - literal.isNegative() implies macro.isSigned() -} - -predicate validLiteralType(PossiblyNegativeLiteral expr) { - expr.getBaseLiteral() instanceof Cpp14Literal::DecimalLiteral or - expr.getBaseLiteral() instanceof Cpp14Literal::OctalLiteral or - expr.getBaseLiteral() instanceof Cpp14Literal::HexLiteral -} - -predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { - // Note: upperBound should equal lowerBound. - upperBound(literal) <= macro.maxValue() and - lowerBound(literal) >= macro.minValue() and exists("123".toBigInt()) +/** + * The max negative 64 bit signed integer is one less than the negative of the + * max positive signed 64 bit integer. The only way to create a "negative" + * literal is to use unary- negation of a positive literal. Therefore, clang + * (and likely other compilers) rejects `INT64_C(-92233...808)` but accepts + * `INT64_C(-92233...807 - 1)`. Therefore, in this case allow non-literal + * expressions. + */ +predicate specialMaxNegative64Exception(IntegerConstantMacro macro, Expr expr) { + macro.getSize() = 64 and + macro.isSigned() and + // Set a cutoff with precision, fix once BigInt library is available. + upperBound(expr) < macro.minValue() * 0.999999999 and + upperBound(expr) > macro.minValue() * 1.000000001 } -from MacroInvocation invoke, IntegerConstantMacro macro, string explanation +from MacroInvocation invoke, IntegerConstantMacro macro where not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and invoke.getMacro() = macro and - ( - (not validExpr(invoke.getExpr()) and explanation = "invalid expression") or - (validLiteralType(invoke.getExpr()) and explanation = "invalid literal type" + invoke.getExpr().getAQlClass()) or - (usesSuffix(invoke) and explanation = "literal suffixes not allowed") or - (not matchedSign(macro, invoke.getExpr()) and explanation = "signed/unsigned mismatch") or - (not matchesSize(macro, invoke.getExpr()) and explanation = "invalid size") - ) - -select invoke.getExpr(), "Invalid integer constant macro: " + explanation + not invoke.getExpr() instanceof PossiblyNegativeLiteral and + not specialMaxNegative64Exception(macro, invoke.getExpr()) +select invoke.getExpr(), "Integer constant macro argument must be an integer literal." diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..2447d82f6f --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -0,0 +1,47 @@ +/** + * @id c/misra/invalid-literal-for-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall be a decimal, hex, or octal literal + * @description Integer constant macro arguments should be a decimal, hex, or octal literal + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +/** + * Floating point literals are not allowed. Neither are char or string + * literals, although those are not `NumericLiteral`s and therefore detected in + * `InvalidIntegerConstantMacroArgument.ql`. + */ +predicate validLiteralType(PossiblyNegativeLiteral literal) { + literal.getBaseLiteral() instanceof Cpp14Literal::DecimalLiteral or + literal.getBaseLiteral() instanceof Cpp14Literal::OctalLiteral or + literal.getBaseLiteral() instanceof Cpp14Literal::HexLiteral +} + +/** + * Clang accepts `xINTsize_C(0b01)`, and expands the argument into a decimal + * literal. Binary literals are not standard c nor are they allowed by rule 7-5. + * Detect this pattern before macro expansion. + */ +predicate seemsBinaryLiteral(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch("0[bB][01]+") +} + +from MacroInvocation invoke, PossiblyNegativeLiteral literal +where + not isExcluded(invoke, Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + literal = invoke.getExpr() and + ( + not validLiteralType(literal) or + seemsBinaryLiteral(invoke) + ) +select literal, "Integer constant macro arguments must be a decimal, octal, or hex integer literal." diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..9ce9b29e3c --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected @@ -0,0 +1,28 @@ +| test.c:26:13:26:15 | 256 | Integer constant macro value is too large for the specified type | +| test.c:27:13:27:16 | 256 | Integer constant macro value is too large for the specified type | +| test.c:28:13:28:17 | 256 | Integer constant macro value is too large for the specified type | +| test.c:31:13:31:14 | - ... | Integer constant macro value cannot be negative | +| test.c:32:13:32:15 | - ... | Integer constant macro value cannot be negative | +| test.c:33:13:33:15 | - ... | Integer constant macro value cannot be negative | +| test.c:34:13:34:17 | - ... | Integer constant macro value cannot be negative | +| test.c:55:12:55:14 | 128 | Integer constant macro value is too large for the specified type | +| test.c:56:12:56:15 | 128 | Integer constant macro value is too large for the specified type | +| test.c:57:12:57:15 | 128 | Integer constant macro value is too large for the specified type | +| test.c:61:12:61:15 | - ... | Integer constant macro value is too large for the specified type | +| test.c:62:12:62:16 | - ... | Integer constant macro value is too large for the specified type | +| test.c:63:12:63:16 | - ... | Integer constant macro value is too large for the specified type | +| test.c:76:14:76:18 | 65536 | Integer constant macro value is too large for the specified type | +| test.c:77:14:77:20 | 65536 | Integer constant macro value is too large for the specified type | +| test.c:78:14:78:20 | 65536 | Integer constant macro value is too large for the specified type | +| test.c:91:13:91:17 | 32768 | Integer constant macro value is too large for the specified type | +| test.c:92:13:92:19 | 32768 | Integer constant macro value is too large for the specified type | +| test.c:93:13:93:18 | 32768 | Integer constant macro value is too large for the specified type | +| test.c:97:13:97:18 | - ... | Integer constant macro value is too large for the specified type | +| test.c:98:13:98:20 | - ... | Integer constant macro value is too large for the specified type | +| test.c:99:13:99:19 | - ... | Integer constant macro value is too large for the specified type | +| test.c:109:14:109:24 | 4294967296 | Integer constant macro value is too large for the specified type | +| test.c:110:14:110:25 | 4294967296 | Integer constant macro value is too large for the specified type | +| test.c:120:13:120:22 | 2147483648 | Integer constant macro value is too large for the specified type | +| test.c:121:13:121:22 | 2147483648 | Integer constant macro value is too large for the specified type | +| test.c:124:13:124:23 | - ... | Integer constant macro value is too large for the specified type | +| test.c:125:13:125:23 | - ... | Integer constant macro value is too large for the specified type | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..ca6959acec --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected new file mode 100644 index 0000000000..cabe2c5c51 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected @@ -0,0 +1,5 @@ +| test.c:16:13:16:14 | 1 | Integer constant macro arguments should not have 'u'/'l' suffix. | +| test.c:17:13:17:14 | 2 | Integer constant macro arguments should not have 'u'/'l' suffix. | +| test.c:18:13:18:14 | 3 | Integer constant macro arguments should not have 'u'/'l' suffix. | +| test.c:19:13:19:14 | 4 | Integer constant macro arguments should not have 'u'/'l' suffix. | +| test.c:20:13:20:15 | 5 | Integer constant macro arguments should not have 'u'/'l' suffix. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref new file mode 100644 index 0000000000..afadb6e34b --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected index b38863eccd..16e28bcd84 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -1,55 +1,5 @@ -| test.c:12:13:12:15 | 1.0 | Invalid integer constant macro: invalid literal type | -| test.c:13:13:12:15 | 0b111 | Invalid integer constant macro: invalid literal type | -| test.c:16:13:16:14 | 1 | Invalid integer constant macro: literal suffixes not allowed | -| test.c:17:13:17:14 | 2 | Invalid integer constant macro: literal suffixes not allowed | -| test.c:18:13:18:14 | 3 | Invalid integer constant macro: literal suffixes not allowed | -| test.c:19:13:19:14 | 4 | Invalid integer constant macro: literal suffixes not allowed | -| test.c:20:13:20:15 | 5 | Invalid integer constant macro: literal suffixes not allowed | -| test.c:26:13:26:15 | 256 | Invalid integer constant macro: invalid size | -| test.c:27:13:27:16 | 256 | Invalid integer constant macro: invalid size | -| test.c:28:13:28:17 | 256 | Invalid integer constant macro: invalid size | -| test.c:31:13:31:14 | - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:32:13:32:15 | - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:33:13:33:15 | - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:34:13:34:17 | - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:37:13:37:17 | ... + ... | Invalid integer constant macro: invalid expression | -| test.c:38:13:38:18 | access to array | Invalid integer constant macro: invalid expression | -| test.c:39:13:39:18 | access to array | Invalid integer constant macro: invalid expression | -| test.c:40:13:39:18 | UINT8_MAX | Invalid integer constant macro: invalid expression | -| test.c:54:12:54:15 | 191 | Invalid integer constant macro: invalid size | -| test.c:55:12:55:14 | 255 | Invalid integer constant macro: invalid size | -| test.c:56:12:56:15 | 192 | Invalid integer constant macro: invalid size | -| test.c:57:12:57:15 | 128 | Invalid integer constant macro: invalid size | -| test.c:61:12:57:15 | -129 | Invalid integer constant macro: invalid size | -| test.c:62:12:57:15 | -129 | Invalid integer constant macro: invalid size | -| test.c:63:12:57:15 | -201 | Invalid integer constant macro: invalid size | -| test.c:64:12:57:15 | -0x81 | Invalid integer constant macro: invalid size | -| test.c:76:14:76:18 | 65536 | Invalid integer constant macro: invalid size | -| test.c:78:14:78:20 | 65536 | Invalid integer constant macro: invalid size | -| test.c:91:13:91:17 | 32768 | Invalid integer constant macro: invalid size | -| test.c:93:13:93:18 | 32768 | Invalid integer constant macro: invalid size | -| test.c:97:13:93:18 | -32769 | Invalid integer constant macro: invalid size | -| test.c:98:13:93:18 | -040001 | Invalid integer constant macro: invalid size | -| test.c:99:13:93:18 | -0x8001 | Invalid integer constant macro: invalid size | -| test.c:109:14:109:24 | 4294967296 | Invalid integer constant macro: invalid size | -| test.c:110:14:110:25 | 4294967296 | Invalid integer constant macro: invalid size | -| test.c:120:13:120:22 | 2147483648 | Invalid integer constant macro: invalid size | -| test.c:121:13:121:23 | 34359738368 | Invalid integer constant macro: invalid size | -| test.c:130:14:130:15 | 0 | Invalid integer constant macro: invalid size | -| test.c:133:14:133:34 | 18446744073709551615 | Invalid integer constant macro: invalid size | -| test.c:134:14:134:32 | 18446744073709551615 | Invalid integer constant macro: invalid size | -| test.c:140:13:140:14 | 0 | Invalid integer constant macro: invalid size | -| test.c:143:13:143:32 | 9223372036854775807 | Invalid integer constant macro: invalid size | -| test.c:147:13:147:33 | - ... | Invalid integer constant macro: invalid size | -| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid expression | -| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid literal type | -| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: invalid size | -| test.c:148:13:148:37 | ... - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid expression | -| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid literal type | -| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: invalid size | -| test.c:150:13:150:37 | ... - ... | Invalid integer constant macro: signed/unsigned mismatch | -| test.c:152:13:152:31 | 9223372036854775807 | Invalid integer constant macro: invalid size | -| test.c:153:13:153:31 | 9223372036854775808 | Invalid integer constant macro: invalid size | -| test.c:154:13:154:31 | - ... | Invalid integer constant macro: invalid size | -| test.c:155:13:155:30 | - ... | Invalid integer constant macro: invalid size | +| test.c:37:13:37:17 | ... + ... | Integer constant macro argument must be an integer literal. | +| test.c:38:13:38:18 | access to array | Integer constant macro argument must be an integer literal. | +| test.c:39:13:39:19 | access to array | Integer constant macro argument must be an integer literal. | +| test.c:152:13:152:37 | ... - ... | Integer constant macro argument must be an integer literal. | +| test.c:153:13:153:47 | ... - ... | Integer constant macro argument must be an integer literal. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..9d8c525527 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected @@ -0,0 +1,2 @@ +| test.c:12:13:12:15 | 1.0 | Integer constant macro arguments must be a decimal, octal, or hex integer literal. | +| test.c:13:13:13:17 | 7 | Integer constant macro arguments must be a decimal, octal, or hex integer literal. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..5584fe8d46 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index 4412bdf82f..f9650254ca 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -2,101 +2,101 @@ uint_least8_t g1[] = { // Basic valid - UINT8_C(0), // COMPLIANT - UINT8_C(1), // COMPLIANT - UINT8_C(8), // COMPLIANT + UINT8_C(0), // COMPLIANT + UINT8_C(1), // COMPLIANT + UINT8_C(8), // COMPLIANT UINT8_C(0x23), // COMPLIANT - UINT8_C(034), // COMPLIANT + UINT8_C(034), // COMPLIANT // Incorrect literal types - UINT8_C(1.0), // NON-COMPLIANT + UINT8_C(1.0), // NON-COMPLIANT UINT8_C(0b111), // NON-COMPLIANT // Suffixes disallowed - UINT8_C(1u), // NON-COMPLIANT - UINT8_C(2U), // NON-COMPLIANT - UINT8_C(3l), // NON-COMPLIANT - UINT8_C(4L), // NON-COMPLIANT + UINT8_C(1u), // NON-COMPLIANT + UINT8_C(2U), // NON-COMPLIANT + UINT8_C(3l), // NON-COMPLIANT + UINT8_C(4L), // NON-COMPLIANT UINT8_C(5ul), // NON-COMPLIANT // Range tests - UINT8_C(255), // COMPLIANT - UINT8_C(0xFF), // COMPLIANT - UINT8_C(0377), // COMPLIANT - UINT8_C(256), // NON-COMPLIANT - UINT8_C(0400), // NON-COMPLIANT + UINT8_C(255), // COMPLIANT + UINT8_C(0xFF), // COMPLIANT + UINT8_C(0377), // COMPLIANT + UINT8_C(256), // NON-COMPLIANT + UINT8_C(0400), // NON-COMPLIANT UINT8_C(0x100), // NON-COMPLIANT // Signage tests - UINT8_C(-1), // NON-COMPLIANT - UINT8_C(-20), // NON-COMPLIANT - UINT8_C(-33), // NON-COMPLIANT + UINT8_C(-1), // NON-COMPLIANT + UINT8_C(-20), // NON-COMPLIANT + UINT8_C(-33), // NON-COMPLIANT UINT8_C(-0x44), // NON-COMPLIANT // Invalid nonliteral expressions - UINT8_C(0 + 0), // NON-COMPLIANT - UINT8_C("a"[0]), // NON-COMPLIANT - UINT8_C(0["a"]), // NON-COMPLIANT - UINT8_C(UINT8_MAX), // NON-COMPLIANT + UINT8_C(0 + 0), // NON-COMPLIANT + UINT8_C("a"[0]), // NON-COMPLIANT + UINT8_C(0 ["a"]), // NON-COMPLIANT + UINT8_C(UINT8_MAX), // COMPLIANT }; int_least8_t g2[] = { // Basic valid - INT8_C(0), // COMPLIANT - INT8_C(1), // COMPLIANT - INT8_C(8), // COMPLIANT + INT8_C(0), // COMPLIANT + INT8_C(1), // COMPLIANT + INT8_C(8), // COMPLIANT INT8_C(0x23), // COMPLIANT - INT8_C(034), // COMPLIANT + INT8_C(034), // COMPLIANT // Range tests - INT8_C(127), // COMPLIANT - INT8_C(0x79), // COMPLIANT - INT8_C(0177), // COMPLIANT - INT8_C(128), // NON-COMPLIANT - INT8_C(0200), // NON-COMPLIANT - INT8_C(0x80), // NON-COMPLIANT - INT8_C(-128), // COMPLIANT + INT8_C(127), // COMPLIANT + INT8_C(0x79), // COMPLIANT + INT8_C(0177), // COMPLIANT + INT8_C(128), // NON-COMPLIANT + INT8_C(0200), // NON-COMPLIANT + INT8_C(0x80), // NON-COMPLIANT + INT8_C(-128), // COMPLIANT INT8_C(-0x80), // COMPLIANT INT8_C(-0200), // COMPLIANT - INT8_C(-129), // NON-COMPLIANT + INT8_C(-129), // NON-COMPLIANT INT8_C(-0201), // NON-COMPLIANT INT8_C(-0x81), // NON-COMPLIANT }; uint_least16_t g3[] = { // Basic valid - UINT16_C(0), // COMPLIANT + UINT16_C(0), // COMPLIANT UINT16_C(0x23), // COMPLIANT - UINT16_C(034), // COMPLIANT + UINT16_C(034), // COMPLIANT // Range tests - UINT16_C(65535), // COMPLIANT - UINT16_C(0xFFFF), // COMPLIANT + UINT16_C(65535), // COMPLIANT + UINT16_C(0xFFFF), // COMPLIANT UINT16_C(0177777), // COMPLIANT - UINT16_C(65536), // NON-COMPLIANT + UINT16_C(65536), // NON-COMPLIANT UINT16_C(0200000), // NON-COMPLIANT UINT16_C(0x10000), // NON-COMPLIANT }; int_least16_t g4[] = { // Basic valid - INT16_C(0), // COMPLIANT + INT16_C(0), // COMPLIANT INT16_C(0x23), // COMPLIANT - INT16_C(034), // COMPLIANT + INT16_C(034), // COMPLIANT // Range tests - INT16_C(32767), // COMPLIANT - INT16_C(0x7FFF), // COMPLIANT - INT16_C(077777), // COMPLIANT - INT16_C(32768), // NON-COMPLIANT - INT16_C(0100000), // NON-COMPLIANT - INT16_C(0x8000), // NON-COMPLIANT - INT16_C(-32768), // COMPLIANT - INT16_C(-040000), // COMPLIANT - INT16_C(-0x8000), // COMPLIANT - INT16_C(-32769), // NON-COMPLIANT - INT16_C(-040001), // NON-COMPLIANT - INT16_C(-0x8001), // NON-COMPLIANT + INT16_C(32767), // COMPLIANT + INT16_C(0x7FFF), // COMPLIANT + INT16_C(077777), // COMPLIANT + INT16_C(32768), // NON-COMPLIANT + INT16_C(0100000), // NON-COMPLIANT + INT16_C(0x8000), // NON-COMPLIANT + INT16_C(-32768), // COMPLIANT + INT16_C(-0100000), // COMPLIANT + INT16_C(-0x8000), // COMPLIANT + INT16_C(-32769), // NON-COMPLIANT + INT16_C(-0100001), // NON-COMPLIANT + INT16_C(-0x8001), // NON-COMPLIANT }; uint_least32_t g5[] = { @@ -104,9 +104,9 @@ uint_least32_t g5[] = { UINT32_C(0), // COMPLIANT // Range tests - UINT32_C(4294967295), // COMPLIANT - UINT32_C(0xFFFFFFFF), // COMPLIANT - UINT32_C(4294967296), // NON-COMPLIANT + UINT32_C(4294967295), // COMPLIANT + UINT32_C(0xFFFFFFFF), // COMPLIANT + UINT32_C(4294967296), // NON-COMPLIANT UINT32_C(0x100000000), // NON-COMPLIANT }; @@ -115,14 +115,14 @@ int_least32_t g6[] = { INT32_C(0), // COMPLIANT // Range tests - INT32_C(2147483647), // COMPLIANT - INT32_C(0x7FFFFFFF), // COMPLIANT - INT32_C(2147483648), // NON-COMPLIANT - INT32_C(0x800000000), // NON-COMPLIANT + INT32_C(2147483647), // COMPLIANT + INT32_C(0x7FFFFFFF), // COMPLIANT + INT32_C(2147483648), // NON-COMPLIANT + INT32_C(0x80000000), // NON-COMPLIANT INT32_C(-2147483648), // COMPLIANT INT32_C(-0x80000000), // COMPLIANT - INT32_C(-2147483647), // NON-COMPLIANT - INT32_C(-0x800000001), // NON-COMPLIANT + INT32_C(-2147483649), // NON-COMPLIANT + INT32_C(-0x80000001), // NON-COMPLIANT }; uint_least64_t g7[] = { @@ -131,7 +131,7 @@ uint_least64_t g7[] = { // Range tests UINT64_C(18446744073709551615), // COMPLIANT - UINT64_C(0xFFFFFFFFFFFFFFFF), // COMPLIANT + UINT64_C(0xFFFFFFFFFFFFFFFF), // COMPLIANT // Compile time error if we try to create integer literals beyond this. }; @@ -143,14 +143,18 @@ int_least64_t g8[] = { INT64_C(9223372036854775807), // COMPLIANT // INT64_C(9223372036854775808) is a compile-time error - // -9223372036854775808 allowed, but cannot be created via unary- without compile time errors. - INT64_C(-9223372036854775807), // COMPLIANT + // -9223372036854775808 allowed, but cannot be created via unary- without + // compile time errors. + INT64_C(-9223372036854775807), // COMPLIANT INT64_C(-9223372036854775807 - 1), // COMPLIANT - // -9223372036854775809 is not allowed, and cannot be created via unary- without compile time errors. - INT64_C(-9223372036854775807 - 2), // NON-COMPLIANT + // -9223372036854775809 is not allowed, and cannot be created via unary- + // without compile time errors. + INT64_C(-9223372036854775807 - 2), // NON-COMPLIANT + INT64_C(-9223372036854775807 - 20000000000), // NON-COMPLIANT - INT64_C(0x7FFFFFFFFFFFFFFF), // COMPLIANT - INT64_C(0x8000000000000000), // NON-COMPLIANT + INT64_C(0x7FFFFFFFFFFFFFFF), // COMPLIANT + INT64_C(0x8000000000000000), // NON-COMPLIANT[FALSE NEGATIVE] INT64_C(-0x8000000000000000), // COMPLIANT - INT64_C(-0x8000000000000001), // NON-COMPLIANT + INT64_C(-0x8000000000000001), // NON-COMPLIANT[FALSE NEGATIVE] + INT64_C(-0x8001000000000000), // NON-COMPLIANT }; \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll index 472866fdea..e38293c8cb 100644 --- a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -1,35 +1,35 @@ import cpp +/** + * The family of macros `xINTsize_C(arg)` (e.g. `UINT16_C(123)`) which are used + * to create an integer constant of type `Xint_leastSIZE_t` (e.g. + * `uint_least16_t). + */ class IntegerConstantMacro extends Macro { boolean signed; int size; + IntegerConstantMacro() { - ( signed = true and size = getName().regexpCapture("INT(8|16|32|64)_C", 1).toInt() - ) or ( + or signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() - ) } - predicate isSmall() { - size < 32 - } + predicate isSmall() { size < 32 } - int getSize() { - result = size - } + int getSize() { result = size } - predicate isSigned() { - signed = true - } + predicate isSigned() { signed = true } - int maxValue() { - (signed = true and result = 2.pow(getSize() - 1) - 1) or - (signed = false and result = 2.pow(getSize()) - 1) + float maxValue() { + signed = true and result = 2.pow(size - 1 * 1.0) - 1 + or + signed = false and result = 2.pow(size) - 1 } - int minValue() { - (signed = true and result = -(2.0.pow(getSize() - 1))) or - (signed = false and result = 0) + float minValue() { + signed = true and result = -2.pow(size - 1) + or + signed = false and result = 0 } -} \ No newline at end of file +} diff --git a/cpp/common/src/codingstandards/cpp/Literals.qll b/cpp/common/src/codingstandards/cpp/Literals.qll index 66e15b28dc..cc0d28dec9 100644 --- a/cpp/common/src/codingstandards/cpp/Literals.qll +++ b/cpp/common/src/codingstandards/cpp/Literals.qll @@ -4,6 +4,7 @@ import cpp import codingstandards.cpp.Cpp14Literal +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis class IntegerLiteral = Cpp14Literal::IntegerLiteral; @@ -70,3 +71,46 @@ class BoolLiteral extends Literal { this.getValue() = "0" and this.getValueText() = "false" } } + +/** + * Abstract case to handle positive and negative "literal" expressions. + * + * All numeric literals in c/cpp are positive. To create a negative constant + * value in a program means applying the unary- operator to a positive literal. + * This class effectively describes positive or negative literals. + */ +abstract class PossiblyNegativeLiteral extends Expr { + /* The syntactic literal, stripped of potential negation */ + abstract Cpp14Literal::NumericLiteral getBaseLiteral(); + + /* The value as a literal reads, without potential underflows from negation */ + abstract float getRawValue(); + + predicate isNegative() { this instanceof NegativeLiteral } +} + +/** + * A negation of a positive literal, creating what can be thought of as a + * "negative literal." + */ +class NegativeLiteral extends PossiblyNegativeLiteral, UnaryMinusExpr { + Cpp14Literal::NumericLiteral literal; + + NegativeLiteral() { literal = getOperand() } + + override Cpp14Literal::NumericLiteral getBaseLiteral() { result = literal } + + override float getRawValue() { result = -lowerBound(literal) } +} + +/** + * A literal which is not immediately negated by a parent unary- expression, + * which can be thought of as a "positive literal." + */ +class PositiveLiteral extends PossiblyNegativeLiteral, Cpp14Literal::NumericLiteral { + PositiveLiteral() { not exists(UnaryMinusExpr l | l.getOperand() = this) } + + override Cpp14Literal::NumericLiteral getBaseLiteral() { result = this } + + override float getRawValue() { result = lowerBound(this) } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll index fbb5d06ee4..3b2d3a4342 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll @@ -5,6 +5,9 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype Types2Query = TInvalidIntegerConstantMacroArgumentQuery() or + TInvalidLiteralForIntegerConstantMacroArgumentQuery() or + TIntegerConstantMacroArgumentUsesSuffixQuery() or + TIncorrectlySizedIntegerConstantMacroArgumentQuery() or TUseOfBannedSmallIntegerConstantMacroQuery() predicate isTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { @@ -17,6 +20,33 @@ predicate isTypes2QueryMetadata(Query query, string queryId, string ruleId, stri ruleId = "RULE-7-5" and category = "required" or + query = + // `Query` instance for the `invalidLiteralForIntegerConstantMacroArgument` query + Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `invalidLiteralForIntegerConstantMacroArgument` query + "c/misra/invalid-literal-for-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `integerConstantMacroArgumentUsesSuffix` query + Types2Package::integerConstantMacroArgumentUsesSuffixQuery() and + queryId = + // `@id` for the `integerConstantMacroArgumentUsesSuffix` query + "c/misra/integer-constant-macro-argument-uses-suffix" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `incorrectlySizedIntegerConstantMacroArgument` query + Types2Package::incorrectlySizedIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `incorrectlySizedIntegerConstantMacroArgument` query + "c/misra/incorrectly-sized-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or query = // `Query` instance for the `useOfBannedSmallIntegerConstantMacro` query Types2Package::useOfBannedSmallIntegerConstantMacroQuery() and @@ -35,6 +65,27 @@ module Types2Package { TQueryC(TTypes2PackageQuery(TInvalidIntegerConstantMacroArgumentQuery())) } + Query invalidLiteralForIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidLiteralForIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TInvalidLiteralForIntegerConstantMacroArgumentQuery())) + } + + Query integerConstantMacroArgumentUsesSuffixQuery() { + //autogenerate `Query` type + result = + // `Query` type for `integerConstantMacroArgumentUsesSuffix` query + TQueryC(TTypes2PackageQuery(TIntegerConstantMacroArgumentUsesSuffixQuery())) + } + + Query incorrectlySizedIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incorrectlySizedIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TIncorrectlySizedIntegerConstantMacroArgumentQuery())) + } + Query useOfBannedSmallIntegerConstantMacroQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json index 9468af278c..6933d3eb63 100644 --- a/rule_packages/c/Types2.json +++ b/rule_packages/c/Types2.json @@ -6,15 +6,52 @@ }, "queries": [ { - "description": "Integer constant macros should be given appropriate values for the size of the integer type.", + "description": "Integer constant macros should be given a literal value as an argument", "kind": "problem", - "name": "The argument of an integer constant macro shall have an appropriate form", + "name": "The argument of an integer constant macro shall be a literal", "precision": "very-high", "severity": "error", "short_name": "InvalidIntegerConstantMacroArgument", "tags": [ "correctness" ] + }, + { + "description": "Integer constant macro arguments should be a decimal, hex, or octal literal", + "kind": "problem", + "name": "The argument of an integer constant macro shall be a decimal, hex, or octal literal", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidLiteralForIntegerConstantMacroArgument", + "tags": [ + "correctness" + ] + }, + { + "description": "Integer constant macros should be used integer literal values with no u/l suffix.", + "kind": "problem", + "name": "The argument of an integer constant macro shall not use literal suffixes u, l, or ul", + "precision": "very-high", + "severity": "error", + "short_name": "IntegerConstantMacroArgumentUsesSuffix", + "tags": [ + "readability", + "maintainability" + ] + }, + { + "description": "Integer constant macros argument values should be values of a compatible size", + "kind": "problem", + "name": "The argument of an integer constant macro shall have an appropriate size", + "precision": "very-high", + "severity": "error", + "short_name": "IncorrectlySizedIntegerConstantMacroArgument", + "tags": [ + "correctness" + ], + "implementation_scope": { + "description": "This rule can validate integers sized 32 or smaller. When the CodeQL runtime supports big ints, this will be expanded to include 64 bit integer types." + } } ], "title": "The argument of an integer constant macro shall have an appropriate form" From 67d5426e048f1b84e965a477c283a09421dfd9e1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 16:51:54 -0700 Subject: [PATCH 03/17] Fix 7-6 formatting --- .../RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql | 8 +++----- c/misra/test/rules/RULE-7-6/test.c | 10 +++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql index cac7f091a8..9a1844601b 100644 --- a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql +++ b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql @@ -15,11 +15,9 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.IntegerConstantMacro - from MacroInvocation macroInvoke, IntegerConstantMacro macro where not isExcluded(macroInvoke, Types2Package::useOfBannedSmallIntegerConstantMacroQuery()) and - macroInvoke.getMacro() = macro - and macro.isSmall() -select - macroInvoke, "Usage of small integer constant macro " + macro.getName() + " is not allowed." + macroInvoke.getMacro() = macro and + macro.isSmall() +select macroInvoke, "Usage of small integer constant macro " + macro.getName() + " is not allowed." diff --git a/c/misra/test/rules/RULE-7-6/test.c b/c/misra/test/rules/RULE-7-6/test.c index f2b783e800..9832cdf251 100644 --- a/c/misra/test/rules/RULE-7-6/test.c +++ b/c/misra/test/rules/RULE-7-6/test.c @@ -1,10 +1,10 @@ #include "stdint.h" -int8_t g1 = INT8_C(0x12); // NON-COMPLIANT -uint8_t g2 = UINT8_C(0x12); // NON-COMPLIANT -int16_t g3 = INT16_C(0x1234); // NON-COMPLIANT +int8_t g1 = INT8_C(0x12); // NON-COMPLIANT +uint8_t g2 = UINT8_C(0x12); // NON-COMPLIANT +int16_t g3 = INT16_C(0x1234); // NON-COMPLIANT uint16_t g4 = UINT16_C(0x1234); // NON-COMPLIANT -int32_t g5 = INT32_C(0x1234); // COMPLIANT +int32_t g5 = INT32_C(0x1234); // COMPLIANT uint32_t g6 = UINT32_C(0x1234); // COMPLIANT -int64_t g7 = INT64_C(0x1234); // COMPLIANT +int64_t g7 = INT64_C(0x1234); // COMPLIANT uint64_t g8 = UINT64_C(0x1234); // COMPLIANT \ No newline at end of file From 24984097e6e9ac62be452367e1dbe4731fe81f15 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 16:53:50 -0700 Subject: [PATCH 04/17] Add full stops to Types.json --- rule_packages/c/Types2.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json index 6933d3eb63..4c4aaaaa7a 100644 --- a/rule_packages/c/Types2.json +++ b/rule_packages/c/Types2.json @@ -6,7 +6,7 @@ }, "queries": [ { - "description": "Integer constant macros should be given a literal value as an argument", + "description": "Integer constant macros should be given a literal value as an argument.", "kind": "problem", "name": "The argument of an integer constant macro shall be a literal", "precision": "very-high", @@ -17,7 +17,7 @@ ] }, { - "description": "Integer constant macro arguments should be a decimal, hex, or octal literal", + "description": "Integer constant macro arguments should be a decimal, hex, or octal literal.", "kind": "problem", "name": "The argument of an integer constant macro shall be a decimal, hex, or octal literal", "precision": "very-high", @@ -40,7 +40,7 @@ ] }, { - "description": "Integer constant macros argument values should be values of a compatible size", + "description": "Integer constant macros argument values should be values of a compatible size.", "kind": "problem", "name": "The argument of an integer constant macro shall have an appropriate size", "precision": "very-high", From 9696f7b4c7b14abd24773ab9045df5803610cf64 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 16:55:11 -0700 Subject: [PATCH 05/17] Add full stops to query metadata. --- .../RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql | 2 +- .../src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql | 2 +- .../RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql index dd1417c2a6..b0ed49f9cc 100644 --- a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -1,7 +1,7 @@ /** * @id c/misra/incorrectly-sized-integer-constant-macro-argument * @name RULE-7-5: The argument of an integer constant macro shall have an appropriate size - * @description Integer constant macros argument values should be values of a compatible size + * @description Integer constant macros argument values should be values of a compatible size. * @kind problem * @precision very-high * @problem.severity error diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index 33ec266b51..b7516a1ff8 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -1,7 +1,7 @@ /** * @id c/misra/invalid-integer-constant-macro-argument * @name RULE-7-5: The argument of an integer constant macro shall be a literal - * @description Integer constant macros should be given a literal value as an argument + * @description Integer constant macros should be given a literal value as an argument. * @kind problem * @precision very-high * @problem.severity error diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql index 2447d82f6f..7d102f667b 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -1,7 +1,7 @@ /** * @id c/misra/invalid-literal-for-integer-constant-macro-argument * @name RULE-7-5: The argument of an integer constant macro shall be a decimal, hex, or octal literal - * @description Integer constant macro arguments should be a decimal, hex, or octal literal + * @description Integer constant macro arguments should be a decimal, hex, or octal literal. * @kind problem * @precision very-high * @problem.severity error From 916ef4dec056d4280505e2b3497222693ff4003c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 1 Oct 2024 16:56:18 -0700 Subject: [PATCH 06/17] Handle cases where AST/extractor give us incomplete/messy information. Add a new UnrecognizedNumericLiteral class in Literal.qll which matches literals that have a numeric value but don't match any regexes for the literal types (hex, decimal, float, octal, binary). Exclude that from results in InvalidLiteralForIntegerConstantMacroArgument.ql --- ...dLiteralForIntegerConstantMacroArgument.ql | 4 ++- c/misra/test/rules/RULE-7-5/test.c | 9 +++++- .../src/codingstandards/cpp/Cpp14Literal.qll | 30 +++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql index 7d102f667b..893151f2be 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -23,7 +23,9 @@ import codingstandards.cpp.Literals predicate validLiteralType(PossiblyNegativeLiteral literal) { literal.getBaseLiteral() instanceof Cpp14Literal::DecimalLiteral or literal.getBaseLiteral() instanceof Cpp14Literal::OctalLiteral or - literal.getBaseLiteral() instanceof Cpp14Literal::HexLiteral + literal.getBaseLiteral() instanceof Cpp14Literal::HexLiteral or + // Ignore cases where the AST/extractor don't give us enough information: + literal.getBaseLiteral() instanceof Cpp14Literal::UnrecognizedNumericLiteral } /** diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index f9650254ca..027ecb1827 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -157,4 +157,11 @@ int_least64_t g8[] = { INT64_C(-0x8000000000000000), // COMPLIANT INT64_C(-0x8000000000000001), // NON-COMPLIANT[FALSE NEGATIVE] INT64_C(-0x8001000000000000), // NON-COMPLIANT -}; \ No newline at end of file +}; + +// Other edge cases: +void f(void) { + uint32_t l1 = 1; + // `UnrecognizedNumericLiteral` case: + int64_t l2 = ((int32_t)UINT64_C(0x1b2) * (l1)); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index c974ec7eb8..b77702fef6 100644 --- a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll +++ b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll @@ -9,6 +9,9 @@ module Cpp14Literal { /** An numeric literal. */ abstract class NumericLiteral extends StandardLibrary::Literal { } + /** Convenience for implementing class `UnrecognizedNumericLiteral` */ + abstract private class RecognizedNumericLiteral extends StandardLibrary::Literal { } + /** An integer literal. */ abstract class IntegerLiteral extends NumericLiteral { predicate isSigned() { not isUnsigned() } @@ -23,7 +26,7 @@ module Cpp14Literal { * ``` * Octal literals must always start with the digit `0`. */ - class OctalLiteral extends IntegerLiteral { + class OctalLiteral extends IntegerLiteral, RecognizedNumericLiteral { OctalLiteral() { getValueText().regexpMatch("\\s*0[0-7']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "OctalLiteral" } @@ -35,7 +38,7 @@ module Cpp14Literal { * unsigned int32_t minus2 = 0xfffffffe; * ``` */ - class HexLiteral extends IntegerLiteral { + class HexLiteral extends IntegerLiteral, RecognizedNumericLiteral { HexLiteral() { getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F']+[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "HexLiteral" } @@ -47,7 +50,7 @@ module Cpp14Literal { * unsigned int32_t binary = 0b101010; * ``` */ - class BinaryLiteral extends IntegerLiteral { + class BinaryLiteral extends IntegerLiteral, RecognizedNumericLiteral { BinaryLiteral() { getValueText().regexpMatch("\\s*0[bB][0-1']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "BinaryLiteral" } @@ -59,7 +62,7 @@ module Cpp14Literal { * unsigned int32_t decimal = 10340923; * ``` */ - class DecimalLiteral extends IntegerLiteral { + class DecimalLiteral extends IntegerLiteral, RecognizedNumericLiteral { DecimalLiteral() { getValueText().regexpMatch("\\s*[1-9][0-9']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "DecimalLiteral" } @@ -71,7 +74,7 @@ module Cpp14Literal { * double floating = 1.340923e-19; * ``` */ - class FloatingLiteral extends NumericLiteral { + class FloatingLiteral extends RecognizedNumericLiteral { FloatingLiteral() { getValueText().regexpMatch("\\s*[0-9][0-9']*(\\.[0-9']+)?([eE][\\+\\-]?[0-9']+)?[flFL]?\\s*") and // A decimal literal takes precedent @@ -83,6 +86,23 @@ module Cpp14Literal { override string getAPrimaryQlClass() { result = "FloatingLiteral" } } + /** + * Literal values with conversions and macros cannot always be trivially + * parsed from `Literal.getValueText()`, and have loss of required + * information in `Literal.getValue()`. This class covers cases that appear + * to be `NumericLiteral`s but cannot be determined to be a hex, decimal, + * octal, binary, or float literal, but still are parsed as a Literal with a + * number value. + */ + class UnrecognizedNumericLiteral extends NumericLiteral { + UnrecognizedNumericLiteral() { + this.getValue().regexpMatch("[0-9.e]+") and + not this instanceof RecognizedNumericLiteral + } + } + + predicate test(RecognizedNumericLiteral r, string valueText) { valueText = r.getValueText() } + /** * A character literal. For example: * ``` From c9436f9af3d46f6d86bbf06e0f15faec7d854d74 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 09:33:20 -0700 Subject: [PATCH 07/17] Fix broken test, remove debug code --- cpp/common/src/codingstandards/cpp/Cpp14Literal.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index b77702fef6..ca3a7fb251 100644 --- a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll +++ b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll @@ -74,7 +74,7 @@ module Cpp14Literal { * double floating = 1.340923e-19; * ``` */ - class FloatingLiteral extends RecognizedNumericLiteral { + class FloatingLiteral extends NumericLiteral, RecognizedNumericLiteral { FloatingLiteral() { getValueText().regexpMatch("\\s*[0-9][0-9']*(\\.[0-9']+)?([eE][\\+\\-]?[0-9']+)?[flFL]?\\s*") and // A decimal literal takes precedent @@ -101,8 +101,6 @@ module Cpp14Literal { } } - predicate test(RecognizedNumericLiteral r, string valueText) { valueText = r.getValueText() } - /** * A character literal. For example: * ``` From 581eb32720ac0a86bb4fa94b8b0d068455fe18ab Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 11:33:20 -0700 Subject: [PATCH 08/17] Add more info to query result strings --- ...rectlySizedIntegerConstantMacroArgument.ql | 7 ++- .../IntegerConstantMacroArgumentUsesSuffix.ql | 12 ++-- .../InvalidIntegerConstantMacroArgument.ql | 3 +- ...dLiteralForIntegerConstantMacroArgument.ql | 17 +++++- ...SizedIntegerConstantMacroArgument.expected | 58 ++++++++++--------- ...erConstantMacroArgumentUsesSuffix.expected | 12 ++-- ...validIntegerConstantMacroArgument.expected | 10 ++-- ...alForIntegerConstantMacroArgument.expected | 5 +- c/misra/test/rules/RULE-7-5/test.c | 18 +++--- .../cpp/IntegerConstantMacro.qll | 4 ++ 10 files changed, 89 insertions(+), 57 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql index b0ed49f9cc..06a7eb7658 100644 --- a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -37,8 +37,9 @@ where invoke.getMacro() = macro and literal = invoke.getExpr() and ( - not matchesSign(macro, invoke.getExpr()) and explanation = "cannot be negative" + not matchesSign(macro, invoke.getExpr()) and explanation = " cannot be negative" or - not matchesSize(macro, invoke.getExpr()) and explanation = "is too large for the specified type" + not matchesSize(macro, invoke.getExpr()) and + explanation = " is outside of the allowed range " + macro.getRangeString() ) -select invoke.getExpr(), "Integer constant macro value " + explanation +select invoke.getExpr(), "Value provided to integer constant macro " + macro.getName() + explanation diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql index f4ca73e16c..15243ecb29 100644 --- a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -16,14 +16,16 @@ import codingstandards.c.misra import codingstandards.cpp.IntegerConstantMacro import codingstandards.cpp.Literals -predicate usesSuffix(MacroInvocation invoke) { - invoke.getUnexpandedArgument(0).regexpMatch(".*[uUlL]") +string argumentSuffix(MacroInvocation invoke) { + result = invoke.getUnexpandedArgument(0).regexpCapture(".*[^uUlL]([uUlL]+)$", 1) } -from MacroInvocation invoke, PossiblyNegativeLiteral argument +from MacroInvocation invoke, PossiblyNegativeLiteral argument, string suffix where not isExcluded(invoke, Types2Package::integerConstantMacroArgumentUsesSuffixQuery()) and invoke.getMacro() instanceof IntegerConstantMacro and invoke.getExpr() = argument and - usesSuffix(invoke) -select invoke.getExpr(), "Integer constant macro arguments should not have 'u'/'l' suffix." + suffix = argumentSuffix(invoke) +select invoke.getExpr(), + "Value suffix '" + suffix + "' is not allowed on provided argument to integer constant macro " + + invoke.getMacroName() + "." diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index b7516a1ff8..7b20159bb0 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -38,4 +38,5 @@ where invoke.getMacro() = macro and not invoke.getExpr() instanceof PossiblyNegativeLiteral and not specialMaxNegative64Exception(macro, invoke.getExpr()) -select invoke.getExpr(), "Integer constant macro argument must be an integer literal." +select invoke.getExpr(), + "Argument to integer constant macro " + macro.getName() + " must be an integer literal." diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql index 893151f2be..9d3cd33d00 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -37,6 +37,18 @@ predicate seemsBinaryLiteral(MacroInvocation invoke) { invoke.getUnexpandedArgument(0).regexpMatch("0[bB][01]+") } +string explainIncorrectArgument(MacroInvocation invoke) { + if seemsBinaryLiteral(invoke) + then result = "binary literal" + else + exists(PossiblyNegativeLiteral literal | + literal = invoke.getExpr() and + if literal.getBaseLiteral() instanceof Cpp14Literal::FloatingLiteral + then result = "floating point literal" + else result = "invalid literal" + ) +} + from MacroInvocation invoke, PossiblyNegativeLiteral literal where not isExcluded(invoke, Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery()) and @@ -46,4 +58,7 @@ where not validLiteralType(literal) or seemsBinaryLiteral(invoke) ) -select literal, "Integer constant macro arguments must be a decimal, octal, or hex integer literal." +select literal, + "Integer constant macro " + invoke.getMacroName() + " used with " + + explainIncorrectArgument(invoke) + + " argument, only decimal, octal, or hex integer literal allowed." diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected index 9ce9b29e3c..08816f8351 100644 --- a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected @@ -1,28 +1,30 @@ -| test.c:26:13:26:15 | 256 | Integer constant macro value is too large for the specified type | -| test.c:27:13:27:16 | 256 | Integer constant macro value is too large for the specified type | -| test.c:28:13:28:17 | 256 | Integer constant macro value is too large for the specified type | -| test.c:31:13:31:14 | - ... | Integer constant macro value cannot be negative | -| test.c:32:13:32:15 | - ... | Integer constant macro value cannot be negative | -| test.c:33:13:33:15 | - ... | Integer constant macro value cannot be negative | -| test.c:34:13:34:17 | - ... | Integer constant macro value cannot be negative | -| test.c:55:12:55:14 | 128 | Integer constant macro value is too large for the specified type | -| test.c:56:12:56:15 | 128 | Integer constant macro value is too large for the specified type | -| test.c:57:12:57:15 | 128 | Integer constant macro value is too large for the specified type | -| test.c:61:12:61:15 | - ... | Integer constant macro value is too large for the specified type | -| test.c:62:12:62:16 | - ... | Integer constant macro value is too large for the specified type | -| test.c:63:12:63:16 | - ... | Integer constant macro value is too large for the specified type | -| test.c:76:14:76:18 | 65536 | Integer constant macro value is too large for the specified type | -| test.c:77:14:77:20 | 65536 | Integer constant macro value is too large for the specified type | -| test.c:78:14:78:20 | 65536 | Integer constant macro value is too large for the specified type | -| test.c:91:13:91:17 | 32768 | Integer constant macro value is too large for the specified type | -| test.c:92:13:92:19 | 32768 | Integer constant macro value is too large for the specified type | -| test.c:93:13:93:18 | 32768 | Integer constant macro value is too large for the specified type | -| test.c:97:13:97:18 | - ... | Integer constant macro value is too large for the specified type | -| test.c:98:13:98:20 | - ... | Integer constant macro value is too large for the specified type | -| test.c:99:13:99:19 | - ... | Integer constant macro value is too large for the specified type | -| test.c:109:14:109:24 | 4294967296 | Integer constant macro value is too large for the specified type | -| test.c:110:14:110:25 | 4294967296 | Integer constant macro value is too large for the specified type | -| test.c:120:13:120:22 | 2147483648 | Integer constant macro value is too large for the specified type | -| test.c:121:13:121:22 | 2147483648 | Integer constant macro value is too large for the specified type | -| test.c:124:13:124:23 | - ... | Integer constant macro value is too large for the specified type | -| test.c:125:13:125:23 | - ... | Integer constant macro value is too large for the specified type | \ No newline at end of file +| test.c:13:13:13:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:15:13:15:18 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:30:13:30:15 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:31:13:31:16 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:32:13:32:17 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:35:13:35:14 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:36:13:36:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:37:13:37:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:38:13:38:17 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:59:12:59:14 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:60:12:60:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:61:12:61:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:65:12:65:15 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:66:12:66:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:67:12:67:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:80:14:80:18 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:81:14:81:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:82:14:82:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:95:13:95:17 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:96:13:96:19 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:97:13:97:18 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:101:13:101:18 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:102:13:102:20 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:103:13:103:19 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:113:14:113:24 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:114:14:114:25 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:124:13:124:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:125:13:125:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:128:13:128:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:129:13:129:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected index cabe2c5c51..52adf1233e 100644 --- a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected @@ -1,5 +1,7 @@ -| test.c:16:13:16:14 | 1 | Integer constant macro arguments should not have 'u'/'l' suffix. | -| test.c:17:13:17:14 | 2 | Integer constant macro arguments should not have 'u'/'l' suffix. | -| test.c:18:13:18:14 | 3 | Integer constant macro arguments should not have 'u'/'l' suffix. | -| test.c:19:13:19:14 | 4 | Integer constant macro arguments should not have 'u'/'l' suffix. | -| test.c:20:13:20:15 | 5 | Integer constant macro arguments should not have 'u'/'l' suffix. | \ No newline at end of file +| test.c:18:13:18:14 | 1 | Value suffix 'u' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:19:13:19:14 | 2 | Value suffix 'U' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:20:13:20:14 | 3 | Value suffix 'l' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:21:13:21:14 | 4 | Value suffix 'L' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:22:13:22:15 | 5 | Value suffix 'ul' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:23:13:23:15 | 5 | Value suffix 'll' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:24:13:24:16 | 5 | Value suffix 'ull' is not allowed on provided argument to integer constant macro UINT8_C. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected index 16e28bcd84..b3191fa74c 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -1,5 +1,5 @@ -| test.c:37:13:37:17 | ... + ... | Integer constant macro argument must be an integer literal. | -| test.c:38:13:38:18 | access to array | Integer constant macro argument must be an integer literal. | -| test.c:39:13:39:19 | access to array | Integer constant macro argument must be an integer literal. | -| test.c:152:13:152:37 | ... - ... | Integer constant macro argument must be an integer literal. | -| test.c:153:13:153:47 | ... - ... | Integer constant macro argument must be an integer literal. | +| test.c:41:13:41:17 | ... + ... | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:42:13:42:18 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:43:13:43:19 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:156:13:156:37 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | +| test.c:157:13:157:47 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected index 9d8c525527..320b6dd208 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected @@ -1,2 +1,3 @@ -| test.c:12:13:12:15 | 1.0 | Integer constant macro arguments must be a decimal, octal, or hex integer literal. | -| test.c:13:13:13:17 | 7 | Integer constant macro arguments must be a decimal, octal, or hex integer literal. | \ No newline at end of file +| test.c:12:13:12:15 | 1.0 | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:13:13:13:16 | - ... | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:14:13:14:17 | 7 | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index 027ecb1827..db145a844b 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -9,15 +9,19 @@ uint_least8_t g1[] = { UINT8_C(034), // COMPLIANT // Incorrect literal types - UINT8_C(1.0), // NON-COMPLIANT - UINT8_C(0b111), // NON-COMPLIANT + UINT8_C(1.0), // NON-COMPLIANT + UINT8_C(-1.0), // NON-COMPLIANT + UINT8_C(0b111), // NON-COMPLIANT + UINT8_C(-0b111), // NON-COMPLIANT // Suffixes disallowed - UINT8_C(1u), // NON-COMPLIANT - UINT8_C(2U), // NON-COMPLIANT - UINT8_C(3l), // NON-COMPLIANT - UINT8_C(4L), // NON-COMPLIANT - UINT8_C(5ul), // NON-COMPLIANT + UINT8_C(1u), // NON-COMPLIANT + UINT8_C(2U), // NON-COMPLIANT + UINT8_C(3l), // NON-COMPLIANT + UINT8_C(4L), // NON-COMPLIANT + UINT8_C(5ul), // NON-COMPLIANT + UINT8_C(5ll), // NON-COMPLIANT + UINT8_C(5ull), // NON-COMPLIANT // Range tests UINT8_C(255), // COMPLIANT diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll index e38293c8cb..c82024f2f0 100644 --- a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -32,4 +32,8 @@ class IntegerConstantMacro extends Macro { or signed = false and result = 0 } + + string getRangeString() { + result = minValue().toString() + ".." + maxValue().toString() + } } From d763b9109aa9f05fda75a2e5fe8ea2fec5f6737d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 11:40:45 -0700 Subject: [PATCH 09/17] Fix format in IntegerConstantMacro.qll --- cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll index c82024f2f0..8f3fff1e1b 100644 --- a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -33,7 +33,5 @@ class IntegerConstantMacro extends Macro { signed = false and result = 0 } - string getRangeString() { - result = minValue().toString() + ".." + maxValue().toString() - } + string getRangeString() { result = minValue().toString() + ".." + maxValue().toString() } } From fdaacc76086c38045c3a335c063d782c38a7e31b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 13:44:39 -0700 Subject: [PATCH 10/17] Reject char literals, add false negatives for macros. --- .../IntegerConstantMacroArgumentUsesSuffix.ql | 9 ++- .../InvalidIntegerConstantMacroArgument.ql | 2 +- ...dLiteralForIntegerConstantMacroArgument.ql | 28 ++++++--- ...SizedIntegerConstantMacroArgument.expected | 61 ++++++++++--------- ...erConstantMacroArgumentUsesSuffix.expected | 14 ++--- ...validIntegerConstantMacroArgument.expected | 10 +-- ...alForIntegerConstantMacroArgument.expected | 10 ++- c/misra/test/rules/RULE-7-5/test.c | 11 ++++ 8 files changed, 88 insertions(+), 57 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql index 15243ecb29..3b58cf7a92 100644 --- a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -3,8 +3,8 @@ * @name RULE-7-5: The argument of an integer constant macro shall not use literal suffixes u, l, or ul * @description Integer constant macros should be used integer literal values with no u/l suffix. * @kind problem - * @precision very-high - * @problem.severity error + * @precision high + * @problem.severity warning * @tags external/misra/id/rule-7-5 * readability * maintainability @@ -17,7 +17,10 @@ import codingstandards.cpp.IntegerConstantMacro import codingstandards.cpp.Literals string argumentSuffix(MacroInvocation invoke) { - result = invoke.getUnexpandedArgument(0).regexpCapture(".*[^uUlL]([uUlL]+)$", 1) + // Compiler strips the suffix unless we look at the unexpanded argument text. + // Unexpanded argument text can be malformed in all sorts of ways, so make + // this match relatively strict, to be safe. + result = invoke.getUnexpandedArgument(0).regexpCapture("([0-9]+|0[xX][0-9A-F]+)([uUlL]+)$", 2) } from MacroInvocation invoke, PossiblyNegativeLiteral argument, string suffix diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index 7b20159bb0..851569899e 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -4,7 +4,7 @@ * @description Integer constant macros should be given a literal value as an argument. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-7-5 * correctness * external/misra/obligation/required diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql index 9d3cd33d00..e333adfb7e 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -34,19 +34,30 @@ predicate validLiteralType(PossiblyNegativeLiteral literal) { * Detect this pattern before macro expansion. */ predicate seemsBinaryLiteral(MacroInvocation invoke) { - invoke.getUnexpandedArgument(0).regexpMatch("0[bB][01]+") + invoke.getUnexpandedArgument(0).regexpMatch("-?0[bB][01]+") +} + +/** + * Extractor converts `xINTsize_C('a')` to a decimal literal. Therefore, detect + * this pattern before macro expansion. + */ +predicate seemsCharLiteral(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch("-?'\\\\?.'") } string explainIncorrectArgument(MacroInvocation invoke) { if seemsBinaryLiteral(invoke) then result = "binary literal" else - exists(PossiblyNegativeLiteral literal | - literal = invoke.getExpr() and - if literal.getBaseLiteral() instanceof Cpp14Literal::FloatingLiteral - then result = "floating point literal" - else result = "invalid literal" - ) + if seemsCharLiteral(invoke) + then result = "char literal" + else + exists(PossiblyNegativeLiteral literal | + literal = invoke.getExpr() and + if literal.getBaseLiteral() instanceof Cpp14Literal::FloatingLiteral + then result = "floating point literal" + else result = "invalid literal" + ) } from MacroInvocation invoke, PossiblyNegativeLiteral literal @@ -56,7 +67,8 @@ where literal = invoke.getExpr() and ( not validLiteralType(literal) or - seemsBinaryLiteral(invoke) + seemsBinaryLiteral(invoke) or + seemsCharLiteral(invoke) ) select literal, "Integer constant macro " + invoke.getMacroName() + " used with " + diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected index 08816f8351..d3724e21a4 100644 --- a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected @@ -1,30 +1,31 @@ -| test.c:13:13:13:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:15:13:15:18 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:30:13:30:15 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | -| test.c:31:13:31:16 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | -| test.c:32:13:32:17 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | -| test.c:35:13:35:14 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:36:13:36:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:37:13:37:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:38:13:38:17 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | -| test.c:59:12:59:14 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:60:12:60:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:61:12:61:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:65:12:65:15 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:66:12:66:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:67:12:67:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | -| test.c:80:14:80:18 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | -| test.c:81:14:81:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | -| test.c:82:14:82:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | -| test.c:95:13:95:17 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:96:13:96:19 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:97:13:97:18 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:101:13:101:18 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:102:13:102:20 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:103:13:103:19 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | -| test.c:113:14:113:24 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | -| test.c:114:14:114:25 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | -| test.c:124:13:124:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | -| test.c:125:13:125:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | -| test.c:128:13:128:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | -| test.c:129:13:129:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:17:13:17:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:19:13:19:18 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:21:13:21:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:37:13:37:15 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:38:13:38:16 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:39:13:39:17 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:42:13:42:14 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:43:13:43:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:44:13:44:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:45:13:45:17 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:70:12:70:14 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:71:12:71:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:72:12:72:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:76:12:76:15 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:77:12:77:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:78:12:78:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:91:14:91:18 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:92:14:92:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:93:14:93:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:106:13:106:17 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:107:13:107:19 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:108:13:108:18 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:112:13:112:18 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:113:13:113:20 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:114:13:114:19 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:124:14:124:24 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:125:14:125:25 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:135:13:135:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:136:13:136:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:139:13:139:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:140:13:140:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected index 52adf1233e..97a35dd977 100644 --- a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected @@ -1,7 +1,7 @@ -| test.c:18:13:18:14 | 1 | Value suffix 'u' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:19:13:19:14 | 2 | Value suffix 'U' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:20:13:20:14 | 3 | Value suffix 'l' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:21:13:21:14 | 4 | Value suffix 'L' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:22:13:22:15 | 5 | Value suffix 'ul' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:23:13:23:15 | 5 | Value suffix 'll' is not allowed on provided argument to integer constant macro UINT8_C. | -| test.c:24:13:24:16 | 5 | Value suffix 'ull' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:25:13:25:14 | 1 | Value suffix 'u' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:26:13:26:14 | 2 | Value suffix 'U' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:27:13:27:14 | 3 | Value suffix 'l' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:28:13:28:14 | 4 | Value suffix 'L' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:29:13:29:15 | 5 | Value suffix 'ul' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:30:13:30:15 | 5 | Value suffix 'll' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:31:13:31:16 | 5 | Value suffix 'ull' is not allowed on provided argument to integer constant macro UINT8_C. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected index b3191fa74c..44b5d78994 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -1,5 +1,5 @@ -| test.c:41:13:41:17 | ... + ... | Argument to integer constant macro UINT8_C must be an integer literal. | -| test.c:42:13:42:18 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | -| test.c:43:13:43:19 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | -| test.c:156:13:156:37 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | -| test.c:157:13:157:47 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | +| test.c:48:13:48:17 | ... + ... | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:49:13:49:18 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:50:13:50:19 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:167:13:167:37 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | +| test.c:168:13:168:47 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected index 320b6dd208..ee5b75cb91 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected @@ -1,3 +1,7 @@ -| test.c:12:13:12:15 | 1.0 | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | -| test.c:13:13:13:16 | - ... | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | -| test.c:14:13:14:17 | 7 | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:16:13:16:15 | 1.0 | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:17:13:17:16 | - ... | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:18:13:18:17 | 7 | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:19:13:19:18 | - ... | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:20:13:20:15 | 97 | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:21:13:21:16 | - ... | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:22:13:22:16 | 10 | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index db145a844b..432c6ceed5 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -1,5 +1,9 @@ +#include "stdbool.h" #include "stdint.h" +#define NULL 0 +#define NULLPTR ((void *)NULL) + uint_least8_t g1[] = { // Basic valid UINT8_C(0), // COMPLIANT @@ -13,6 +17,9 @@ uint_least8_t g1[] = { UINT8_C(-1.0), // NON-COMPLIANT UINT8_C(0b111), // NON-COMPLIANT UINT8_C(-0b111), // NON-COMPLIANT + UINT8_C('a'), // NON-COMPLIANT + UINT8_C(-'$'), // NON-COMPLIANT + UINT8_C('\n'), // NON-COMPLIANT // Suffixes disallowed UINT8_C(1u), // NON-COMPLIANT @@ -42,6 +49,10 @@ uint_least8_t g1[] = { UINT8_C("a"[0]), // NON-COMPLIANT UINT8_C(0 ["a"]), // NON-COMPLIANT UINT8_C(UINT8_MAX), // COMPLIANT + UINT8_C(true), // NON-COMPLIANT[False Negative] + UINT8_C(false), // NON-COMPLIANT[False Negative] + UINT8_C(NULL), // NON-COMPLIANT[False Negative] + UINT8_C(NULLPTR), // NON-COMPLIANT[False Negative] }; int_least8_t g2[] = { From 51098868065d90d55b7e83874241de40ea7e81cb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 13:53:27 -0700 Subject: [PATCH 11/17] Fix types2 package json vs query --- rule_packages/c/Types2.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json index 4c4aaaaa7a..7489a99de5 100644 --- a/rule_packages/c/Types2.json +++ b/rule_packages/c/Types2.json @@ -31,8 +31,8 @@ "description": "Integer constant macros should be used integer literal values with no u/l suffix.", "kind": "problem", "name": "The argument of an integer constant macro shall not use literal suffixes u, l, or ul", - "precision": "very-high", - "severity": "error", + "precision": "high", + "severity": "warning", "short_name": "IntegerConstantMacroArgumentUsesSuffix", "tags": [ "readability", From 3012bfaf3e1d113f3f5d5f9bbfb4b9738c3e2f65 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 14:32:01 -0700 Subject: [PATCH 12/17] Fix package file consistency, c format --- c/misra/test/rules/RULE-7-5/test.c | 2 +- rule_packages/c/Types2.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index 432c6ceed5..fad34ac160 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -19,7 +19,7 @@ uint_least8_t g1[] = { UINT8_C(-0b111), // NON-COMPLIANT UINT8_C('a'), // NON-COMPLIANT UINT8_C(-'$'), // NON-COMPLIANT - UINT8_C('\n'), // NON-COMPLIANT + UINT8_C('\n'), // NON-COMPLIANT // Suffixes disallowed UINT8_C(1u), // NON-COMPLIANT diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json index 7489a99de5..efed56c511 100644 --- a/rule_packages/c/Types2.json +++ b/rule_packages/c/Types2.json @@ -10,7 +10,7 @@ "kind": "problem", "name": "The argument of an integer constant macro shall be a literal", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "InvalidIntegerConstantMacroArgument", "tags": [ "correctness" From 3708edfbefdc68ae9a9558ba4f4170b325e5bb55 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 23:41:04 -0700 Subject: [PATCH 13/17] Reject macros inside (u)INT_C macros (eg, `1NT8_C(true)`) and remove exception Added exception to handle INT63_MIN as an addition expression, but that exception is actually quite dangerous and should be removed. --- .../InvalidIntegerConstantMacroArgument.ql | 24 ++++++------------ ...validIntegerConstantMacroArgument.expected | 7 ++++-- c/misra/test/rules/RULE-7-5/test.c | 25 ++++++++----------- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index 851569899e..9c35c3c2d6 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -16,27 +16,19 @@ import codingstandards.cpp.IntegerConstantMacro import codingstandards.cpp.Literals import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -/** - * The max negative 64 bit signed integer is one less than the negative of the - * max positive signed 64 bit integer. The only way to create a "negative" - * literal is to use unary- negation of a positive literal. Therefore, clang - * (and likely other compilers) rejects `INT64_C(-92233...808)` but accepts - * `INT64_C(-92233...807 - 1)`. Therefore, in this case allow non-literal - * expressions. - */ -predicate specialMaxNegative64Exception(IntegerConstantMacro macro, Expr expr) { - macro.getSize() = 64 and - macro.isSigned() and - // Set a cutoff with precision, fix once BigInt library is available. - upperBound(expr) < macro.minValue() * 0.999999999 and - upperBound(expr) > macro.minValue() * 1.000000001 +predicate containsMacroInvocation(MacroInvocation outer, MacroInvocation inner) { + outer.getExpr() = inner.getExpr() and + exists(outer.getUnexpandedArgument(0).indexOf(inner.getMacroName())) } from MacroInvocation invoke, IntegerConstantMacro macro where not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and invoke.getMacro() = macro and - not invoke.getExpr() instanceof PossiblyNegativeLiteral and - not specialMaxNegative64Exception(macro, invoke.getExpr()) + ( + not invoke.getExpr() instanceof PossiblyNegativeLiteral + or + containsMacroInvocation(invoke, _) + ) select invoke.getExpr(), "Argument to integer constant macro " + macro.getName() + " must be an integer literal." diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected index 44b5d78994..b29228b6df 100644 --- a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -1,5 +1,8 @@ | test.c:48:13:48:17 | ... + ... | Argument to integer constant macro UINT8_C must be an integer literal. | | test.c:49:13:49:18 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | | test.c:50:13:50:19 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | -| test.c:167:13:167:37 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | -| test.c:168:13:168:47 | ... - ... | Argument to integer constant macro INT64_C must be an integer literal. | +| test.c:51:5:51:22 | 255 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:52:5:52:17 | 1 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:53:5:53:18 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:54:5:54:17 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:55:5:55:20 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c index fad34ac160..a3fb4b60e4 100644 --- a/c/misra/test/rules/RULE-7-5/test.c +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -48,11 +48,11 @@ uint_least8_t g1[] = { UINT8_C(0 + 0), // NON-COMPLIANT UINT8_C("a"[0]), // NON-COMPLIANT UINT8_C(0 ["a"]), // NON-COMPLIANT - UINT8_C(UINT8_MAX), // COMPLIANT - UINT8_C(true), // NON-COMPLIANT[False Negative] - UINT8_C(false), // NON-COMPLIANT[False Negative] - UINT8_C(NULL), // NON-COMPLIANT[False Negative] - UINT8_C(NULLPTR), // NON-COMPLIANT[False Negative] + UINT8_C(UINT8_MAX), // NON-COMPLIANT + UINT8_C(true), // NON-COMPLIANT + UINT8_C(false), // NON-COMPLIANT + UINT8_C(NULL), // NON-COMPLIANT + UINT8_C(NULLPTR), // NON-COMPLIANT }; int_least8_t g2[] = { @@ -158,20 +158,17 @@ int_least64_t g8[] = { INT64_C(9223372036854775807), // COMPLIANT // INT64_C(9223372036854775808) is a compile-time error - // -9223372036854775808 allowed, but cannot be created via unary- without - // compile time errors. - INT64_C(-9223372036854775807), // COMPLIANT - INT64_C(-9223372036854775807 - 1), // COMPLIANT - // -9223372036854775809 is not allowed, and cannot be created via unary- - // without compile time errors. - INT64_C(-9223372036854775807 - 2), // NON-COMPLIANT - INT64_C(-9223372036854775807 - 20000000000), // NON-COMPLIANT + INT64_C(-9223372036854775807), // COMPLIANT + // -9223372036854775808 is correctly sized, but not a valid decimal literal + // value. + // -9223372036854775809 is not correctly sized, and not a valid decimal + // literal value. INT64_C(0x7FFFFFFFFFFFFFFF), // COMPLIANT INT64_C(0x8000000000000000), // NON-COMPLIANT[FALSE NEGATIVE] INT64_C(-0x8000000000000000), // COMPLIANT INT64_C(-0x8000000000000001), // NON-COMPLIANT[FALSE NEGATIVE] - INT64_C(-0x8001000000000000), // NON-COMPLIANT + INT64_C(-0x8001000000000000), // NON-COMPLIANT[FALSE NEGATIVE] }; // Other edge cases: From 445d18e9c9d42b0c399624b655e0480f8b1385ac Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 23:33:39 -0700 Subject: [PATCH 14/17] Add misra c 2012 amendment3 tag --- rule_packages/c/Types2.json | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json index efed56c511..7e4c0827fe 100644 --- a/rule_packages/c/Types2.json +++ b/rule_packages/c/Types2.json @@ -13,7 +13,8 @@ "severity": "warning", "short_name": "InvalidIntegerConstantMacroArgument", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/amendment3" ] }, { @@ -24,7 +25,8 @@ "severity": "error", "short_name": "InvalidLiteralForIntegerConstantMacroArgument", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/amendment3" ] }, { @@ -36,7 +38,8 @@ "short_name": "IntegerConstantMacroArgumentUsesSuffix", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/amendment3" ] }, { @@ -47,7 +50,8 @@ "severity": "error", "short_name": "IncorrectlySizedIntegerConstantMacroArgument", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/amendment3" ], "implementation_scope": { "description": "This rule can validate integers sized 32 or smaller. When the CodeQL runtime supports big ints, this will be expanded to include 64 bit integer types." @@ -69,7 +73,8 @@ "severity": "warning", "short_name": "UseOfBannedSmallIntegerConstantMacro", "tags": [ - "readability" + "readability", + "external/misra/c/2012/amendment3" ] } ], From 07d28ef432bcd0d51047a6fb14bf8ac3b4b1bb13 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 23:39:46 -0700 Subject: [PATCH 15/17] Regenerate query file tags --- .../RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql | 1 + .../src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql | 1 + .../src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql | 1 + .../RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql | 1 + .../src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql | 1 + 5 files changed, 5 insertions(+) diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql index 06a7eb7658..ac8cd56a7a 100644 --- a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-7-5 * correctness + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql index 3b58cf7a92..13e7ee6b7b 100644 --- a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-7-5 * readability * maintainability + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index 9c35c3c2d6..40b66d0067 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -7,6 +7,7 @@ * @problem.severity warning * @tags external/misra/id/rule-7-5 * correctness + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql index e333adfb7e..e4e660c628 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-7-5 * correctness + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql index 9a1844601b..47e88196d5 100644 --- a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql +++ b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-7-6 * readability + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ From 202fb667b2087f32d3c14e6bcd229f3d64a29a15 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 8 Oct 2024 20:54:23 -0700 Subject: [PATCH 16/17] Address feedback. --- ...rectlySizedIntegerConstantMacroArgument.ql | 19 +++++++++---------- .../IntegerConstantMacroArgumentUsesSuffix.ql | 4 ++-- .../InvalidIntegerConstantMacroArgument.ql | 7 +------ .../cpp/IntegerConstantMacro.qll | 2 +- .../src/codingstandards/cpp/Literals.qll | 5 ++--- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql index ac8cd56a7a..87c945d6b6 100644 --- a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -21,13 +21,8 @@ predicate matchesSign(IntegerConstantMacro macro, PossiblyNegativeLiteral litera } predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { - // Wait for BigInt support to check 64 bit macro types. - (macro.getSize() < 64 and matchesSign(macro, literal)) - implies - ( - literal.getRawValue() <= macro.maxValue() and - literal.getRawValue() >= macro.minValue() - ) + literal.getRawValue() <= macro.maxValue() and + literal.getRawValue() >= macro.minValue() } from @@ -38,9 +33,13 @@ where invoke.getMacro() = macro and literal = invoke.getExpr() and ( - not matchesSign(macro, invoke.getExpr()) and explanation = " cannot be negative" + not matchesSign(macro, literal) and + explanation = " cannot be negative" or - not matchesSize(macro, invoke.getExpr()) and + matchesSign(macro, literal) and + // Wait for BigInt support to check 64 bit macro types. + macro.getSize() < 64 and + not matchesSize(macro, literal) and explanation = " is outside of the allowed range " + macro.getRangeString() ) -select invoke.getExpr(), "Value provided to integer constant macro " + macro.getName() + explanation +select literal, "Value provided to integer constant macro " + macro.getName() + explanation diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql index 13e7ee6b7b..84fb1a9872 100644 --- a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -18,7 +18,7 @@ import codingstandards.cpp.IntegerConstantMacro import codingstandards.cpp.Literals string argumentSuffix(MacroInvocation invoke) { - // Compiler strips the suffix unless we look at the unexpanded argument text. + // Extractor strips the suffix unless we look at the unexpanded argument text. // Unexpanded argument text can be malformed in all sorts of ways, so make // this match relatively strict, to be safe. result = invoke.getUnexpandedArgument(0).regexpCapture("([0-9]+|0[xX][0-9A-F]+)([uUlL]+)$", 2) @@ -30,6 +30,6 @@ where invoke.getMacro() instanceof IntegerConstantMacro and invoke.getExpr() = argument and suffix = argumentSuffix(invoke) -select invoke.getExpr(), +select argument, "Value suffix '" + suffix + "' is not allowed on provided argument to integer constant macro " + invoke.getMacroName() + "." diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql index 40b66d0067..4c750e32d8 100644 --- a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -17,11 +17,6 @@ import codingstandards.cpp.IntegerConstantMacro import codingstandards.cpp.Literals import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -predicate containsMacroInvocation(MacroInvocation outer, MacroInvocation inner) { - outer.getExpr() = inner.getExpr() and - exists(outer.getUnexpandedArgument(0).indexOf(inner.getMacroName())) -} - from MacroInvocation invoke, IntegerConstantMacro macro where not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and @@ -29,7 +24,7 @@ where ( not invoke.getExpr() instanceof PossiblyNegativeLiteral or - containsMacroInvocation(invoke, _) + any(MacroInvocation inner).getParentInvocation() = invoke ) select invoke.getExpr(), "Argument to integer constant macro " + macro.getName() + " must be an integer literal." diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll index 8f3fff1e1b..bc4ea3d125 100644 --- a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -15,7 +15,7 @@ class IntegerConstantMacro extends Macro { signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() } - predicate isSmall() { size < 32 } + predicate isSmall() { size < any(IntType it | it.isSigned()).getSize() } int getSize() { result = size } diff --git a/cpp/common/src/codingstandards/cpp/Literals.qll b/cpp/common/src/codingstandards/cpp/Literals.qll index cc0d28dec9..edec04152e 100644 --- a/cpp/common/src/codingstandards/cpp/Literals.qll +++ b/cpp/common/src/codingstandards/cpp/Literals.qll @@ -4,7 +4,6 @@ import cpp import codingstandards.cpp.Cpp14Literal -import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis class IntegerLiteral = Cpp14Literal::IntegerLiteral; @@ -100,7 +99,7 @@ class NegativeLiteral extends PossiblyNegativeLiteral, UnaryMinusExpr { override Cpp14Literal::NumericLiteral getBaseLiteral() { result = literal } - override float getRawValue() { result = -lowerBound(literal) } + override float getRawValue() { result = -literal.getValue().toFloat() } } /** @@ -112,5 +111,5 @@ class PositiveLiteral extends PossiblyNegativeLiteral, Cpp14Literal::NumericLite override Cpp14Literal::NumericLiteral getBaseLiteral() { result = this } - override float getRawValue() { result = lowerBound(this) } + override float getRawValue() { result = getValue().toFloat() } } From 47a6600a2f8801728b1fa9602b93538c493b6f0d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 8 Oct 2024 22:00:36 -0700 Subject: [PATCH 17/17] Fix small integer macro size, bytes not bits. --- cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll index bc4ea3d125..ce72033ecc 100644 --- a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -15,7 +15,7 @@ class IntegerConstantMacro extends Macro { signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() } - predicate isSmall() { size < any(IntType it | it.isSigned()).getSize() } + predicate isSmall() { size < any(IntType it | it.isSigned()).getSize() * 8 } int getSize() { result = size }