diff --git a/apply-configuration/action.yml b/apply-configuration/action.yml new file mode 100644 index 0000000000..89a702b72a --- /dev/null +++ b/apply-configuration/action.yml @@ -0,0 +1,24 @@ +name: Applies Coding Standard configuration files in the repository +description: | + Installs Python and indexes the CodeQL Coding Standard configuration files in the repository + +runs: + using: composite + steps: + - name: Install Python + id: cs-install-python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + update-environment: false + - name: Install dependencies and process files + shell: bash + run: | + install_dir=$(dirname $(dirname "${{ steps.cs-install-python.outputs.python-path }}")) + if [[ -z "$LD_LIBRARY_PATH" ]]; then + export LD_LIBRARY_PATH="$install_dir/lib" + else + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$install_dir/lib" + fi + ${{ steps.cs-install-python.outputs.python-path }} -m pip install -r ${GITHUB_ACTION_PATH}/../scripts/configuration/requirements.txt + ${{ steps.cs-install-python.outputs.python-path }} ${GITHUB_ACTION_PATH}/../scripts/configuration/process_coding_standards_config.py \ No newline at end of file diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index a55d7391da..2b94485102 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 7a700897b0..b9ae07d6ef 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index f1b5271d74..b4128cbbe8 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 47b71ea34a..ec8fdff257 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index d01bc81038..4783547ed2 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -130,12 +130,17 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) { essentialType.(IntegralType).isSigned() and not essentialType instanceof PlainCharType or + // Anonymous enums are considered to be signed + result = EssentiallySignedType() and + essentialType instanceof AnonymousEnumType and + not essentialType instanceof MisraBoolType + or result = EssentiallyUnsignedType() and essentialType.(IntegralType).isUnsigned() and not essentialType instanceof PlainCharType or result = EssentiallyEnumType() and - essentialType instanceof Enum and + essentialType instanceof NamedEnumType and not essentialType instanceof MisraBoolType or result = EssentiallyFloatingType() and @@ -348,16 +353,51 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera } } +/** + * A named Enum type, as per D.5. + */ +class NamedEnumType extends Enum { + NamedEnumType() { + not isAnonymous() + or + exists(Type useOfEnum | this = useOfEnum.stripType() | + exists(TypedefType t | t.getBaseType() = useOfEnum) + or + exists(Function f | f.getType() = useOfEnum or f.getAParameter().getType() = useOfEnum) + or + exists(Struct s | s.getAField().getType() = useOfEnum) + or + exists(Variable v | v.getType() = useOfEnum) + ) + } +} + +/** + * An anonymous Enum type, as per D.5. + */ +class AnonymousEnumType extends Enum { + AnonymousEnumType() { not this instanceof NamedEnumType } +} + +/** + * The EssentialType of an EnumConstantAccess, which may be essentially enum or essentially signed. + */ class EssentialEnumConstantAccess extends EssentialExpr, EnumConstantAccess { - override Type getEssentialType() { result = getTarget().getDeclaringEnum() } + override Type getEssentialType() { + exists(Enum e | e = getTarget().getDeclaringEnum() | + if e instanceof NamedEnumType then result = e else result = stlr(this) + ) + } } class EssentialLiteral extends EssentialExpr, Literal { override Type getEssentialType() { if this instanceof BooleanLiteral - then result instanceof MisraBoolType + then + // This returns a multitude of types - not sure if we really want that + result instanceof MisraBoolType else ( - if this.(CharLiteral).getCharacter().length() = 1 + if this instanceof CharLiteral then result instanceof PlainCharType else exists(Type underlyingStandardType | diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 7839b51dd3..36619027dd 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql index cc4c860d7d..d1fed06319 100644 --- a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -38,7 +38,7 @@ where // be reported as non-compliant. leftOpTypeCategory = EssentiallyEnumType() and rightOpTypeCategory = EssentiallyEnumType() and - not leftOpEssentialType = rightOpEssentialType and + not leftOpEssentialType.getUnspecifiedType() = rightOpEssentialType.getUnspecifiedType() and message = "The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: " + leftOpEssentialType + ", right operand: " + rightOpEssentialType + ")." diff --git a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql index bdaebcbf54..0363c28c19 100644 --- a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql +++ b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql @@ -19,7 +19,7 @@ import codingstandards.cpp.Pointers from Cast cast, VoidPointerType type, PointerToObjectType newType where not isExcluded(cast, Pointers1Package::conversionFromPointerToVoidIntoPointerToObjectQuery()) and - type = cast.getExpr().getUnderlyingType() and + type = cast.getExpr().getUnspecifiedType() and newType = cast.getUnderlyingType() and not isNullPointerConstant(cast.getExpr()) select cast, diff --git a/c/misra/src/rules/RULE-2-2/DeadCode.ql b/c/misra/src/rules/RULE-2-2/DeadCode.ql index 19ac69c2c1..97c3808607 100644 --- a/c/misra/src/rules/RULE-2-2/DeadCode.ql +++ b/c/misra/src/rules/RULE-2-2/DeadCode.ql @@ -15,8 +15,83 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.rules.deadcode.DeadCode +import codingstandards.cpp.alertreporting.HoldsForAllCopies +import codingstandards.cpp.deadcode.UselessAssignments -class MisraCDeadCodeQuery extends DeadCodeSharedQuery { - MisraCDeadCodeQuery() { this = DeadCodePackage::deadCodeQuery() } +/** + * Gets an explicit cast from `e` if one exists. + */ +Cast getExplicitCast(Expr e) { + exists(Conversion c | c = e.getExplicitlyConverted() | + result = c + or + result = c.(ParenthesisExpr).getExpr() + ) +} + +class ExprStmtExpr extends Expr { + ExprStmtExpr() { exists(ExprStmt es | es.getExpr() = this) } +} + +/** + * An "operation" as defined by MISRA C Rule 2.2 that is dead, i.e. it's removal has no effect on + * the behaviour of the program. + */ +class DeadOperationInstance extends Expr { + string description; + + DeadOperationInstance() { + // Exclude cases nested within macro expansions, because the code may be "live" in other + // expansions + isNotWithinMacroExpansion(this) and + exists(ExprStmtExpr e | + if exists(getExplicitCast(e)) + then + this = getExplicitCast(e) and + // void conversions are permitted + not getExplicitCast(e) instanceof VoidConversion and + description = "Cast operation is unused" + else ( + this = e and + ( + if e instanceof Assignment + then + exists(SsaDefinition sd, LocalScopeVariable v | + e = sd.getDefinition() and + sd.getDefiningValue(v).isPure() and + // The definition is useless + isUselessSsaDefinition(sd, v) and + description = "Assignment to " + v.getName() + " is unused and has no side effects" + ) + else ( + e.isPure() and + description = "Result of operation is unused and has no side effects" + ) + ) + ) + ) + } + + string getDescription() { result = description } } + +class DeadOperation = HoldsForAllCopies::LogicalResultElement; + +from + DeadOperation deadOperation, DeadOperationInstance instance, string message, Element explainer, + string explainerDescription +where + not isExcluded(instance, DeadCodePackage::deadCodeQuery()) and + instance = deadOperation.getAnElementInstance() and + if instance instanceof FunctionCall + then + message = instance.getDescription() + " from call to function $@" and + explainer = instance.(FunctionCall).getTarget() and + explainerDescription = explainer.(Function).getName() + else ( + message = instance.getDescription() and + // Ignore the explainer + explainer = instance and + explainerDescription = "" + ) +select deadOperation, message + ".", explainer, explainerDescription diff --git a/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql b/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql new file mode 100644 index 0000000000..8066cc80cb --- /dev/null +++ b/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/call-to-banned-random-function + * @name RULE-21-24: The random number generator functions of shall not be used + * @description The standard functions rand() and srand() will not give high quality random results + * in all implementations and are therefore banned. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-21-24 + * security + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from FunctionCall call, string name +where + not isExcluded(call, Banned2Package::callToBannedRandomFunctionQuery()) and + name = ["rand", "srand"] and + call.getTarget().hasGlobalOrStdName(name) +select call, "Call to banned random number generation function '" + name + "'." 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..87c945d6b6 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -0,0 +1,45 @@ +/** + * @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/c/2012/amendment3 + * 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) { + 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, literal) and + explanation = " cannot be negative" + or + 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 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 new file mode 100644 index 0000000000..84fb1a9872 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -0,0 +1,35 @@ +/** + * @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 high + * @problem.severity warning + * @tags external/misra/id/rule-7-5 + * readability + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +string argumentSuffix(MacroInvocation invoke) { + // 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) +} + +from MacroInvocation invoke, PossiblyNegativeLiteral argument, string suffix +where + not isExcluded(invoke, Types2Package::integerConstantMacroArgumentUsesSuffixQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + invoke.getExpr() = argument and + suffix = argumentSuffix(invoke) +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 new file mode 100644 index 0000000000..4c750e32d8 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -0,0 +1,30 @@ +/** + * @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. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +from MacroInvocation invoke, IntegerConstantMacro macro +where + not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() = macro and + ( + not invoke.getExpr() instanceof PossiblyNegativeLiteral + or + any(MacroInvocation inner).getParentInvocation() = invoke + ) +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 new file mode 100644 index 0000000000..e4e660c628 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -0,0 +1,77 @@ +/** + * @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/c/2012/amendment3 + * 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 or + // Ignore cases where the AST/extractor don't give us enough information: + literal.getBaseLiteral() instanceof Cpp14Literal::UnrecognizedNumericLiteral +} + +/** + * 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]+") +} + +/** + * 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 + 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 +where + not isExcluded(invoke, Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + literal = invoke.getExpr() and + ( + not validLiteralType(literal) or + seemsBinaryLiteral(invoke) or + seemsCharLiteral(invoke) + ) +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/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql new file mode 100644 index 0000000000..47e88196d5 --- /dev/null +++ b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql @@ -0,0 +1,24 @@ +/** + * @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/c/2012/amendment3 + * 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/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected index 8b6b45a2f0..c0e010b8e4 100644 --- a/c/misra/test/c/misra/EssentialTypes.expected +++ b/c/misra/test/c/misra/EssentialTypes.expected @@ -1,3 +1,9 @@ +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | | test.c:4:20:4:20 | 1 | signed char | signed char | essentially Signed type | | test.c:4:20:4:20 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | | test.c:5:23:5:23 | 1 | signed char | signed char | essentially Signed type | @@ -73,3 +79,14 @@ | test.c:54:3:54:5 | ~ ... | int | int | essentially Signed type | | test.c:54:4:54:5 | (int)... | int | int | essentially Signed type | | test.c:54:4:54:5 | ss | signed short | signed short | essentially Signed type | +| test.c:63:30:63:32 | ((unnamed enum))... | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:63:30:63:32 | EC5 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:70:3:70:5 | EC1 | signed char | signed char | essentially Signed type | +| test.c:71:3:71:5 | EC2 | E1 | E1 | essentially Enum Type | +| test.c:72:3:72:5 | EC3 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:73:3:73:5 | EC4 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:74:3:74:5 | EC5 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:75:3:75:5 | EC6 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:79:3:79:5 | 97 | char | char | essentially Character type | +| test.c:80:3:80:6 | 10 | char | char | essentially Character type | +| test.c:81:3:81:6 | 0 | char | char | essentially Character type | diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index 6156e9440e..b3fdddd591 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -52,4 +52,31 @@ void testUnary() { ~us; // Should be essentially unsigned ~s; // Should be essentially signed ~ss; // Should be essentially signed +} + +enum { EC1 }; +enum E1 { EC2 }; +typedef enum { EC3 } E2; + +enum { EC4 } g; + +enum { EC5 } test() { return EC5; } + +struct S1 { + enum { EC6 } m; +}; + +void testEnums() { + EC1; // Should be essentially signed + EC2; // Should be essentially enum + EC3; // Should be essentially enum + EC4; // Should be essentially enum + EC5; // Should be essentially enum + EC6; // Should be essentially enum +} + +void testControlChar() { + 'a'; // Essentially char + '\n'; // Essentially char + '\0'; // Essentially char } \ No newline at end of file diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index bc2f2e7546..b205f34897 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/test/rules/RULE-10-4/test.c b/c/misra/test/rules/RULE-10-4/test.c index 666590a2d5..cbcb7191f6 100644 --- a/c/misra/test/rules/RULE-10-4/test.c +++ b/c/misra/test/rules/RULE-10-4/test.c @@ -33,4 +33,13 @@ void testOps() { A < A; // COMPLIANT e1a < e2a; // NON_COMPLIANT A < D; // NON_COMPLIANT + + enum { G }; + s32 + G; // COMPLIANT + c == '\n'; // COMPLIANT + + typedef enum { H } E3; + + E3 e3a = H; + e3a < H; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected index 91fd9f274a..94cf6ee635 100644 --- a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected +++ b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected @@ -2,3 +2,7 @@ | test.c:14:8:14:9 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | | test.c:15:8:15:25 | (int *)... | Cast performed between a pointer to object type (short) and a pointer to a different object type (int). | | test.c:15:15:15:25 | (short *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (short). | +| test.c:20:3:20:17 | (const int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (const int). | +| test.c:21:3:21:16 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | +| test.c:22:20:22:21 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | +| test.c:23:3:23:18 | (long long *)... | Cast performed between a pointer to object type (int) and a pointer to a different object type (long long). | diff --git a/c/misra/test/rules/RULE-11-3/test.c b/c/misra/test/rules/RULE-11-3/test.c index 64ae688993..4730aeac03 100644 --- a/c/misra/test/rules/RULE-11-3/test.c +++ b/c/misra/test/rules/RULE-11-3/test.c @@ -13,4 +13,12 @@ void f1(void) { int *v8 = (int *)0; // COMPLIANT v8 = v2; // NON_COMPLIANT v8 = (int *)(short *)v2; // NON_COMPLIANT + (const void *)v1; // COMPLIANT + const void *v9 = v1; // COMPLIANT + (int *)v9; // COMPLIANT - cast from void* + (const void *)v2; // COMPLIANT + (const int *)v2; // NON_COMPLIANT + (int *const)v2; // NON_COMPLIANT + int *const v10 = v2; // NON_COMPLIANT + (long long *)v10; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected index 44d5ca5943..17a2fa223f 100644 --- a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected @@ -1,6 +1,6 @@ | test.c:6:21:6:37 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:6:21:6:37 | (unsigned int)... | | | test.c:8:8:8:24 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:8:8:8:24 | (unsigned int)... | | | test.c:12:22:12:39 | (unsigned int *)... | Cast from integer type 'unsigned int' to pointer to object type 'unsigned int *'. | test.c:12:22:12:39 | (unsigned int *)... | | -| test.c:15:1:15:24 | #define FOO (int *)0x200 | Cast from integer type 'int' to pointer to object type 'int *'. | test.c:15:1:15:24 | #define FOO (int *)0x200 | | -| test.c:23:3:23:22 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:17:1:17:34 | #define FOO_FUNCTIONAL(x) (int *)x | FOO_FUNCTIONAL | -| test.c:24:14:24:25 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:18:1:18:23 | #define FOO_INSERT(x) x | FOO_INSERT | +| test.c:18:1:18:24 | #define FOO (int *)0x200 | Cast from integer type 'int' to pointer to object type 'int *'. | test.c:18:1:18:24 | #define FOO (int *)0x200 | | +| test.c:26:3:26:22 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:20:1:20:34 | #define FOO_FUNCTIONAL(x) (int *)x | FOO_FUNCTIONAL | +| test.c:27:14:27:25 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:21:1:21:23 | #define FOO_INSERT(x) x | FOO_INSERT | diff --git a/c/misra/test/rules/RULE-11-4/test.c b/c/misra/test/rules/RULE-11-4/test.c index 5a78387247..283af5e560 100644 --- a/c/misra/test/rules/RULE-11-4/test.c +++ b/c/misra/test/rules/RULE-11-4/test.c @@ -10,6 +10,9 @@ void f1(void) { unsigned int *v4 = 0; // COMPLIANT unsigned int *v5 = NULL; // COMPLIANT unsigned int *v6 = (unsigned int *)v2; // NON_COMPLIANT + const void *v7 = 0; + (unsigned int)v7; // COMPLIANT - cast const void to int + (const void *)v1; // COMPLIANT - casting int to const void } #define FOO (int *)0x200 // NON_COMPLIANT diff --git a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected index 5b4eec8d15..42cf288b34 100644 --- a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected +++ b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected @@ -1 +1,2 @@ | test.c:6:13:6:21 | (int *)... | Cast performed from a void pointer into a pointer to an object (int *). | +| test.c:11:3:11:11 | (int *)... | Cast performed from a void pointer into a pointer to an object (int *). | diff --git a/c/misra/test/rules/RULE-11-5/test.c b/c/misra/test/rules/RULE-11-5/test.c index a7ffa4822e..5b5a5b3a52 100644 --- a/c/misra/test/rules/RULE-11-5/test.c +++ b/c/misra/test/rules/RULE-11-5/test.c @@ -7,4 +7,8 @@ void f1(void) { v2 = NULL; // COMPLIANT void *v3 = (void *)v1; // COMPLIANT v3 = (void *)v2; // COMPLIANT + const void *v4 = 0; + (int *)v4; // NON_COMPLIANT - const in type is irrelevant + (const void *)v1; // COMPLIANT - casting is from void to void, const addition + // should be irrelevant } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-7/test.c b/c/misra/test/rules/RULE-11-7/test.c index b7dd989b00..4891aaae85 100644 --- a/c/misra/test/rules/RULE-11-7/test.c +++ b/c/misra/test/rules/RULE-11-7/test.c @@ -7,4 +7,12 @@ void f1(void) { float v4 = (float)(bool)v1; // NON_COMPLIANT v1 = (int *)v2; // NON_COMPLIANT v4 = (float)v3; // COMPLIANT + void *v5 = 0; + const void *v6 = 0; + // void pointers (regardless of specifier) are not pointers to object, so all + // these examples are compliant according to this rule + (bool)v5; // COMPLIANT + (bool)v6; // COMPLIANT + (void *)v2; // COMPLIANT + (const void *)v2; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.expected b/c/misra/test/rules/RULE-2-2/DeadCode.expected new file mode 100644 index 0000000000..e25a5a97ef --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/DeadCode.expected @@ -0,0 +1,9 @@ +| test.c:15:3:15:11 | ... = ... | Assignment to dead1 is unused and has no side effects. | test.c:15:3:15:11 | ... = ... | | +| test.c:16:3:16:11 | ... = ... | Assignment to dead2 is unused and has no side effects. | test.c:16:3:16:11 | ... = ... | | +| test.c:19:3:19:7 | ... + ... | Result of operation is unused and has no side effects. | test.c:19:3:19:7 | ... + ... | | +| test.c:21:3:21:17 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:23:3:23:30 | (int)... | Cast operation is unused. | test.c:23:3:23:30 | (int)... | | +| test.c:24:3:24:25 | (int)... | Cast operation is unused. | test.c:24:3:24:25 | (int)... | | +| test.c:27:4:27:18 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:37:3:37:27 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:38:7:38:31 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.qlref b/c/misra/test/rules/RULE-2-2/DeadCode.qlref new file mode 100644 index 0000000000..761e04d51b --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/DeadCode.qlref @@ -0,0 +1 @@ +rules/RULE-2-2/DeadCode.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.testref b/c/misra/test/rules/RULE-2-2/DeadCode.testref deleted file mode 100644 index f084f30aaa..0000000000 --- a/c/misra/test/rules/RULE-2-2/DeadCode.testref +++ /dev/null @@ -1 +0,0 @@ -c/common/test/rules/deadcode/DeadCode.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/test.c b/c/misra/test/rules/RULE-2-2/test.c new file mode 100644 index 0000000000..f8248c52d2 --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/test.c @@ -0,0 +1,42 @@ +int may_have_side_effects(); +int no_side_effects(int x) { return 1 + 2; } +int no_side_effects_nondeterministic(); + +int test_dead_code(int x) { + int live1 = may_have_side_effects(), + live2 = may_have_side_effects(); // COMPLIANT + int live3 = 0, + live4 = may_have_side_effects(); // COMPLIANT + int live5 = 0, live6 = 0; // COMPLIANT + live5 = 1; // COMPLIANT + live6 = 2; // COMPLIANT + + int dead1 = 0, dead2 = 0; // COMPLIANT - init not considered by this rule + dead1 = 1; // NON_COMPLIANT - useless assignment + dead2 = 1; // NON_COMPLIANT - useless assignment + + may_have_side_effects(); // COMPLIANT + 1 + 2; // NON_COMPLIANT + + no_side_effects(x); // NON_COMPLIANT + + (int)may_have_side_effects(); // NON_COMPLIANT + (int)no_side_effects(x); // NON_COMPLIANT + (void)no_side_effects(x); // COMPLIANT + (may_have_side_effects()); // COMPLIANT + (no_side_effects(x)); // NON_COMPLIANT + +#define FULL_STMT_NO_SIDE_EFFECTS no_side_effects(1); +#define PART_STMT_NO_SIDE_EFFECTS no_side_effects(1) +#define BLOCK_SOME_SIDE_EFFECTS \ + { \ + may_have_side_effects(); \ + no_side_effects(1); \ + } + + FULL_STMT_NO_SIDE_EFFECTS // NON_COMPLIANT + PART_STMT_NO_SIDE_EFFECTS; // NON_COMPLIANT + BLOCK_SOME_SIDE_EFFECTS; // COMPLIANT + + return live5 + live6; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected new file mode 100644 index 0000000000..b3953d166b --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected @@ -0,0 +1,2 @@ +| test.c:5:3:5:7 | call to srand | Call to banned random number generation function 'srand'. | +| test.c:6:11:6:14 | call to rand | Call to banned random number generation function 'rand'. | diff --git a/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref new file mode 100644 index 0000000000..b229c0e84f --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref @@ -0,0 +1 @@ +rules/RULE-21-24/CallToBannedRandomFunction.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-24/test.c b/c/misra/test/rules/RULE-21-24/test.c new file mode 100644 index 0000000000..56cfae3cb1 --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/test.c @@ -0,0 +1,11 @@ +#include "stdlib.h" + +void f() { + // rand() is banned -- and thus, so is srand(). + srand(0); // NON-COMPLIANT + int x = rand(); // NON-COMPLIANT + + // Other functions from stdlib are not banned by this rule. + x = abs(-4); // COMPLIANT + getenv("ENV_VAR"); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected index 07cd56b3d9..0d5504ba03 100644 --- a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected +++ b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected @@ -4,3 +4,9 @@ | test.c:162:3:162:21 | 9223372036854775808 | Unsigned literal 0x8000000000000000L does not explicitly express sign with a 'U' or 'u' suffix. | | test.c:185:3:185:22 | 9223372036854775808 | Unsigned literal 0x8000000000000000ll does not explicitly express sign with a 'U' or 'u' suffix. | | test.c:208:3:208:22 | 9223372036854775808 | Unsigned literal 0x8000000000000000LL does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:227:3:227:14 | 2147483648 | Unsigned literal 020000000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:232:3:232:25 | 9223372036854775808 | Unsigned literal 01000000000000000000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:249:3:249:26 | 9223372036854775808 | Unsigned literal 01000000000000000000000l does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:266:3:266:26 | 9223372036854775808 | Unsigned literal 01000000000000000000000L does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:283:3:283:27 | 9223372036854775808 | Unsigned literal 01000000000000000000000ll does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:300:3:300:27 | 9223372036854775808 | Unsigned literal 01000000000000000000000LL does not explicitly express sign with a 'U' or 'u' suffix. | diff --git a/c/misra/test/rules/RULE-7-2/test.c b/c/misra/test/rules/RULE-7-2/test.c index b95d2b1e02..170e822023 100644 --- a/c/misra/test/rules/RULE-7-2/test.c +++ b/c/misra/test/rules/RULE-7-2/test.c @@ -221,6 +221,94 @@ void test_hexadecimal_constants() { 0x8000000000000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly } +void test_octal_constants() { + 00; // COMPLIANT - uses signed int + 017777777777; // COMPLIANT - max value held by signed int + 020000000000; // NON_COMPLIANT - larger than max signed int, so will be + // unsigned int + 040000000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0777777777777777777777; // COMPLIANT - max long int + 01000000000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00U; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777U; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777U; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000U; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `l` suffix + 00l; // COMPLIANT - uses signed long + 017777777777l; // COMPLIANT - uses signed long + 020000000000l; // COMPLIANT - uses signed long + 040000000000l; // COMPLIANT - uses signed long + 0777777777777777777777l; // COMPLIANT - max long int + 01000000000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `L` suffix + 00L; // COMPLIANT - uses signed long + 017777777777L; // COMPLIANT - uses signed long + 020000000000L; // COMPLIANT - uses signed long + 040000000000L; // COMPLIANT - uses signed long + 0777777777777777777777L; // COMPLIANT - COMPLIANT - uses signed long + 01000000000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00UL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777UL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `ll` suffix + 00ll; // COMPLIANT - uses signed long long + 017777777777ll; // COMPLIANT - uses signed long long + 020000000000ll; // COMPLIANT - uses signed long long + 040000000000ll; // COMPLIANT - uses signed long long + 0777777777777777777777ll; // COMPLIANT - max long int + 01000000000000000000000ll; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 017777777777LL; // COMPLIANT - uses signed long long + 020000000000LL; // COMPLIANT - uses signed long long + 040000000000LL; // COMPLIANT - uses signed long long + 0777777777777777777777LL; // COMPLIANT - max long int + 01000000000000000000000LL; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly +} + #define COMPLIANT_VAL 0x80000000U #define NON_COMPLIANT_VAL 0x80000000 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..d3724e21a4 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected @@ -0,0 +1,31 @@ +| 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/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..97a35dd977 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected @@ -0,0 +1,7 @@ +| 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/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 new file mode 100644 index 0000000000..b29228b6df --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -0,0 +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: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/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/InvalidLiteralForIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..ee5b75cb91 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected @@ -0,0 +1,7 @@ +| 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/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 new file mode 100644 index 0000000000..a3fb4b60e4 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -0,0 +1,179 @@ +#include "stdbool.h" +#include "stdint.h" + +#define NULL 0 +#define NULLPTR ((void *)NULL) + +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(-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 + 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 + 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 + UINT8_C(true), // NON-COMPLIANT + UINT8_C(false), // NON-COMPLIANT + UINT8_C(NULL), // NON-COMPLIANT + UINT8_C(NULLPTR), // 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(-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[] = { + // 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(0x80000000), // NON-COMPLIANT + INT32_C(-2147483648), // COMPLIANT + INT32_C(-0x80000000), // COMPLIANT + INT32_C(-2147483649), // NON-COMPLIANT + INT32_C(-0x80000001), // 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 + + 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[FALSE NEGATIVE] +}; + +// 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/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..9832cdf251 --- /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/change_notes/2024-07-11-fix-fp-406.md b/change_notes/2024-07-11-fix-fp-406.md new file mode 100644 index 0000000000..78e607ecb6 --- /dev/null +++ b/change_notes/2024-07-11-fix-fp-406.md @@ -0,0 +1,2 @@ + - `A13-3-1` - `FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql`: + - Fixes #406. Exclude detection of overloaded implicit copy/move constructors. \ No newline at end of file diff --git a/change_notes/2024-09-25-dead-code-improvements.md b/change_notes/2024-09-25-dead-code-improvements.md new file mode 100644 index 0000000000..9cd8d95ff5 --- /dev/null +++ b/change_notes/2024-09-25-dead-code-improvements.md @@ -0,0 +1,5 @@ + - `M0-1-9` - `DeadCode.ql` + - Remove false positives for statements where the enclosing function is compiled multiple times, either as part of different targets or a different template instantiations. Previously we would see false positives where a statement was dead in one instance of the code, but not other instances. We now only consider a statement dead if it is dead in all instances of that code. +- `RULE-2-2` - `DeadCode.ql`: + - Query has been rewritten to report only _operations_ that are considered dead, not statements. This should reduce false positives. + - Remove false positives for operations where the enclosing function is compiled multiple times, either as part of different targets or a different template instantiations. Previously we would see false positives where a operation was dead in one instance of the code, but not other instances. We now only consider a operation dead if it is dead in all instances of that code. \ No newline at end of file diff --git a/change_notes/2024-10-02-fix-fp-711-M0-1-10.md b/change_notes/2024-10-02-fix-fp-711-M0-1-10.md new file mode 100644 index 0000000000..cff5d5ab43 --- /dev/null +++ b/change_notes/2024-10-02-fix-fp-711-M0-1-10.md @@ -0,0 +1,2 @@ +- `M0-1-10` - `UnusedFunction.ql`: + - Fixes #711. Excludes constexpr functions, considers functions from GoogleTest as an EntryPoint and does not consider special member functions. Another query called UnusedSplMemberFunction.ql is created that reports unused special member functions. This is done so as to enable deviations to be applied to this case. diff --git a/change_notes/2024-10-11-specifiers-rule-11-misra-c.md b/change_notes/2024-10-11-specifiers-rule-11-misra-c.md new file mode 100644 index 0000000000..5f74dc6b3f --- /dev/null +++ b/change_notes/2024-10-11-specifiers-rule-11-misra-c.md @@ -0,0 +1,4 @@ +- `RULE-11-3`, `RULE-11-4`, `RULE-11-5`, `RULE-11-7` - `CastBetweenObjectPointerAndDifferentObjectType.ql`, `ConversionBetweenPointerToObjectAndIntegerType.ql`, `ConversionFromPointerToVoidIntoPointerToObject.ql`, `CastBetweenPointerToObjectAndNonIntArithmeticType.ql`: + - Removed false positives where casts involved a specified void type pointer, e.g. `const void*`, which should not be considered as a pointer to object. +- `RULE-11-5` - `ConversionFromPointerToVoidIntoPointerToObject.ql`: + - Addressed false negatives where the pointer-to-void was specified. \ No newline at end of file diff --git a/change_notes/2024-10-15-a7-1-3-multi-refs.md b/change_notes/2024-10-15-a7-1-3-multi-refs.md new file mode 100644 index 0000000000..39e00495cb --- /dev/null +++ b/change_notes/2024-10-15-a7-1-3-multi-refs.md @@ -0,0 +1,2 @@ +- `A7-1-3` - `CvQualifiersNotPlacedOnTheRightHandSide.ql`: + - Removed false positives where a correctly CV-qualified typedef variable type was also referenced in the initializer. \ No newline at end of file diff --git a/change_notes/2024-10-15-fix-fp-739-a14-5-2.md b/change_notes/2024-10-15-fix-fp-739-a14-5-2.md new file mode 100644 index 0000000000..6e3f422718 --- /dev/null +++ b/change_notes/2024-10-15-fix-fp-739-a14-5-2.md @@ -0,0 +1,2 @@ +- `A14-5-2` - `NonTemplateMemberDefinedInTemplate.ql` + - Fixes #739. Correctly detect template parameters specified in using alias base types, e.g. `using T1 = some_type::Type;`. diff --git a/change_notes/2024-10-15-lits-and-constants-10-4.md b/change_notes/2024-10-15-lits-and-constants-10-4.md new file mode 100644 index 0000000000..cfcb309204 --- /dev/null +++ b/change_notes/2024-10-15-lits-and-constants-10-4.md @@ -0,0 +1,5 @@ + - `RULE-10-4` - `OperandswithMismatchedEssentialTypeCategory.ql`: + - Removed false positives where a specified or typedef'd enum type was compared to an enum constant type. + - `EssentialType` - for all queries related to essential types: + - `\n` and other control characters are now correctly deduced as essentially char type, instead of an essentially integer type. + - Enum constants for anonymous enums are now correctly deduced as an essentially signed integer type instead of essentially enum. \ No newline at end of file diff --git a/change_notes/2024-10-17-suffixes.md b/change_notes/2024-10-17-suffixes.md new file mode 100644 index 0000000000..16d8ca4cda --- /dev/null +++ b/change_notes/2024-10-17-suffixes.md @@ -0,0 +1,4 @@ + - `5.13.4` - `UnsignedLiteralsNotAppropriatelySuffixed.ql`: + - Expand detection to binary literals. + - `M2-13-3` - `MissingUSuffix.ql`: + - Expand detection to binary literals. \ No newline at end of file diff --git a/change_notes/2024-10-18-init-base-class-deleted.md b/change_notes/2024-10-18-init-base-class-deleted.md new file mode 100644 index 0000000000..992e1e88a2 --- /dev/null +++ b/change_notes/2024-10-18-init-base-class-deleted.md @@ -0,0 +1,2 @@ +- `A12-1-1`, `RULE-15-1-2` - `InitializeAllVirtualBaseClasses.ql`, `ExplicitConstructorBaseClassInitialization.ql`: + - Remove false positives for deleted member functions. \ No newline at end of file diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index fede5b3e69..c7c633184a 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index 393c1222fd..81ca7039c3 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -32,25 +32,13 @@ where // allow for overloading with different number of parameters, because there is no // confusion on what function will be called. f.getNumberOfParameters() = c.getNumberOfParameters() and - //build a dynamic select statement that guarantees to read that the overloading function is the explicit one - if - (f instanceof CopyConstructor or f instanceof MoveConstructor) and - f.isCompilerGenerated() - then ( - ( - f instanceof CopyConstructor and - msg = "implicit copy constructor" - or - f instanceof MoveConstructor and - msg = "implicit move constructor" - ) and - firstMsgSegment = " with a forwarding reference parameter " and - overloaded = f and - overload = c - ) else ( - msg = "function with a forwarding reference parameter" and - firstMsgSegment = " " and - overloaded = c and - overload = f - ) + //ignore implicit copy and move constructor overloads + not ( + f.isCompilerGenerated() and + (f instanceof CopyConstructor or f instanceof MoveConstructor) + ) and + msg = "function with a forwarding reference parameter" and + firstMsgSegment = " " and + overloaded = c and + overload = f select overload, "Function" + firstMsgSegment + "overloads a $@.", overloaded, msg diff --git a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql index 4a81e32b0f..7f9ced9909 100644 --- a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql +++ b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql @@ -167,7 +167,10 @@ where mf = c.getAMemberFunction() and not mf.isCompilerGenerated() and not exists(mf.getBlock()) ) ) - ) + ) and + // Omit using alias (cf. https://github.com/github/codeql-coding-standards/issues/739) + // Exclude Using alias which refer directly to a TypeParameter + not d.(UsingAliasTypedefType).getBaseType() instanceof TemplateParameter select d, "Member " + d.getName() + " template class does not use any of template arguments of its $@.", d.getDeclaringType(), "declaring type" diff --git a/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql b/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql index 54968dc223..5d34f89c7d 100644 --- a/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql +++ b/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql @@ -20,37 +20,50 @@ import cpp import codingstandards.cpp.autosar /** - * Holds if declaration `e` using a `TypedefType` is CV-qualified - * - * For example, given `using intconstptr = int * const`: - * the predicate holds for `const/volatile intconstptr ptr1`, but not for `intconstptr ptr2` + * Unwrap layers of indirection that occur on the right side of the type. */ -predicate containsExtraSpecifiers(VariableDeclarationEntry e) { - e.getType().toString().matches("const %") or - e.getType().toString().matches("volatile %") +Type unwrapIndirection(Type type) { + if type instanceof DerivedType and not type instanceof SpecifiedType + then result = unwrapIndirection(type.(DerivedType).getBaseType()) + else result = type } // DeclStmts that have a TypedefType name use (ie TypeMention) in them //AND TypeMention.getStartColumn() - DeclStmt.getStartColumn() > len(const) //AND the declared thing contains one of these "extra" specifiers in the DeclarationEntry Location -from VariableDeclarationEntry e, TypedefType t, TypeMention tm +from + VariableDeclarationEntry e, TypedefType t, TypeMention tm, string message, Element explainer, + string explainerMessage where not isExcluded(e, ConstPackage::cvQualifiersNotPlacedOnTheRightHandSideQuery()) and - containsExtraSpecifiers(e) and + // Variable type is specified, and has the typedef type as a base type + unwrapIndirection(e.getType()).(SpecifiedType).getBaseType() = t and exists(string filepath, int startline | e.getLocation().hasLocationInfo(filepath, startline, _, _, _) and tm.getLocation().hasLocationInfo(filepath, startline, _, _, _) and e = t.getATypeNameUse() and tm.getMentionedType() = t and + // TypeMention occurs before the variable declaration + tm.getLocation().getStartColumn() < e.getLocation().getStartColumn() and exists(DeclStmt s | s.getDeclarationEntry(_) = e and - //const could fit in there + // TypeMention occurs after the start of the StmtDecl, with enough space for const/volatile tm.getLocation().getStartColumn() - s.getLocation().getStartColumn() > 5 - //volatile could fit in there - //but the above condition subsumes this one - //l.getStartColumn() - tm.getLocation().getStartColumn() > 8 ) + ) and + if exists(t.getFile().getRelativePath()) + then + message = + "There is possibly a const or volatile specifier on the left hand side of typedef name $@." and + explainer = t and + explainerMessage = t.getName() + else ( + // Type occurs outside source root, so don't link + message = + "There is possibly a const or volatile specifier on the left hand side of typedef name " + + t.getName() + "." and + // explainer not used in this case + explainer = e and + explainerMessage = "" ) -select e, - "There is possibly a const or volatile specifier on the left hand side of typedef name $@.", t, - t.getName() +select e, message, explainer, explainerMessage diff --git a/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql b/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql index b8593e75c0..f175cb8992 100644 --- a/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql +++ b/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql @@ -26,5 +26,6 @@ where then name = unusedFunction.getQualifiedName() else name = unusedFunction.getName() ) and - not unusedFunction.isDeleted() + not unusedFunction.isDeleted() and + not unusedFunction instanceof SpecialMemberFunction select unusedFunction, "Function " + name + " is " + unusedFunction.getDeadCodeType() diff --git a/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql b/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql new file mode 100644 index 0000000000..bcbf6f4e1b --- /dev/null +++ b/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql @@ -0,0 +1,31 @@ +/** + * @id cpp/autosar/unused-spl-member-function + * @name M0-1-10: Every defined function should be called at least once + * @description Uncalled functions complicate the program and can indicate a possible mistake on the + * part of the programmer. + * @kind problem + * @precision medium + * @problem.severity warning + * @tags external/autosar/id/m0-1-10 + * readability + * maintainability + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/advisory + */ + +import cpp +import codingstandards.cpp.autosar +import codingstandards.cpp.deadcode.UnusedFunctions + +from UnusedFunctions::UnusedSplMemberFunction unusedSplMemFunction, string name +where + not isExcluded(unusedSplMemFunction, DeadCodePackage::unusedFunctionQuery()) and + ( + if exists(unusedSplMemFunction.getQualifiedName()) + then name = unusedSplMemFunction.getQualifiedName() + else name = unusedSplMemFunction.getName() + ) and + not unusedSplMemFunction.isDeleted() +select unusedSplMemFunction, + "Special member function " + name + " is " + unusedSplMemFunction.getDeadCodeType() diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 41a02a6afb..d470b12f70 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected index 6e79cb00a4..cb71b56b51 100644 --- a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected +++ b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected @@ -1,7 +1,3 @@ | test.cpp:24:6:24:7 | F1 | Function overloads a $@. | test.cpp:27:25:27:26 | F1 | function with a forwarding reference parameter | | test.cpp:50:3:50:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | | test.cpp:51:3:51:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | -| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit copy constructor | -| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit move constructor | -| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit copy constructor | -| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit move constructor | diff --git a/cpp/autosar/test/rules/A13-3-1/test.cpp b/cpp/autosar/test/rules/A13-3-1/test.cpp index 82fe866a0a..8ed4e4d609 100644 --- a/cpp/autosar/test/rules/A13-3-1/test.cpp +++ b/cpp/autosar/test/rules/A13-3-1/test.cpp @@ -40,7 +40,7 @@ template void F1(T &&x) {} // class A { public: // COMPLIANT[FALSE_POSITIVE] - by exception, constrained to not match - // copy/move ctors + // explicit copy/move ctors template < typename T, std::enable_if_t>, A>::value> * = nullptr> - B(T &&value) {} // COMPLIANT[FALSE_POSITIVE] - by exception + B(T &&value) {} // COMPLIANT - by exception }; int main() {} @@ -74,5 +74,6 @@ int main() {} class C { public: C() {} - template C(T &&) {} // NON_COMPLIANT + template + C(T &&) {} // COMPLIANT - ignore overloads of implicit copy/move ctors }; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected b/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected index d45a3c6871..f0c78e2af1 100644 --- a/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected +++ b/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected @@ -1,4 +1,3 @@ -| test.cpp:10:9:10:10 | T1 | Member T1 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:11:9:11:10 | T2 | Member T2 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:28:31:28:33 | C12 | Member C12 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:45:7:45:8 | a1 | Member a1 template class does not use any of template arguments of its $@. | test.cpp:37:31:37:33 | C22 | declaring type | diff --git a/cpp/autosar/test/rules/A14-5-2/test.cpp b/cpp/autosar/test/rules/A14-5-2/test.cpp index e60a955c68..260ff5b4b2 100644 --- a/cpp/autosar/test/rules/A14-5-2/test.cpp +++ b/cpp/autosar/test/rules/A14-5-2/test.cpp @@ -7,7 +7,7 @@ template class C1 { public: enum E1 : T { e1, e2 }; // COMPLIANT - using T1 = typename template_base::type; // COMPLIANT[FALSE_POSITIVE] + using T1 = typename template_base::type; // COMPLIANT using T2 = typename template_base::type; // NON_COMPLIANT class C11 { // COMPLIANT @@ -156,4 +156,4 @@ template class V { void f4() { V v; v.type(); -} \ No newline at end of file +} diff --git a/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected b/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected index 9d6a710449..d845df142d 100644 --- a/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected +++ b/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected @@ -1,3 +1,4 @@ | test.cpp:9:16:9:19 | definition of ptr1 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:1:7:1:12 | intptr | intptr | | test.cpp:10:19:10:22 | definition of ptr2 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:1:7:1:12 | intptr | intptr | | test.cpp:19:21:19:24 | definition of ptr8 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:3:7:3:17 | constintptr | constintptr | +| test.cpp:32:23:32:26 | definition of u32d | There is possibly a const or volatile specifier on the left hand side of typedef name uint32_t. | test.cpp:32:23:32:26 | definition of u32d | | diff --git a/cpp/autosar/test/rules/A7-1-3/test.cpp b/cpp/autosar/test/rules/A7-1-3/test.cpp index 621a64115d..39f53b8623 100644 --- a/cpp/autosar/test/rules/A7-1-3/test.cpp +++ b/cpp/autosar/test/rules/A7-1-3/test.cpp @@ -18,4 +18,16 @@ void f() { constintptr const ptr7 = &l; // COMPLIANT const constintptr ptr8 = &l; // NON_COMPLIANT inttypedef ptr9 = l; // COMPLIANT +} + +#include + +void false_positive() { + std::uint8_t u8{0}; + + auto const u32 = static_cast(u8); // COMPLIANT - auto ignored + std::uint32_t const u32b = static_cast(u8); // COMPLIANT + + const auto u32c = static_cast(u8); // COMPLIANT - auto ignored + const std::uint32_t u32d = static_cast(u8); // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected b/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected index d9ab0d38ac..912e2104e8 100644 --- a/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected +++ b/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected @@ -10,4 +10,5 @@ | test.cpp:50:5:50:6 | i3 | Function C::i3 is never called. | | test.cpp:51:8:51:9 | i4 | Function C::i4 is never called. | | test.cpp:52:15:52:16 | i5 | Function C::i5 is never called. | -| test.cpp:69:17:69:18 | g4 | Function g4 is never called. | +| test.cpp:79:6:79:21 | anUnusedFunction | Function anUnusedFunction is never called. | +| test.cpp:113:17:113:18 | g4 | Function g4 is never called. | diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected new file mode 100644 index 0000000000..e2bf0acc79 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected @@ -0,0 +1,2 @@ +| test.cpp:71:5:71:16 | ANestedClass | Special member function ANestedClass is never called. | +| test.cpp:82:5:82:22 | AnotherNestedClass | Special member function AnotherNestedClass is never called from a main function or entry point. | diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref new file mode 100644 index 0000000000..899f00fda1 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref @@ -0,0 +1 @@ +rules/M0-1-10/UnusedSplMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-1-10/test.cpp b/cpp/autosar/test/rules/M0-1-10/test.cpp index 748d2196ef..e1a19abf24 100644 --- a/cpp/autosar/test/rules/M0-1-10/test.cpp +++ b/cpp/autosar/test/rules/M0-1-10/test.cpp @@ -52,6 +52,50 @@ template class C { inline void i5() {} // NON_COMPLIANT - never used in any instantiation }; +#include "test.hpp" +#include + +template +constexpr bool aConstExprFunc() noexcept { // COMPLIANT + static_assert(std::is_trivially_copy_constructible() && + std::is_trivially_copy_constructible(), + "assert"); + return true; +} + +template class AClass { T anArr[val]; }; + +void aCalledFunc1() // COMPLIANT +{ + struct ANestedClass { + ANestedClass() noexcept(false) { // COMPLIANT: False Positive! + static_cast(0); + } + }; + static_assert(std::is_trivially_copy_constructible>(), + "Must be trivially copy constructible"); +} + +void anUnusedFunction() // NON_COMPLIANT +{ + struct AnotherNestedClass { + AnotherNestedClass() noexcept(false) { // NON_COMPLAINT + static_cast(0); + } + }; + AnotherNestedClass d; +} + +void aCalledFunc2() // COMPLIANT +{ + struct YetAnotherNestedClass { + YetAnotherNestedClass() noexcept(false) { + static_cast(0); + } // COMPLIANT + }; + YetAnotherNestedClass d; +}; + int main() { // COMPLIANT - this is a main like function which acts as an entry // point f3(); @@ -88,8 +132,37 @@ int main() { // COMPLIANT - this is a main like function which acts as an entry c1.getAT(); S s; c2.i1(s); + + int aVar; + aConstExprFunc(); + aCalledFunc1(); + aCalledFunc2(); } class M { public: M(const M &) = delete; // COMPLIANT - ignore if deleted -}; \ No newline at end of file +}; + +#include +int called_from_google_test_function( + int a_param) // COMPLIANT - called from TEST +{ + int something = a_param; + something++; + return something; +} + +TEST(sample_test, + called_from_google_test_function) // COMPLIANT - Google Test function +{ + bool pass = false; + if (called_from_google_test_function(0) >= 10) + pass = true; + struct a_nested_class_in_gtest { + a_nested_class_in_gtest() noexcept(false) { + static_cast(0); + } // COMPLIANT + }; + static_assert(std::is_trivially_copy_constructible(), + "assert"); +} diff --git a/cpp/autosar/test/rules/M0-1-10/test.hpp b/cpp/autosar/test/rules/M0-1-10/test.hpp new file mode 100644 index 0000000000..a2da990951 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/test.hpp @@ -0,0 +1,4 @@ +template +constexpr T aCalledFuncInHeader(T value) noexcept { // COMPLIANT + return static_cast(value); +} diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index f7cd4a0291..d70429c0de 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 2464828aac..ae70b1f71c 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index c974ec7eb8..ca3a7fb251 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 NumericLiteral, 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,21 @@ 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 + } + } + /** * A character literal. For example: * ``` diff --git a/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll b/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll index f82705e2c7..559c04ce98 100644 --- a/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll @@ -3,6 +3,7 @@ */ import cpp +import codingstandards.cpp.Class /** A function which represents the entry point into a specific thread of execution in the program. */ abstract class MainLikeFunction extends Function { } @@ -18,6 +19,37 @@ class MainFunction extends MainLikeFunction { } } +/** + * A test function from the GoogleTest infrastructure. + * + * Such functions can be treated as valid EntryPoint functions during analysis + * of "called" or "unused" functions. It is not straightforward to identify + * such functions, however, they have certain features that can be used for + * identification. This can be refined based on experiments/real-world use. + */ +class GoogleTestFunction extends MainLikeFunction { + GoogleTestFunction() { + // A GoogleTest function is named "TestBody" and + ( + this.hasName("TestBody") or + this instanceof SpecialMemberFunction + ) and + // it's parent class inherits a base class + exists(Class base | + base = this.getEnclosingAccessHolder+().(Class).getABaseClass+() and + ( + // with a name "Test" inside a namespace called "testing" + base.hasName("Test") and + base.getNamespace().hasName("testing") + or + // or at a location in a file called gtest.h (or gtest-internal.h, + // gtest-typed-test.h etc). + base.getDefinitionLocation().getFile().getBaseName().regexpMatch("gtest*.h") + ) + ) + } +} + /** * A "task main" function. */ diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll new file mode 100644 index 0000000000..ce72033ecc --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -0,0 +1,37 @@ +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 + signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() + } + + predicate isSmall() { size < any(IntType it | it.isSigned()).getSize() * 8 } + + int getSize() { result = size } + + predicate isSigned() { signed = true } + + float maxValue() { + signed = true and result = 2.pow(size - 1 * 1.0) - 1 + or + signed = false and result = 2.pow(size) - 1 + } + + float minValue() { + signed = true and result = -2.pow(size - 1) + or + signed = false and result = 0 + } + + string getRangeString() { result = minValue().toString() + ".." + maxValue().toString() } +} diff --git a/cpp/common/src/codingstandards/cpp/Literals.qll b/cpp/common/src/codingstandards/cpp/Literals.qll index 66e15b28dc..edec04152e 100644 --- a/cpp/common/src/codingstandards/cpp/Literals.qll +++ b/cpp/common/src/codingstandards/cpp/Literals.qll @@ -70,3 +70,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 = -literal.getValue().toFloat() } +} + +/** + * 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 = getValue().toFloat() } +} diff --git a/cpp/common/src/codingstandards/cpp/Pointers.qll b/cpp/common/src/codingstandards/cpp/Pointers.qll index 22dcbd187b..8ed55b2bc0 100644 --- a/cpp/common/src/codingstandards/cpp/Pointers.qll +++ b/cpp/common/src/codingstandards/cpp/Pointers.qll @@ -80,9 +80,9 @@ predicate isCastNullPointerConstant(Cast c) { class PointerToObjectType extends PointerType { PointerToObjectType() { not ( - this.getUnderlyingType() instanceof FunctionPointerType or - this.getUnderlyingType() instanceof VoidPointerType or - this.getBaseType().getUnderlyingType() instanceof IncompleteType + this.getUnspecifiedType() instanceof FunctionPointerType or + this.getUnspecifiedType() instanceof VoidPointerType or + this.getBaseType().getUnspecifiedType() instanceof IncompleteType ) } } diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll b/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll new file mode 100644 index 0000000000..634c1bf610 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll @@ -0,0 +1,119 @@ +/** + * A module for considering whether a result occurs in all copies of the code at a given location. + * + * Multiple copies of an element at the same location can occur for two main reasons: + * 1. Instantiations of a template + * 2. Re-compilation of a file under a different context + * This module helps ensure that a particular condition holds for all copies of a particular logical + * element. For example, this can be used to determine whether a line of code is dead in all copies + * of a piece of code. + * + * This module is parameterized by a set of _candidate_ elements in the program. For each candidate + * element, we determine whether all other elements in the same element set that occur at the same + * location in the program are also part of the same set, ignoring any results generated by macros. + * + * We do so by reporting a new type of result, `LogicalResultElement`, which represents a logical result + * where all instances of a element at a given location are considered to be part of the same set. + */ + +import cpp + +/** + * Holds if the `Element` `e` is not within a macro expansion, i.e. generated by a macro, but not + * the outermost `Element` or `Expr` generated by the macro. + */ +predicate isNotWithinMacroExpansion(Element e) { + not e.isInMacroExpansion() + or + exists(MacroInvocation mi | + mi.getStmt() = e + or + mi.getExpr() = e + or + mi.getStmt().(ExprStmt).getExpr() = e + | + not exists(mi.getParentInvocation()) + ) +} + +/** + * A type representing a set of Element's in the program that satisfy some condition. + * + * `HoldsForAllCopies::LogicalResultElement` will represent an element in this set + * iff all copies of that element satisfy the condition. + */ +signature class CandidateElementSig extends Element; + +/** The super set of relevant elements. */ +signature class ElementSetSig extends Element; + +/** + * A module for considering whether a result occurs in all copies of the code at a given location. + */ +module HoldsForAllCopies { + private predicate hasLocation( + ElementSet s, string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + s.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + final private class MyElement = ElementSet; + + /** + * A `Element` that appears at the same location as a candidate element. + */ + private class RelevantElement extends MyElement { + CandidateElement e; + + RelevantElement() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + hasLocation(this, filepath, startline, startcolumn, endline, endcolumn) and + hasLocation(e, filepath, startline, startcolumn, endline, endcolumn) + ) and + // Not within a macro expansion, as we cannot match up instances by location in that + // case + isNotWithinMacroExpansion(this) and + // Ignore catch handlers, as they occur at the same location as the catch block + not this instanceof Handler + } + + CandidateElement getCandidateElement() { result = e } + } + + newtype TResultElements = + TLogicalResultElement( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(CandidateElement s | + // Only consider candidates where we can match up the location + isNotWithinMacroExpansion(s) and + hasLocation(s, filepath, startline, startcolumn, endline, endcolumn) and + // All relevant elements that occur at the same location are candidates + forex(RelevantElement relevantElement | s = relevantElement.getCandidateElement() | + relevantElement instanceof CandidateElement + ) + ) + } + + /** + * A logical result element representing all copies of an element that occur at the same + * location, iff they all belong to the `CandidateElement` set. + */ + class LogicalResultElement extends TLogicalResultElement { + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this = TLogicalResultElement(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets a copy instance of this logical result element. */ + CandidateElement getAnElementInstance() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + this = TLogicalResultElement(filepath, startline, startcolumn, endline, endcolumn) and + hasLocation(result, filepath, startline, startcolumn, endline, endcolumn) + ) + } + + string toString() { result = getAnElementInstance().toString() } + } +} diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll index b01b80208e..fdd713b436 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll @@ -13,6 +13,7 @@ import cpp import codingstandards.cpp.DynamicCallGraph import codingstandards.cpp.EncapsulatingFunctions import codingstandards.cpp.FunctionEquivalence +import codingstandards.cpp.Class module UnusedFunctions { /** @@ -119,7 +120,12 @@ module UnusedFunctions { class UnusedFunction extends UsableFunction { UnusedFunction() { // This function, or an equivalent function, is not reachable from any entry point - not exists(EntryPoint ep | getAnEquivalentFunction(this) = ep.getAReachableFunction()) + not exists(EntryPoint ep | getAnEquivalentFunction(this) = ep.getAReachableFunction()) and + // and it is not a constexpr. Refer issue #646. + // The usages of constexpr is not well tracked and hence + // to avoid false positives, this is added. In case there is an improvement in + // handling constexpr in CodeQL, we can consider removing it. + not this.isConstexpr() } string getDeadCodeType() { @@ -128,4 +134,7 @@ module UnusedFunctions { else result = "never called." } } + + /** A `SpecialMemberFunction` which is an `UnusedFunction`. */ + class UnusedSplMemberFunction extends UnusedFunction, SpecialMemberFunction { } } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll new file mode 100644 index 0000000000..024aa9b76c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Banned2Query = TCallToBannedRandomFunctionQuery() + +predicate isBanned2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `callToBannedRandomFunction` query + Banned2Package::callToBannedRandomFunctionQuery() and + queryId = + // `@id` for the `callToBannedRandomFunction` query + "c/misra/call-to-banned-random-function" and + ruleId = "RULE-21-24" and + category = "required" +} + +module Banned2Package { + Query callToBannedRandomFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToBannedRandomFunction` query + TQueryC(TBanned2PackageQuery(TCallToBannedRandomFunctionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 581585da5c..3833533d50 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -3,6 +3,7 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import Banned +import Banned2 import BitfieldTypes import BitfieldTypes2 import Concurrency1 @@ -73,10 +74,12 @@ import Strings2 import Strings3 import Syntax import Types1 +import Types2 /** The TQuery type representing this language * */ newtype TCQuery = TBannedPackageQuery(BannedQuery q) or + TBanned2PackageQuery(Banned2Query q) or TBitfieldTypesPackageQuery(BitfieldTypesQuery q) or TBitfieldTypes2PackageQuery(BitfieldTypes2Query q) or TConcurrency1PackageQuery(Concurrency1Query q) or @@ -146,11 +149,13 @@ 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) { isBannedQueryMetadata(query, queryId, ruleId, category) or + isBanned2QueryMetadata(query, queryId, ruleId, category) or isBitfieldTypesQueryMetadata(query, queryId, ruleId, category) or isBitfieldTypes2QueryMetadata(query, queryId, ruleId, category) or isConcurrency1QueryMetadata(query, queryId, ruleId, category) or @@ -220,5 +225,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..3b2d3a4342 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll @@ -0,0 +1,95 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +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) { + 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 `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 + 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 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 = + // `Query` type for `useOfBannedSmallIntegerConstantMacro` query + TQueryC(TTypes2PackageQuery(TUseOfBannedSmallIntegerConstantMacroQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll index 40b8795e5e..f11741fde5 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll @@ -12,6 +12,7 @@ newtype DeadCodeQuery = TUnusedTypeDeclarationsQuery() or TUnreachableCodeQuery() or TUnusedFunctionQuery() or + TUnusedSplMemberFunctionQuery() or TInfeasiblePathQuery() or TUnusedLocalVariableQuery() or TUnusedGlobalOrNamespaceVariableQuery() or @@ -94,6 +95,15 @@ predicate isDeadCodeQueryMetadata(Query query, string queryId, string ruleId, st ruleId = "M0-1-10" and category = "advisory" or + query = + // `Query` instance for the `unusedSplMemberFunction` query + DeadCodePackage::unusedSplMemberFunctionQuery() and + queryId = + // `@id` for the `unusedSplMemberFunction` query + "cpp/autosar/unused-spl-member-function" and + ruleId = "M0-1-10" and + category = "advisory" + or query = // `Query` instance for the `infeasiblePath` query DeadCodePackage::infeasiblePathQuery() and @@ -224,6 +234,13 @@ module DeadCodePackage { TQueryCPP(TDeadCodePackageQuery(TUnusedFunctionQuery())) } + Query unusedSplMemberFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedSplMemberFunction` query + TQueryCPP(TDeadCodePackageQuery(TUnusedSplMemberFunctionQuery())) + } + Query infeasiblePathQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll b/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll index 2b5be15e80..fb0bd772a2 100644 --- a/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll +++ b/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll @@ -12,6 +12,7 @@ */ import cpp +import codingstandards.cpp.alertreporting.HoldsForAllCopies import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.deadcode.UselessAssignments @@ -31,10 +32,6 @@ predicate isDeadOrUnreachableStmt(Stmt s) { s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() } -/** - * Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully - * affect the program. - */ predicate isDeadStmt(Stmt s) { // A `DeclStmt` is dead code if: // - All the declarations are variable declarations @@ -108,17 +105,33 @@ predicate isDeadStmt(Stmt s) { exists(TryStmt ts | s = ts and isDeadStmt(ts.getStmt())) } -query predicate problems(Stmt s, string message) { - not isExcluded(s, getQuery()) and +/** + * Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully + * affect the program. + */ +class DeadStmtInstance extends Stmt { + DeadStmtInstance() { + isDeadStmt(this) and + // Exclude compiler generated statements + not this.isCompilerGenerated() and + // Exclude code fully generated by macros, because the code may be "live" in other expansions + isNotWithinMacroExpansion(this) and + // MISRA defines dead code as an "_executed_ statement whose removal would not affect the program + // output". We therefore exclude unreachable statements as they are, by definition, not executed. + not this.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() + } +} + +class DeadStmt = HoldsForAllCopies::LogicalResultElement; + +query predicate problems(DeadStmt s, string message) { + not isExcluded(s.getAnElementInstance(), getQuery()) and message = "This statement is dead code." and - isDeadStmt(s) and // Report only the highest level dead statement, to avoid over reporting - not isDeadStmt(s.getParentStmt()) and - // MISRA defines dead code as an "_executed_ statement whose removal would not affect the program - // output". We therefore exclude unreachable statements as they are, by definition, not executed. - not s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() and - // Exclude code fully generated by macros, because the code may be "live" in other expansions - not s.isInMacroExpansion() and - // Exclude compiler generated statements - not s.isCompilerGenerated() + not exists(DeadStmt parent | + // All instances must share a dead statement parent for us to report the parent instead + forall(Stmt instance | instance = s.getAnElementInstance() | + parent.getAnElementInstance() = instance.getParentStmt() + ) + ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll b/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll index b3cfe203ac..ffb08283cd 100644 --- a/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll +++ b/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll @@ -38,6 +38,8 @@ query predicate problems( not c.isCompilerGenerated() and // Not a defaulted constructor not c.isDefaulted() and + // Not a deleted constructor + not c.isDeleted() and declaringType_string = declaringType.getSimpleName() and baseClass_string = baseClass.getSimpleName() and message = diff --git a/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll index 0b9ccb17f1..a9535d9bfc 100644 --- a/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll @@ -19,6 +19,8 @@ query predicate problems(Cpp14Literal::NumericLiteral nl, string message) { nl instanceof Cpp14Literal::OctalLiteral and literalKind = "Octal" or nl instanceof Cpp14Literal::HexLiteral and literalKind = "Hex" + or + nl instanceof Cpp14Literal::BinaryLiteral and literalKind = "Binary" ) and // This either directly has an unsigned integer type, or it is converted to an unsigned integer type nl.getType().getUnspecifiedType().(IntegralType).isUnsigned() and diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 69483ef611..ed33ca2398 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev license: MIT dependencies: codeql/cpp-all: 0.12.9 diff --git a/cpp/common/test/includes/custom-library/gtest/gtest-internal.h b/cpp/common/test/includes/custom-library/gtest/gtest-internal.h new file mode 100644 index 0000000000..31d47b714f --- /dev/null +++ b/cpp/common/test/includes/custom-library/gtest/gtest-internal.h @@ -0,0 +1,29 @@ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test + +#define GTEST_TEST_(test_suite_name, test_name, parent_class) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \ + ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + (const GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &) = delete; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \ + const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name) &) = delete; /* NOLINT */ \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + (GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &&) noexcept = delete; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \ + GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name) &&) noexcept = delete; /* NOLINT */ \ + \ + private: \ + void TestBody() override; \ + }; \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() \ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/cpp/common/test/includes/custom-library/gtest/gtest.h b/cpp/common/test/includes/custom-library/gtest/gtest.h new file mode 100644 index 0000000000..65fce9fc5a --- /dev/null +++ b/cpp/common/test/includes/custom-library/gtest/gtest.h @@ -0,0 +1,28 @@ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_ + +#include "gtest/gtest-internal.h" + +namespace testing { + +class Test +{ + public: + virtual ~Test(); + protected: + // Creates a Test object. + Test(); + private: + virtual void TestBody() = 0; + Test(const Test&) = delete; + Test& operator=(const Test&) = delete; +}; + +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test) + +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_ diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 249c64696e..de878794a7 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/test/rules/deadcode/DeadCode.expected b/cpp/common/test/rules/deadcode/DeadCode.expected index aec93e0914..1756231343 100644 --- a/cpp/common/test/rules/deadcode/DeadCode.expected +++ b/cpp/common/test/rules/deadcode/DeadCode.expected @@ -15,3 +15,7 @@ | test.cpp:85:3:85:43 | declaration | This statement is dead code. | | test.cpp:87:3:87:30 | declaration | This statement is dead code. | | test.cpp:90:3:90:50 | declaration | This statement is dead code. | +| test.cpp:116:3:116:21 | ExprStmt | This statement is dead code. | +| test.cpp:117:3:117:27 | ExprStmt | This statement is dead code. | +| test.cpp:118:7:118:32 | ExprStmt | This statement is dead code. | +| test.cpp:139:3:139:35 | ExprStmt | This statement is dead code. | diff --git a/cpp/common/test/rules/deadcode/test.cpp b/cpp/common/test/rules/deadcode/test.cpp index d9c0cab277..d40667539d 100644 --- a/cpp/common/test/rules/deadcode/test.cpp +++ b/cpp/common/test/rules/deadcode/test.cpp @@ -91,3 +91,51 @@ int test_dead_code(int x) { return live5 + live6 + constexpr_used_array[1]; // COMPLIANT } + +class Foo { +public: + void bar() { may_have_side_effects(); } +}; + +class Baz { +public: + void bar() {} // No side effects +}; + +#define FULL_STMT_NO_SIDE_EFFECTS no_side_effects(1); +#define PART_STMT_NO_SIDE_EFFECTS no_side_effects(1) +#define BLOCK_SOME_SIDE_EFFECTS \ + { \ + may_have_side_effects(); \ + no_side_effects(1); \ + } + +template void test_template() { + T t; + t.bar(); // COMPLIANT + no_side_effects(1); // NON_COMPLIANT + FULL_STMT_NO_SIDE_EFFECTS // NON_COMPLIANT + PART_STMT_NO_SIDE_EFFECTS; // NON_COMPLIANT + BLOCK_SOME_SIDE_EFFECTS; // COMPLIANT - cannot determine loc for + // no_side_effects(1) +} + +template void test_variant_side_effects() { + T t; + t.bar(); // COMPLIANT - not dead in at least one instance +} + +template void test_unused_template() { + T t; + t.bar(); // COMPLIANT + no_side_effects( + 1); // NON_COMPLIANT[FALSE_NEGATIVE] - unused templates are not extracted +} + +void test() { + test_template(); + test_template(); + test_variant_side_effects(); // COMPLIANT + test_variant_side_effects(); // NON_COMPLIANT - no effect in this + // instantiation +} \ No newline at end of file diff --git a/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp b/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp index 7721da8b01..8e6b318b19 100644 --- a/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp +++ b/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp @@ -61,4 +61,13 @@ class Derived6 : public Base2 { private: Base2 b; +}; + +class Base3 {}; + +class Derived7 final : public Base3 { +public: + Derived7() = delete; // COMPLIANT + Derived7(const Derived7 &) = delete; // COMPLIANT + Derived7(Derived7 &&) = delete; // COMPLIANT }; \ No newline at end of file diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected index 56dce901dd..3326ede548 100644 --- a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected @@ -1 +1,18 @@ -| test.cpp:3:3:3:12 | 4294967295 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:111:3:111:12 | 2147483648 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:116:3:116:20 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:139:3:139:21 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:162:3:162:21 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:185:3:185:22 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:208:3:208:22 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:227:3:227:14 | 2147483648 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:232:3:232:25 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:249:3:249:26 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:266:3:266:26 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:283:3:283:27 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:300:3:300:27 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:315:3:315:36 | 2147483648 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:322:3:322:68 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:365:3:365:69 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:412:3:412:69 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:457:3:457:70 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:502:3:502:70 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp index e5b3abfa47..fcbd51b3de 100644 --- a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp @@ -1,5 +1,546 @@ -void test_unsigned_literals_without_suffix() { - 0xFFFFFFFFU; // COMPLIANT - literal explicitly marked as unsigned - 0xFFFFFFFF; // NON_COMPLIANT - literal is too large for a signed int, so has - // type unsigned int +// Assumed platform in qltest is linux_x86_64, so +// int, long, long long sizes are assumed to be 32, 64, 64 bits respectively + +// The type of an integer constant is determined by "6.4.4.1 Integer constants" +// in the C11 Standard. The principle is that any decimal integer constant will +// be signed, unless it has the `U` or `u` suffix. Any hexadecimal integer will +// depend on whether it is larger than the maximum value of the smallest signed +// integer value that can hold the value. So the signedness depends on the +// magnitude of the constant. + +void test_decimal_constants() { + 0; // COMPLIANT + 2147483648; // COMPLIANT - larger than int, but decimal constants never use + // unsigned without the suffix, so will be `long` + 4294967296; // COMPLIANT - larger than unsigned int, still `long` + 9223372036854775807; // COMPLIANT - max long int + // 9223372036854775808; Not a valid integer constant, out of signed range + 0U; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648U; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296U; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807U; // COMPLIANT - max long int + 9223372036854775808U; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + 0u; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648u; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296u; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807u; // COMPLIANT - max long int + 9223372036854775808u; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + + // l suffix + 0l; // COMPLIANT + 2147483648l; // COMPLIANT - within the range of long int + 4294967296l; // COMPLIANT - within the range of long int + 9223372036854775807l; // COMPLIANT - max long int + // 9223372036854775808l; Not a valid integer constant, out of signed range + 0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lU; // COMPLIANT - max long int + 9223372036854775808lU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lu; // COMPLIANT - max long int + 9223372036854775808lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // L suffix + 0L; // COMPLIANT + 2147483648L; // COMPLIANT - within the range of long int + 4294967296L; // COMPLIANT - within the range of long int + 9223372036854775807L; // COMPLIANT - max long int + // 9223372036854775808L; Not a valid integer constant, out of signed range + 0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LU; // COMPLIANT - max long int + 9223372036854775808LU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807Lu; // COMPLIANT - max long int + 9223372036854775808Lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // ll suffix + 0ll; // COMPLIANT + 2147483648ll; // COMPLIANT - within the range of long long int + 4294967296ll; // COMPLIANT - within the range of long long int + 9223372036854775807ll; // COMPLIANT - max long long int + // 9223372036854775808ll; Not a valid integer constant, out of signed range + 0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llU; // COMPLIANT - max long long int + 9223372036854775808llU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llu; // COMPLIANT - max long long int + 9223372036854775808llu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + + // LL suffix + 0LL; // COMPLIANT + 2147483648LL; // COMPLIANT - within the range of long long int + 4294967296LL; // COMPLIANT - within the range of long long int + 9223372036854775807LL; // COMPLIANT - max long long int + // 9223372036854775808LL; Not a valid integer constant, out of signed range + 0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLU; // COMPLIANT - max long long int + 9223372036854775808LLU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLu; // COMPLIANT - max long long int + 9223372036854775808LLu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int +} + +void test_hexadecimal_constants() { + 0x0; // COMPLIANT - uses signed int + 0x7FFFFFFF; // COMPLIANT - max value held by signed int + 0x80000000; // NON_COMPLIANT - larger than max signed int, so will be unsigned + // int + 0x100000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFF; // COMPLIANT - max long int + 0x8000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000u; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `l` suffix + 0x0l; // COMPLIANT - uses signed int + 0x7FFFFFFFl; // COMPLIANT - max value held by signed int + 0x80000000l; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000l; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFl; // COMPLIANT - max long int + 0x8000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `L` suffix + 0x0L; // COMPLIANT - uses signed int + 0x7FFFFFFFL; // COMPLIANT - max value held by signed int + 0x80000000L; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000L; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFL; // COMPLIANT - max long int + 0x8000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `ll` suffix + 0x0ll; // COMPLIANT - uses signed int + 0x7FFFFFFFll; // COMPLIANT - max value held by signed int + 0x80000000ll; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000ll; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFll; // COMPLIANT - max long long int + 0x8000000000000000ll; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `LL` suffix + 0x0LL; // COMPLIANT - uses signed int + 0x7FFFFFFFLL; // COMPLIANT - max value held by signed int + 0x80000000LL; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000LL; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFLL; // COMPLIANT - max long long int + 0x8000000000000000LL; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly +} + +void test_octal_constants() { + 00; // COMPLIANT - uses signed int + 017777777777; // COMPLIANT - max value held by signed int + 020000000000; // NON_COMPLIANT - larger than max signed int, so will be + // unsigned int + 040000000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0777777777777777777777; // COMPLIANT - max long int + 01000000000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00U; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777U; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777U; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000U; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `l` suffix + 00l; // COMPLIANT - uses signed long + 017777777777l; // COMPLIANT - uses signed long + 020000000000l; // COMPLIANT - uses signed long + 040000000000l; // COMPLIANT - uses signed long + 0777777777777777777777l; // COMPLIANT - max long int + 01000000000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `L` suffix + 00L; // COMPLIANT - uses signed long + 017777777777L; // COMPLIANT - uses signed long + 020000000000L; // COMPLIANT - uses signed long + 040000000000L; // COMPLIANT - uses signed long + 0777777777777777777777L; // COMPLIANT - COMPLIANT - uses signed long + 01000000000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00UL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777UL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `ll` suffix + 00ll; // COMPLIANT - uses signed long long + 017777777777ll; // COMPLIANT - uses signed long long + 020000000000ll; // COMPLIANT - uses signed long long + 040000000000ll; // COMPLIANT - uses signed long long + 0777777777777777777777ll; // COMPLIANT - max long int + 01000000000000000000000ll; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 017777777777LL; // COMPLIANT - uses signed long long + 020000000000LL; // COMPLIANT - uses signed long long + 040000000000LL; // COMPLIANT - uses signed long long + 0777777777777777777777LL; // COMPLIANT - max long int + 01000000000000000000000LL; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly +} + +void test_binary_constants() { + 0b0; // COMPLIANT - uses signed int + 0b1111111111111111111111111111111; // COMPLIANT - max value held by signed int + 0b10000000000000000000000000000000; // NON_COMPLIANT - larger than max signed + // int, so will be unsigned int + 0b100000000000000000000000000000000; // COMPLIANT - larger than unsigned int, + // but smaller than long int + 0b111111111111111111111111111111111111111111111111111111111111111; // COMPLIANT + // - max + // long int + 0b1000000000000000000000000000000000000000000000000000000000000000; // NON_COMPLIANT + // - + // larger + // than + // long + // int, so + // will be + // unsigned + // long + // int + 0b0U; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111U; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000U; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `l` suffix + 0b0l; // COMPLIANT - uses signed long + 0b1111111111111111111111111111111l; // COMPLIANT - uses signed long + 0b10000000000000000000000000000000l; // COMPLIANT - uses signed long + 0b100000000000000000000000000000000l; // COMPLIANT - uses signed long + 0b111111111111111111111111111111111111111111111111111111111111111l; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000l; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111Ul; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000Ul; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `L` suffix + 0b0L; // COMPLIANT - uses signed long + 0b1111111111111111111111111111111L; // COMPLIANT - uses signed long + 0b10000000000000000000000000000000L; // COMPLIANT - uses signed long + 0b100000000000000000000000000000000L; // COMPLIANT - uses signed long + 0b111111111111111111111111111111111111111111111111111111111111111L; // COMPLIANT + // - + // COMPLIANT + // - uses + // signed + // long + 0b1000000000000000000000000000000000000000000000000000000000000000L; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111UL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000UL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `ll` suffix + 0b0ll; // COMPLIANT - uses signed long long + 0b1111111111111111111111111111111ll; // COMPLIANT - uses signed long long + 0b10000000000000000000000000000000ll; // COMPLIANT - uses signed long long + 0b100000000000000000000000000000000ll; // COMPLIANT - uses signed long long + 0b111111111111111111111111111111111111111111111111111111111111111ll; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000ll; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111Ull; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000Ull; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 0b1111111111111111111111111111111LL; // COMPLIANT - uses signed long long + 0b10000000000000000000000000000000LL; // COMPLIANT - uses signed long long + 0b100000000000000000000000000000000LL; // COMPLIANT - uses signed long long + 0b111111111111111111111111111111111111111111111111111111111111111LL; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000LL; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111ULL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000ULL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly +} + +#define COMPLIANT_VAL 0x80000000U +#define NON_COMPLIANT_VAL 0x80000000 + +void test_macro() { + COMPLIANT_VAL; // COMPLIANT + NON_COMPLIANT_VAL; // NON_COMPLIANT[FALSE_NEGATIVE] - cannot determine suffix + // in macro expansions } \ No newline at end of file diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 19a37a8650..e0d399484e 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 0267a9ec70..e77a784a18 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.36.0-dev +version: 2.37.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/options b/cpp/options index 1f8961ecda..44267e9323 100644 --- a/cpp/options +++ b/cpp/options @@ -1 +1 @@ -semmle-extractor-options:--clang -std=c++14 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library \ No newline at end of file +semmle-extractor-options:--clang -std=c++14 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index b37f2ca9ad..58b473f755 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.36.0-dev +version: 2.37.0-dev license: MIT dependencies: codeql/cpp-all: 0.12.9 diff --git a/docs/user_manual.md b/docs/user_manual.md index db0f836339..17c08237ef 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -26,18 +26,19 @@ | 0.18.0 | 2024-01-30 | Luke Cartey | Update product description and coverage table. | | 0.19.0 | 2024-02-23 | Remco Vermeulen | Clarify the required use of Python version 3.9. | | 0.20.0 | 2024-02-23 | Remco Vermeulen | Add table describing the permitted guideline re-categorizations. | -| 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | -| 0.22.0 | 2024-10-02 | Luke Cartey | Add MISRA C 2023 as under development, and clarify MISRA C 2012 coverage. +| 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | +| 0.22.0 | 2024-10-02 | Luke Cartey | Add MISRA C 2023 as under development, and clarify MISRA C 2012 coverage. | +| 0.23.0 | 2024-10-21 | Luke Cartey | Add assembly as a hazard. | ## Release information -This user manual documents release `2.36.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.37.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: -- `code-scanning-cpp-query-pack-2.36.0-dev.zip`: coding standard queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.36.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.36.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.36.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.37.0-dev.zip`: coding standard queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.37.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.37.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.37.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -500,14 +501,15 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Use of incorrect build command | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Analysis integrity report lists all analyzed files, and must be crossed referenced with the list of files that are expected to be analyzed. | Ensure the build command corresponds to the build command that is used to build the release artifacts. | | | Incorrect build environment (e.g., concurrent builds writing to same file, overwriting translation unit/object file with different content) | Less or more output. Results are reported that are not violations of the guidelines or guideline violations are not reported | All reported results must be reviewed. | Ensure the build environment is configured to not use shared resources such as caches or artifact providers that can introduce race conditions. Report inconsistent results via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | Source root misspecification | Less output. The results cannot be correctly correlated to source files when viewing the resulting Sarif file in a Sarif viewer. | Verify that the reported results are display on the correct files in the Sarif viewer | Ensure the CodeQL CLI configured to use the correct source root that correspond to the root of the repository under consideration. | -| | Ouf of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | +| | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.36.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.37.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | | | Incorrect database. The information extracted by the CodeQL extractor deviates from what the compiler extracts resulting in an incorrect model of the source-code. | More or less output. Incorrect extraction can result in false positives or false negatives. | Combinations of supported compilers and CodeQL CLIs are tested against a [provided](https://github.com/github/codeql/tree/main/cpp/ql/test/library-tests) suite of test cases and a coding standards specific test suite to determine if the extracted information deviates from the expected information. | Report incorrect database issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | +| | Use of assembly language instructions, which are not inspected by CodeQL. | More or less output. Can result in false positives or false negatives. | Avoid the use of assembly language instructions where possible. Where unavoidable, encapasulate and isolate the use of assembly language in separate functions to limit impact. Careful manual review of all functions that use assembly language. | Ensure that all functions which use assembly language instructions are manually reviewed for compliance. | ## Reporting bugs diff --git a/rule_packages/c/Banned2.json b/rule_packages/c/Banned2.json new file mode 100644 index 0000000000..3898125d73 --- /dev/null +++ b/rule_packages/c/Banned2.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-21-24": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The standard functions rand() and srand() will not give high quality random results in all implementations and are therefore banned.", + "kind": "problem", + "name": "The random number generator functions of shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CallToBannedRandomFunction", + "tags": [ + "security", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "The random number generator functions of shall not be used" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/DeadCode.json b/rule_packages/c/DeadCode.json index ea5ddad703..d8e80d14d1 100644 --- a/rule_packages/c/DeadCode.json +++ b/rule_packages/c/DeadCode.json @@ -41,21 +41,7 @@ "readability", "maintainability", "external/misra/c/2012/third-edition-first-revision" - ], - "implementation_scope": { - "description": "This query identifies dead statements in the program of the following kinds:", - "items": [ - "Declarations of a non-static stack variable whose initializing expression is pure (i.e. has no side-effects) and that is never subsequently accessed in live code.", - "Blocks that contain only dead statements.", - "Do loops whose condition is pure, and whose body contains only dead statements.", - "If statements whose condition is pure, and whose then and else clauses (where they exist) only contain dead statements.", - "Label statements to which the code never jumps.", - "While loops whose condition is pure, and whose body contains only dead statements.", - "Expression statements whose expressions are pure.", - "Writes to a non-static stack variable that is never subsequently read in live code." - ] - }, - "shared_implementation_short_name": "DeadCode" + ] } ], "title": "There shall be no dead code" diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json new file mode 100644 index 0000000000..7e4c0827fe --- /dev/null +++ b/rule_packages/c/Types2.json @@ -0,0 +1,84 @@ +{ + "MISRA-C-2012": { + "RULE-7-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "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", + "severity": "warning", + "short_name": "InvalidIntegerConstantMacroArgument", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "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", + "external/misra/c/2012/amendment3" + ] + }, + { + "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": "high", + "severity": "warning", + "short_name": "IntegerConstantMacroArgumentUsesSuffix", + "tags": [ + "readability", + "maintainability", + "external/misra/c/2012/amendment3" + ] + }, + { + "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", + "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." + } + } + ], + "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", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "The small integer variants of the minimum-width integer constant macros shall not be used" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/DeadCode.json b/rule_packages/cpp/DeadCode.json index 7eb5c9f6f9..4746f86dee 100644 --- a/rule_packages/cpp/DeadCode.json +++ b/rule_packages/cpp/DeadCode.json @@ -194,6 +194,21 @@ "readability", "maintainability" ] + }, + { + "description": "Uncalled functions complicate the program and can indicate a possible mistake on the part of the programmer.", + "kind": "problem", + "name": "Every defined function should be called at least once", + "precision": "medium", + "severity": "warning", + "short_name": "UnusedSplMemberFunction", + "tags": [ + "readability", + "maintainability" + ], + "implementation_scope": { + "description": "In limited cases, this query can raise false-positives for special member function calls invoked from the C++ Metaprogramming library." + } } ], "title": "Every defined function should be called at least once."