diff --git a/change_notes/2025-12-15-update-catch-block-shadowing-dead-code.md b/change_notes/2025-12-15-update-catch-block-shadowing-dead-code.md new file mode 100644 index 0000000000..5249edf0d4 --- /dev/null +++ b/change_notes/2025-12-15-update-catch-block-shadowing-dead-code.md @@ -0,0 +1,6 @@ + - `M0-1-1`, `RULE-2-1` - `UnreachableCode.ql`: + - Updated detection of compiler generated code to include "handler" blocks, part of EDG's IR. + - "handler" blocks generated for `catch(...)` blocks are not excluded for technical reasons related to how the CFG is constructed. + - `M15-3-6`, `ERR54-CPP` - `CatchBlockShadowingMisra.ql`, `CathcBlockShadowingCert.ql`: + - Altered semantics to detect shadowing for a catch block involving type `T` preceding another catch block involving the same type `T`, such as `catch(T&)` shadowing `catch(T)` and vice versa. Previously, the involved types had to have a subtype relationship. + - Refactored catch block shadowing into a shared library for use in `RULE-0-0-1`. diff --git a/cpp/common/src/codingstandards/cpp/ast/Catch.qll b/cpp/common/src/codingstandards/cpp/ast/Catch.qll new file mode 100644 index 0000000000..5b75e9548d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ast/Catch.qll @@ -0,0 +1,17 @@ +import cpp + +CatchBlock getEarlierCatchBlock(CatchBlock cb) { + exists(TryStmt try, int i, int j | + cb = try.getCatchClause(j) and + i < j and + result = try.getCatchClause(i) + ) +} + +/** + * Get the body of a catch block, ie, the block of statements executed when the catch block is + * entered. + * + * This is useful, for instance, for CFG traversal + */ +Stmt getCatchBody(CatchBlock cb) { result = cb.getChild(0) } diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnreachableCode.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnreachableCode.qll index bf0040cacb..abeda3030f 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnreachableCode.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnreachableCode.qll @@ -8,6 +8,16 @@ predicate isCompilerGenerated(BasicBlock b) { b.(Stmt).isCompilerGenerated() or b.(Expr).isCompilerGenerated() + or + // Catch blocks come with a generated 'Handler' that owns the basic block of the catch body, + // however, `isCompilerGenerated` does not hold these generated handlers. + // + // We must also handle the case of `CatchAnyBlock`s. Unlike other catch blocks, for these the + // handler dominates the non-generated basic block, so in our CFG the `Handler` node is the entity + // used in the CFG rather than the basic block itself. Therefore we must not exclude these + // `BasicBlock`s. + b instanceof Handler and + not b.(Handler).getBlock() instanceof CatchAnyBlock } /** diff --git a/cpp/common/src/codingstandards/cpp/exceptions/Shadowing.qll b/cpp/common/src/codingstandards/cpp/exceptions/Shadowing.qll new file mode 100644 index 0000000000..75bd51ee45 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exceptions/Shadowing.qll @@ -0,0 +1,50 @@ +import cpp +import codingstandards.cpp.ast.Catch +import codingstandards.cpp.exceptions.ExceptionFlow + +/** + * A catch block which is shadowed by an earlier catch block for a base type. + * + * For example: + * + * ```cpp + * class Base { }; + * class Derived : public Base { }; + * + * try { + * // ... + * } catch (const Base& b) { // This catch block shadows the next one + * // Handle Base + * } catch (const Derived& d) { // This catch block is shadowed + * // Handle Derived + * } + * ``` + */ +class ShadowedCatchBlock extends CatchBlock { + CatchBlock cbBase; + Class baseType; + Class derivedType; + + ShadowedCatchBlock() { + cbBase = getEarlierCatchBlock(this) and + baseType = simplifyHandlerType(cbBase.getParameter().getType()) and + derivedType = simplifyHandlerType(this.getParameter().getType()) and + baseType.getADerivedClass*() = derivedType + } + + /** + * Get the earlier catch block which shadows this catch block. + */ + CatchBlock getShadowingBlock() { result = cbBase } + + /** + * Get the type of this catch block's derived class whose catch block is shadowed by an earlier + * catch block. + */ + Class getShadowedType() { result = derivedType } + + /** + * Get the type of the base class whose catch block precedes, and thus shadows, this catch block. + */ + Class getShadowingType() { result = baseType } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode3.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode3.qll new file mode 100644 index 0000000000..ed19906fd2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode3.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype DeadCode3Query = TUnreachableStatementQuery() + +predicate isDeadCode3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unreachableStatement` query + DeadCode3Package::unreachableStatementQuery() and + queryId = + // `@id` for the `unreachableStatement` query + "cpp/misra/unreachable-statement" and + ruleId = "RULE-0-0-1" and + category = "required" +} + +module DeadCode3Package { + Query unreachableStatementQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unreachableStatement` query + TQueryCPP(TDeadCode3PackageQuery(TUnreachableStatementQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 0c3cbcc28c..a910711091 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -16,6 +16,7 @@ import Const import Conversions import Conversions2 import DeadCode +import DeadCode3 import Declarations import ExceptionSafety import Exceptions1 @@ -78,6 +79,7 @@ newtype TCPPQuery = TConversionsPackageQuery(ConversionsQuery q) or TConversions2PackageQuery(Conversions2Query q) or TDeadCodePackageQuery(DeadCodeQuery q) or + TDeadCode3PackageQuery(DeadCode3Query q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or @@ -140,6 +142,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConversionsQueryMetadata(query, queryId, ruleId, category) or isConversions2QueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or + isDeadCode3QueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/catchblockshadowing/CatchBlockShadowing.qll b/cpp/common/src/codingstandards/cpp/rules/catchblockshadowing/CatchBlockShadowing.qll index 0ee0614f92..1d160f0411 100644 --- a/cpp/common/src/codingstandards/cpp/rules/catchblockshadowing/CatchBlockShadowing.qll +++ b/cpp/common/src/codingstandards/cpp/rules/catchblockshadowing/CatchBlockShadowing.qll @@ -6,27 +6,19 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.exceptions.ExceptionFlow +import codingstandards.cpp.exceptions.Shadowing abstract class CatchBlockShadowingSharedQuery extends Query { } Query getQuery() { result instanceof CatchBlockShadowingSharedQuery } query predicate problems( - CatchBlock cbDerived, string message, CatchBlock cbBase, string cbBaseDescription + ShadowedCatchBlock cbDerived, string message, CatchBlock cbBase, string cbBaseDescription ) { - exists(TryStmt try, Class baseType, Class derivedType | - not isExcluded(cbDerived, getQuery()) and - exists(int i, int j | - cbBase = try.getCatchClause(i) and - cbDerived = try.getCatchClause(j) and - i < j - ) and - baseType = simplifyHandlerType(cbBase.getParameter().getType()) and - derivedType = simplifyHandlerType(cbDerived.getParameter().getType()) and - baseType.getADerivedClass+() = derivedType and - message = - "Catch block for derived type " + derivedType + - " is shadowed by $@ earlier catch block for base type " + baseType + "." and - cbBaseDescription = "this" - ) + not isExcluded(cbDerived, getQuery()) and + cbBase = cbDerived.getShadowingBlock() and + message = + "Catch block for derived type " + cbDerived.getShadowedType() + + " is shadowed by $@ earlier catch block for base type " + cbDerived.getShadowingType() + "." and + cbBaseDescription = "this" } diff --git a/cpp/misra/src/rules/RULE-0-0-1/UnreachableStatement.ql b/cpp/misra/src/rules/RULE-0-0-1/UnreachableStatement.ql new file mode 100644 index 0000000000..4b63c487fc --- /dev/null +++ b/cpp/misra/src/rules/RULE-0-0-1/UnreachableStatement.ql @@ -0,0 +1,71 @@ +/** + * @id cpp/misra/unreachable-statement + * @name RULE-0-0-1: A function shall not contain unreachable statements + * @description Dead code can indicate a logic error, potentially introduced during code edits, or + * it may be unnecessary code that can be deleted. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-0-0-1 + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.deadcode.UnreachableCode +import codingstandards.cpp.exceptions.ExceptionFlow +import codingstandards.cpp.exceptions.ExceptionSpecifications +import codingstandards.cpp.exceptions.Shadowing + +/** + * MISRA C++ defines its own notion of unreachable statements, which is similar to, but distinct + * from, the general concept of unreachable code. + * + * This is not a superset of `BasicBlock.isReachable()`, because that includes all catch blocks. + * However, it is a superset of the transitive closure of blocks reachable from function entry via + * `getASuccessor`. + * + * The superset relationship can be read below, with extra reachable cases added for `&&`, `||`, + * `?:`, and `constexpr if`, and catch blocks that aren't shadowed by prior catch blocks. + */ +predicate isReachable(BasicBlock bb) { + bb = any(Function f).getEntryPoint() + or + isReachable(bb.getAPredecessor()) + or + exists(BinaryLogicalOperation op | + isReachable(op.getBasicBlock()) and + bb = op.getAnOperand().getBasicBlock() + ) + or + exists(ConditionalExpr cond | + isReachable(cond.getBasicBlock()) and + bb = [cond.getThen(), cond.getElse()].getBasicBlock() + ) + or + exists(FunctionCall call, TryStmt try, CatchBlock cb | + isReachable(call.getBasicBlock()) and + not isNoExceptTrue(call.getTarget()) and + try = getNearestTry(call.getEnclosingStmt()) and + cb = try.getACatchClause() and + not cb instanceof ShadowedCatchBlock and + bb = cb.getBasicBlock() + ) + or + exists(ConstexprIfStmt ifStmt | + isReachable(ifStmt.getBasicBlock()) and + bb = [ifStmt.getThen(), ifStmt.getElse()].getBasicBlock() + ) +} + +from BasicBlock bb +where + not isExcluded(bb, DeadCode3Package::unreachableStatementQuery()) and + not isReachable(bb) and + not isCompilerGenerated(bb) and + not affectedByMacro(bb) +select bb, "Unreachable statement in function '$@'.", bb.getEnclosingFunction(), + bb.getEnclosingFunction().getName() diff --git a/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.expected b/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.expected new file mode 100644 index 0000000000..7d578c9748 --- /dev/null +++ b/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.expected @@ -0,0 +1,28 @@ +| test.cpp:7:3:7:12 | declaration | Unreachable statement in function '$@'. | test.cpp:5:6:5:7 | f2 | f2 | +| test.cpp:18:14:19:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:10:6:10:7 | f3 | f3 | +| test.cpp:26:10:27:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:10:6:10:7 | f3 | f3 | +| test.cpp:43:5:43:14 | declaration | Unreachable statement in function '$@'. | test.cpp:40:6:40:7 | f4 | f4 | +| test.cpp:52:5:52:14 | declaration | Unreachable statement in function '$@'. | test.cpp:40:6:40:7 | f4 | f4 | +| test.cpp:63:3:63:12 | declaration | Unreachable statement in function '$@'. | test.cpp:40:6:40:7 | f4 | f4 | +| test.cpp:70:10:71:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:66:6:66:7 | f5 | f5 | +| test.cpp:75:11:76:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:66:6:66:7 | f5 | f5 | +| test.cpp:89:10:90:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:88:24:88:24 | f6 | f6 | +| test.cpp:92:10:93:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:88:24:88:24 | f6 | f6 | +| test.cpp:114:5:114:14 | declaration | Unreachable statement in function '$@'. | test.cpp:109:6:109:7 | f8 | f8 | +| test.cpp:119:5:119:14 | declaration | Unreachable statement in function '$@'. | test.cpp:109:6:109:7 | f8 | f8 | +| test.cpp:131:3:131:12 | declaration | Unreachable statement in function '$@'. | test.cpp:109:6:109:7 | f8 | f8 | +| test.cpp:135:18:136:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:134:6:134:7 | f9 | f9 | +| test.cpp:146:5:146:14 | declaration | Unreachable statement in function '$@'. | test.cpp:134:6:134:7 | f9 | f9 | +| test.cpp:158:3:134:7 | declaration | Unreachable statement in function '$@'. | test.cpp:134:6:134:7 | f9 | f9 | +| test.cpp:162:17:163:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:161:6:161:8 | f10 | f10 | +| test.cpp:173:5:173:14 | declaration | Unreachable statement in function '$@'. | test.cpp:161:6:161:8 | f10 | f10 | +| test.cpp:185:3:161:8 | declaration | Unreachable statement in function '$@'. | test.cpp:161:6:161:8 | f10 | f10 | +| test.cpp:192:3:190:8 | declaration | Unreachable statement in function '$@'. | test.cpp:190:6:190:8 | f11 | f11 | +| test.cpp:213:30:214:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:215:27:216:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:217:17:218:14 | | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:225:30:226:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:233:30:234:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:235:24:236:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:237:23:238:14 | { ... } | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | +| test.cpp:246:19:247:16 | | Unreachable statement in function '$@'. | test.cpp:200:6:200:8 | f12 | f12 | diff --git a/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.qlref b/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.qlref new file mode 100644 index 0000000000..f1e0afe023 --- /dev/null +++ b/cpp/misra/test/rules/RULE-0-0-1/UnreachableStatement.qlref @@ -0,0 +1 @@ +rules/RULE-0-0-1/UnreachableStatement.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-0-0-1/test.cpp b/cpp/misra/test/rules/RULE-0-0-1/test.cpp new file mode 100644 index 0000000000..923d3433a4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-0-0-1/test.cpp @@ -0,0 +1,250 @@ +void f1() { + int l1 = 0; // COMPLIANT -- reachable block +} + +void f2() { + return; + int l1 = 0; // NON-COMPLIANT +} + +void f3(int p1) { + // Reachable empty + if (p1) { + int l1 = 0; // COMPLIANT + } else { + int l2 = 0; // COMPLIANT + } + + if (false) { + int l3 = 0; // NON-COMPLIANT + } else { + int l4 = 0; // COMPLIANT + } + + if (true) { + int l5 = 0; // COMPLIANT + } else { + int l6 = 0; // NON-COMPLIANT + } + + // Rule text states tht both operands of && are considered reachable, and that + // blocks linked from edges of conditions are considered reachable if the + // condition is not a constant expression. + if (false && p1) { + int l7 = 0; // COMPLIANT + } else { + int l8 = 0; // COMPLIANT + } +} + +void f4(int p1) { + if (p1) { + return; + int l1 = 0; // NON-COMPLIANT + } + + int l2 = 0; // COMPLIANT + + if (p1) { + int l3 = 0; // COMPLIANT + } else { + return; + int l4 = 0; // NON-COMPLIANT + } + + int l5 = 0; // COMPLIANT + + if (p1) { + return; + } else { + return; + } + + int l6 = 0; // NON-COMPLIANT +} + +void f5() { + const bool b1 = true; + if (b1) { + int l1 = 0; // COMPLIANT + } else { + int l2 = 0; // NON-COMPLIANT + } + + constexpr bool b2 = false; + if (b2) { + int l3 = 0; // NON-COMPLIANT + } else { + int l4 = 0; // COMPLIANT + } + + if constexpr (b1) { + int l5 = 0; // COMPLIANT -- constexpr excluded from rule + } else { + int l6 = 0; // COMPLIANT -- constexpr excluded from rule + } +} + +template void f6() { + if (B) { + int l1 = 0; // NON-COMPLIANT -- reachability depends on template parameter + // value, a constant + } else { + int l2 = 0; // NON-COMPLIANT -- reachability depends on template parameter + // value, a constant + } + + if constexpr (B) { + int l3 = 0; // COMPLIANT -- constexpr excluded from rule + } else { + int l4 = 0; // COMPLIANT -- constexpr excluded from rule + } +} + +void f7() { + f6(); + f6(); +} + +void f8(int p1) { + switch (p1) { + case 1: { + int l1 = 0; // COMPLIANT + break; + int l2 = 0; // NON-COMPLIANT + } + case 2: { + int l3 = 0; // COMPLIANT + return; + int l4 = 0; // NON-COMPLIANT + } + } + + int l5 = 0; // COMPLIANT + + switch (p1) { + default: { + return; + } + } + + int l6 = 0; // NON-COMPLIANT +} + +void f9(int p1) { + for (; false;) { + int l1 = 0; // NON-COMPLIANT + } + + for (; p1;) { + int l2 = 0; // COMPLIANT + } + + for (; true;) { + int l3 = 0; // COMPLIANT + break; + int l4 = 0; // NON-COMPLIANT + } + + // Rule text states that both operands of && are considered reachable, and + // that blocks linked from edges of conditions are considered reachable if the + // condition is not a constant expression. + for (; false && p1;) { + int l5 = 0; // COMPLIANT + } + + for (; true;) + ; + int l6 = 0; // NON-COMPLIANT +} + +void f10(int p1) { + while (false) { + int l1 = 0; // NON-COMPLIANT + } + + while (p1) { + int l2 = 0; // COMPLIANT + } + + while (true) { + int l3 = 0; // COMPLIANT + break; + int l4 = 0; // NON-COMPLIANT + } + + // Rule text states that both operands of && are considered reachable, and + // that blocks linked from edges of conditions are considered reachable if the + // condition is not a constant expression. + while (false && p1) { + int l5 = 0; // COMPLIANT + } + + while (true) + ; + int l6 = 0; // NON-COMPLIANT +} + +[[noreturn]] void noret(); + +void f11() { + noret(); + int l1 = 0; // NON-COMPLIANT +} + +class Base {}; +class Derived : public Base {}; +void f_except(); +void f_no_except() noexcept; + +void f12() { + try { + f_except(); + } catch (const Derived &d) { + int l1 = 0; // COMPLIANT + } catch (const Base &b) { + int l2 = 0; // COMPLIANT + } catch (...) { + int l1 = 0; // COMPLIANT + } + + try { + f_no_except(); + } catch (const Derived &d) { + int l1 = 0; // NON-COMPLIANT + } catch (const Base &b) { + int l2 = 0; // NON-COMPLIANT + } catch (...) { + int l2 = 0; // NON-COMPLIANT + } + + try { + f_except(); + } catch (const Base &b) { + int l1 = 0; // COMPLIANT + } catch (const Derived &b) { + int l2 = 0; // NON-COMPLIANT + } + + try { + f_except(); + } catch (const Derived &d) { + int l1 = 0; // COMPLIANT + } catch (const Derived &b) { + int l2 = 0; // NON-COMPLIANT -- duplicate + } catch (Derived &b) { + int l2 = 0; // NON-COMPLIANT -- masked by previous catch + } catch (Derived b) { + int l2 = 0; // NON-COMPLIANT -- masked by previous catch + } + + try { + f_except(); + } catch (const Base &b) { + try { + f_no_except(); // COMPLIANT + } catch (...) { + int l1 = 0; // NON-COMPLIANT + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/DeadCode3.json b/rule_packages/cpp/DeadCode3.json new file mode 100644 index 0000000000..7212fbfa97 --- /dev/null +++ b/rule_packages/cpp/DeadCode3.json @@ -0,0 +1,25 @@ +{ + "MISRA-C++-2023": { + "RULE-0-0-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Dead code can indicate a logic error, potentially introduced during code edits, or it may be unnecessary code that can be deleted.", + "kind": "problem", + "name": "A function shall not contain unreachable statements", + "precision": "very-high", + "severity": "error", + "short_name": "UnreachableStatement", + "tags": [ + "maintainability", + "scope/single-translation-unit" + ] + } + ], + "title": "A function shall not contain unreachable statements" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index a2eb7eddd8..bf6c196efa 100644 --- a/rules.csv +++ b/rules.csv @@ -823,7 +823,7 @@ c,MISRA-C-2012,RULE-23-5,Yes,Advisory,,,A generic selection should not depend on c,MISRA-C-2012,RULE-23-6,Yes,Required,,,The controlling expression of a generic selection shall have an essential type that matches its standard type,,Generics,Medium, c,MISRA-C-2012,RULE-23-7,Yes,Advisory,,,A generic selection that is expanded from a macro should evaluate its argument only once,,Generics,Medium, c,MISRA-C-2012,RULE-23-8,Yes,Required,,,A default association shall appear as either the first or the last association of a generic selection,,Generics,Easy, -cpp,MISRA-C++-2023,RULE-0-0-1,Yes,Required,Decidable,Single Translation Unit,A function shall not contain unreachable statements,M0-1-1,DeadCode2,Medium, +cpp,MISRA-C++-2023,RULE-0-0-1,Yes,Required,Decidable,Single Translation Unit,A function shall not contain unreachable statements,M0-1-1,DeadCode3,Medium, cpp,MISRA-C++-2023,RULE-0-0-2,Yes,Advisory,Undecidable,System,Controlling expressions should not be invariant,M0-1-2,DeadCode2,Easy, cpp,MISRA-C++-2023,RULE-0-1-1,Yes,Advisory,Undecidable,System,A value should not be unnecessarily written to a local object,A0-1-1,DeadCode2,Medium, cpp,MISRA-C++-2023,RULE-0-1-2,Yes,Required,Decidable,Single Translation Unit,The value returned by a function shall be used,A0-1-2,DeadCode2,Easy,