Java: Count second level scopes for fieldFlowBranchLimit.

This commit is contained in:
Anders Schack-Mulligen
2024-04-10 14:57:51 +02:00
parent 2f0987e980
commit 3c69f8f607
2 changed files with 76 additions and 1 deletions

View File

@@ -20,6 +20,8 @@ module JavaDataFlow implements InputSig<Location> {
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
predicate getSecondLevelScope = Private::getSecondLevelScope/1;
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;

View File

@@ -581,7 +581,80 @@ predicate knownSourceModel(Node source, string model) { sourceNode(source, _, mo
predicate knownSinkModel(Node sink, string model) { sinkNode(sink, _, model) }
class DataFlowSecondLevelScope = Unit;
private predicate isTopLevel(Stmt s) {
any(Callable c).getBody() = s
or
exists(BlockStmt b | s = b.getAStmt() and isTopLevel(b))
}
private Stmt getAChainedBranch(IfStmt s) {
result = s.getThen()
or
exists(Stmt elseBranch | s.getElse() = elseBranch |
result = getAChainedBranch(elseBranch)
or
result = elseBranch and not elseBranch instanceof IfStmt
)
}
private newtype TDataFlowSecondLevelScope =
TTopLevelIfBranch(Stmt s) {
exists(IfStmt ifstmt | s = getAChainedBranch(ifstmt) and isTopLevel(ifstmt))
} or
TTopLevelSwitchCase(SwitchCase s) {
exists(SwitchStmt switchstmt | s = switchstmt.getACase() and isTopLevel(switchstmt))
}
private SwitchCase getPrecedingCase(Stmt s) {
result = s
or
exists(SwitchStmt switch, int i |
s = switch.getStmt(i) and
not s instanceof SwitchCase and
result = getPrecedingCase(switch.getStmt(i - 1))
)
}
/**
* A second-level control-flow scope in a `switch` or a chained `if` statement.
*
* This is a `switch` case or a branch of a chained `if` statement, given that
* the `switch` or `if` statement is top level, that is, it is not nested inside
* other CFG constructs.
*/
class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
/** Gets a textual representation of this element. */
string toString() {
exists(Stmt s | this = TTopLevelIfBranch(s) | result = s.toString())
or
exists(SwitchCase s | this = TTopLevelSwitchCase(s) | result = s.toString())
}
/**
* Gets a statement directly contained in this scope. For an `if` branch, this
* is the branch itself, and for a `switch case`, this is one the statements
* of that case branch.
*/
private Stmt getAStmt() {
exists(Stmt s | this = TTopLevelIfBranch(s) | result = s)
or
exists(SwitchCase s | this = TTopLevelSwitchCase(s) |
result = s.getRuleStatement() or
s = getPrecedingCase(result)
)
}
/** Gets a data-flow node nested within this scope. */
Node getANode() { getRelatedExpr(result).getAnEnclosingStmt() = this.getAStmt() }
}
private Expr getRelatedExpr(Node n) {
n.asExpr() = result or
n.(PostUpdateNode).getPreUpdateNode().asExpr() = result
}
/** Gets the second-level scope containing the node `n`, if any. */
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a