|
17 | 17 | import cpp
|
18 | 18 | import codingstandards.cpp.autosar
|
19 | 19 | import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
| 20 | +import codingstandards.cpp.deadcode.UnreachableCode |
| 21 | +import semmle.code.cpp.controlflow.Guards |
20 | 22 |
|
21 | 23 | /**
|
22 | 24 | * A "conditional" node in the control flow graph, i.e. one that can potentially have a true and false path.
|
@@ -44,6 +46,7 @@ class BreakingLoop extends Loop {
|
44 | 46 | predicate hasCFGDeducedInfeasiblePath(
|
45 | 47 | ConditionalControlFlowNode cond, boolean infeasiblePath, string explanation
|
46 | 48 | ) {
|
| 49 | + not cond.isFromTemplateInstantiation(_) and |
47 | 50 | // No true successor, so the true path has already been deduced as infeasible
|
48 | 51 | not exists(cond.getATrueSuccessor()) and
|
49 | 52 | infeasiblePath = true and
|
@@ -147,17 +150,189 @@ predicate isConstantRelationalOperation(
|
147 | 150 | /**
|
148 | 151 | * Holds if the `ConditionalNode` has an infeasible `path` for the reason given in `explanation`.
|
149 | 152 | */
|
150 |
| -predicate hasInfeasiblePath( |
151 |
| - ConditionalControlFlowNode node, boolean infeasiblePath, string explanation |
152 |
| -) { |
153 |
| - hasCFGDeducedInfeasiblePath(node, infeasiblePath, explanation) and |
154 |
| - not isConstantRelationalOperation(node, infeasiblePath, _) |
| 153 | +predicate hasInfeasiblePath(ConditionalControlFlowNode node, string message) { |
| 154 | + //deal with the infeasible in all uninstantiated templates separately |
| 155 | + node.isFromUninstantiatedTemplate(_) and |
| 156 | + node instanceof ConditionControllingUnreachable and |
| 157 | + message = "The path is unreachable in a template." |
155 | 158 | or
|
156 |
| - isConstantRelationalOperation(node, infeasiblePath, explanation) |
| 159 | + exists(boolean infeasiblePath, string explanation | |
| 160 | + ( |
| 161 | + not node.isFromUninstantiatedTemplate(_) and |
| 162 | + not node.isFromTemplateInstantiation(_) and |
| 163 | + message = "The " + infeasiblePath + " path is infeasible because " + explanation + "." |
| 164 | + ) and |
| 165 | + ( |
| 166 | + hasCFGDeducedInfeasiblePath(node, infeasiblePath, explanation) and |
| 167 | + not isConstantRelationalOperation(node, infeasiblePath, _) |
| 168 | + or |
| 169 | + isConstantRelationalOperation(node, infeasiblePath, explanation) |
| 170 | + ) |
| 171 | + ) |
| 172 | +} |
| 173 | + |
| 174 | +/** |
| 175 | + * A newtype representing "unreachable" blocks in the program. We use a newtype here to avoid |
| 176 | + * reporting the same block in multiple `Function` instances created from one function in a template. |
| 177 | + */ |
| 178 | +private newtype TUnreachableBasicBlock = |
| 179 | + TUnreachableNonTemplateBlock(BasicBlock bb) { |
| 180 | + bb.isUnreachable() and |
| 181 | + // Exclude anything template related from this case |
| 182 | + not bb.getEnclosingFunction().isFromTemplateInstantiation(_) and |
| 183 | + not bb.getEnclosingFunction().isFromUninstantiatedTemplate(_) and |
| 184 | + // Exclude compiler generated basic blocks |
| 185 | + not isCompilerGenerated(bb) |
| 186 | + } or |
| 187 | + /** |
| 188 | + * A `BasicBlock` that occurs in at least one `Function` instance for a template. `BasicBlock`s |
| 189 | + * are matched up across templates by location. |
| 190 | + */ |
| 191 | + TUnreachableTemplateBlock( |
| 192 | + string filepath, int startline, int startcolumn, int endline, int endcolumn, |
| 193 | + GuardCondition uninstantiatedGuardCondition |
| 194 | + ) { |
| 195 | + exists(BasicBlock bb | |
| 196 | + // BasicBlock occurs in this location |
| 197 | + bb.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and |
| 198 | + // And is contained in the `uninstantiatedFunction` only |
| 199 | + // not from anything constructed from it |
| 200 | + // because we want infeasible paths independent of parameters |
| 201 | + exists(Function enclosing | enclosing = bb.getEnclosingFunction() | |
| 202 | + //guard is in the template function |
| 203 | + ( |
| 204 | + enclosing.getBlock().getAChild*() = uninstantiatedGuardCondition and |
| 205 | + //function template |
| 206 | + enclosing.isFromUninstantiatedTemplate(_) and |
| 207 | + uninstantiatedGuardCondition.isFromUninstantiatedTemplate(_) and |
| 208 | + //true condition is unreachable: basic block starts on same line as guard |
| 209 | + ( |
| 210 | + not exists(uninstantiatedGuardCondition.getATrueSuccessor()) and |
| 211 | + bb.hasLocationInfo(filepath, uninstantiatedGuardCondition.getLocation().getStartLine(), |
| 212 | + startcolumn, endline, endcolumn) |
| 213 | + or |
| 214 | + //false condition is unreachable: false basic block starts on one line after its true basic block |
| 215 | + not exists(uninstantiatedGuardCondition.getAFalseSuccessor()) and |
| 216 | + bb.hasLocationInfo(filepath, |
| 217 | + uninstantiatedGuardCondition.getATrueSuccessor().getLocation().getEndLine() + 1, |
| 218 | + startcolumn, endline, endcolumn) |
| 219 | + ) |
| 220 | + ) |
| 221 | + ) and |
| 222 | + // And is unreachable |
| 223 | + bb.isUnreachable() and |
| 224 | + // //Exclude compiler generated control flow nodes |
| 225 | + not isCompilerGenerated(bb) and |
| 226 | + //Exclude nodes affected by macros, because our find-the-same-basic-block-by-location doesn't |
| 227 | + //work in that case |
| 228 | + not bb.(ControlFlowNode).isAffectedByMacro() |
| 229 | + ) |
| 230 | + } |
| 231 | + |
| 232 | +/** |
| 233 | + * An unreachable basic block. |
| 234 | + */ |
| 235 | +class UnreachableBasicBlock extends TUnreachableBasicBlock { |
| 236 | + /** Gets a `BasicBlock` which is represented by this set of unreachable basic blocks. */ |
| 237 | + BasicBlock getABasicBlock() { none() } |
| 238 | + |
| 239 | + /** Gets a `GuardCondition` instance which we treat as the original GuardCondition. */ |
| 240 | + GuardCondition getGuardCondition() { none() } |
| 241 | + |
| 242 | + predicate hasLocationInfo( |
| 243 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 244 | + ) { |
| 245 | + none() |
| 246 | + } |
| 247 | + |
| 248 | + string toString() { result = "default" } |
| 249 | +} |
| 250 | + |
| 251 | +/** |
| 252 | + * A non-templated unreachable basic block. |
| 253 | + */ |
| 254 | +class UnreachableNonTemplateBlock extends UnreachableBasicBlock, TUnreachableNonTemplateBlock { |
| 255 | + BasicBlock getBasicBlock() { this = TUnreachableNonTemplateBlock(result) } |
| 256 | + |
| 257 | + override BasicBlock getABasicBlock() { result = getBasicBlock() } |
| 258 | + |
| 259 | + override GuardCondition getGuardCondition() { result.controls(getBasicBlock(), true) } |
| 260 | + |
| 261 | + override predicate hasLocationInfo( |
| 262 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 263 | + ) { |
| 264 | + getBasicBlock().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) |
| 265 | + } |
| 266 | + |
| 267 | + override string toString() { result = getBasicBlock().toString() } |
| 268 | +} |
| 269 | + |
| 270 | +/** |
| 271 | + * A templated unreachable basic block. |
| 272 | + */ |
| 273 | +class UnreachableTemplateBlock extends UnreachableBasicBlock, TUnreachableTemplateBlock { |
| 274 | + override BasicBlock getABasicBlock() { |
| 275 | + exists( |
| 276 | + string filepath, int startline, int startcolumn, int endline, int endcolumn, |
| 277 | + GuardCondition uninstantiatedGuardCondition |
| 278 | + | |
| 279 | + this = |
| 280 | + TUnreachableTemplateBlock(filepath, startline, startcolumn, endline, endcolumn, |
| 281 | + uninstantiatedGuardCondition) and |
| 282 | + result.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and |
| 283 | + exists(Function enclosing | |
| 284 | + //guard is in the template function |
| 285 | + ( |
| 286 | + enclosing.getBlock().getAChild*() = uninstantiatedGuardCondition and |
| 287 | + //function template |
| 288 | + enclosing.isFromUninstantiatedTemplate(_) and |
| 289 | + uninstantiatedGuardCondition.isFromUninstantiatedTemplate(_) and |
| 290 | + //true condition is unreachable: basic block starts on same line as guard |
| 291 | + ( |
| 292 | + not exists(uninstantiatedGuardCondition.getATrueSuccessor()) and |
| 293 | + this.hasLocationInfo(filepath, |
| 294 | + uninstantiatedGuardCondition.getLocation().getStartLine(), startcolumn, endline, |
| 295 | + endcolumn) |
| 296 | + or |
| 297 | + //false condition is unreachable: false basic block starts on one line after its true basic block |
| 298 | + not exists(uninstantiatedGuardCondition.getAFalseSuccessor()) and |
| 299 | + this.hasLocationInfo(filepath, |
| 300 | + uninstantiatedGuardCondition.getATrueSuccessor().getLocation().getEndLine() + 1, |
| 301 | + startcolumn, endline, endcolumn) |
| 302 | + ) |
| 303 | + ) |
| 304 | + ) |
| 305 | + | |
| 306 | + result.isUnreachable() and |
| 307 | + // Exclude compiler generated control flow nodes |
| 308 | + not isCompilerGenerated(result) and |
| 309 | + // Exclude nodes affected by macros, because our find-the-same-basic-block-by-location doesn't |
| 310 | + // work in that case |
| 311 | + not result.(ControlFlowNode).isAffectedByMacro() |
| 312 | + ) |
| 313 | + } |
| 314 | + |
| 315 | + override GuardCondition getGuardCondition() { |
| 316 | + this = TUnreachableTemplateBlock(_, _, _, _, _, result) |
| 317 | + } |
| 318 | + |
| 319 | + override predicate hasLocationInfo( |
| 320 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 321 | + ) { |
| 322 | + this = TUnreachableTemplateBlock(filepath, startline, startcolumn, endline, endcolumn, _) |
| 323 | + } |
| 324 | + |
| 325 | + override string toString() { result = getABasicBlock().toString() } |
| 326 | +} |
| 327 | + |
| 328 | +class ConditionControllingUnreachable extends GuardCondition { |
| 329 | + ConditionControllingUnreachable() { |
| 330 | + exists(UnreachableTemplateBlock b | this = b.getGuardCondition()) |
| 331 | + } |
157 | 332 | }
|
158 | 333 |
|
159 |
| -from ConditionalControlFlowNode cond, boolean infeasiblePath, string explanation |
| 334 | +from ConditionalControlFlowNode cond, string explanation |
160 | 335 | where
|
161 | 336 | not isExcluded(cond, DeadCodePackage::infeasiblePathQuery()) and
|
162 |
| - hasInfeasiblePath(cond, infeasiblePath, explanation) |
163 |
| -select cond, "The " + infeasiblePath + " path is infeasible because " + explanation + "." |
| 337 | + hasInfeasiblePath(cond, explanation) |
| 338 | +select cond, explanation |
0 commit comments