-
Notifications
You must be signed in to change notification settings - Fork 71
Implement Rule 0-0-1, unreachable statements from DeadCode package #1001
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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())) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -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:158:3:134:7 | declaration | Unreachable statement in function '$@'. | test.cpp:134:6:134:7 | f9 | f9 | | |
| | test.cpp:158:3:158:12 | declaration | Unreachable statement in function '$@'. | test.cpp:134:6:134:7 | f9 | f9 | |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The location range for this expected result is incorrect. The first line number should be '185' (the line of the unreachable statement) but instead it says '185:3:161:8' where the end location incorrectly references line 161 and column 8, which appears to be the function name location instead of the statement's end location. It should be '185:3:185:12' to correctly span the declaration on line 185.
| | test.cpp:185:3:161:8 | declaration | Unreachable statement in function '$@'. | test.cpp:161:6:161:8 | f10 | f10 | | |
| | test.cpp:185:3:185:12 | declaration | Unreachable statement in function '$@'. | test.cpp:161:6:161:8 | f10 | f10 | |
Copilot
AI
Dec 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The location range for this expected result is incorrect. The first line number should be '192' (the line of the unreachable statement) but instead it says '192:3:190:8' where the end location incorrectly references line 190 and column 8, which appears to be the function name location instead of the statement's end location. It should be '192:3:192:12' to correctly span the declaration on line 192.
| | test.cpp:192:3:190:8 | declaration | Unreachable statement in function '$@'. | test.cpp:190:6:190:8 | f11 | f11 | | |
| | test.cpp:192:3:192:12 | declaration | Unreachable statement in function '$@'. | test.cpp:190:6:190:8 | f11 | f11 | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rules/RULE-0-0-1/UnreachableStatement.ql |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in filename: 'CathcBlockShadowingCert.ql' should be 'CatchBlockShadowingCert.ql' (missing 't' in 'Catch').