This commit is contained in:
Arthur Baars
2021-11-24 17:19:33 +01:00
parent 44a615839d
commit d17c055139
3 changed files with 363 additions and 1 deletions

View File

@@ -6,6 +6,7 @@
private import codeql.ruby.AST
private import codeql.ruby.ast.internal.AST
private import codeql.ruby.ast.internal.Control
private import codeql.ruby.controlflow.ControlFlowGraph
private import ControlFlowGraphImpl
private import NonReturning
@@ -100,7 +101,11 @@ abstract class Completion extends TCompletion {
or
n = any(RescueModifierExpr parent).getBody() and this = TRaiseCompletion()
or
mayRaise(n) and
(
mayRaise(n)
or
n instanceof CaseMatch and not exists(n.(CaseExpr).getElseBranch())
) and
this = TRaiseCompletion()
or
not n instanceof NonReturningCall and
@@ -172,6 +177,8 @@ private predicate inBooleanContext(AstNode n) {
or
n = any(ConditionalLoop parent).getCondition()
or
n = any(InClause parent).getCondition()
or
exists(LogicalAndExpr parent |
n = parent.getLeftOperand()
or
@@ -218,6 +225,14 @@ private predicate inMatchingContext(AstNode n) {
w.getPattern(_) = n
)
or
n instanceof CasePattern
or
n = any(ArrayPattern p).getClass()
or
n = any(FindPattern p).getClass()
or
n = any(HashPattern p).getClass()
or
n.(Trees::DefaultValueParameterTree).hasDefaultValue()
}

View File

@@ -419,6 +419,352 @@ module Trees {
}
}
private class CaseMatchTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseMatch {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getValue() or child = this.getABranch()
}
final override predicate last(AstNode last, Completion c) {
last(this.getABranch(), last, c) and
not c.(MatchingCompletion).getValue() = false
or
not exists(this.getElseBranch()) and
exists(Completion lc, Expr lastBranch |
lastBranch = max(int i | | this.getBranch(i) order by i) and
lc.(MatchingCompletion).getValue() = false and
last(lastBranch, last, lc) and
c.getInnerCompletion() = lc and
c instanceof RaiseCompletion
)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
first(this.getValue(), succ) and
c instanceof SimpleCompletion
or
last(this.getValue(), pred, c) and
first(this.getBranch(0), succ) and
c instanceof SimpleCompletion
or
exists(int i, Expr branch | branch = this.getBranch(i) |
last(branch, pred, c) and
first(this.getBranch(i + 1), succ) and
c.(MatchingCompletion).getValue() = false
)
}
}
private class PatternVariableAccessTree extends LocalVariableAccessTree, CasePattern {
final override predicate last(AstNode last, Completion c) {
super.last(last, c) and
c.(MatchingCompletion).getValue() = true
}
}
private class ArrayPatternTree extends ControlFlowTree, ArrayPattern {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getClass() or
child = this.getPrefixElement(_) or
child = this.getRestVariableAccess() or
child = this.getSuffixElement(_)
}
final override predicate first(AstNode first) {
first(this.getClass(), first)
or
not exists(this.getClass()) and first = this
}
final override predicate last(AstNode last, Completion c) {
c.(MatchingCompletion).getValue() = false and
(
last = this
or
exists(AstNode node |
node = this.getClass() or
node = this.getPrefixElement(_) or
node = this.getSuffixElement(_)
|
last(node, last, c)
)
)
or
c.(MatchingCompletion).getValue() = true and
last = this and
not exists(this.getPrefixElement(_)) and
not exists(this.getRestVariableAccess())
or
c.(MatchingCompletion).getValue() = true and
last(max(int i | | this.getPrefixElement(i) order by i), last, c) and
not exists(this.getRestVariableAccess())
or
last(this.getRestVariableAccess(), last, c) and
not exists(this.getSuffixElement(_))
or
c.(MatchingCompletion).getValue() = true and
last(max(int i | | this.getSuffixElement(i) order by i), last, c)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
last(this.getClass(), pred, c) and
succ = this and
c.(MatchingCompletion).getValue() = true
or
pred = this and
first(this.getPrefixElement(0), succ) and
c.(MatchingCompletion).getValue() = true
or
not exists(this.getPrefixElement(_)) and
pred = this and
first(this.getRestVariableAccess(), succ) and
c.(MatchingCompletion).getValue() = true
or
last(max(int i | | this.getPrefixElement(i) order by i), pred, c) and
first(this.getRestVariableAccess(), succ) and
c.(MatchingCompletion).getValue() = true
or
exists(int i |
last(this.getPrefixElement(i), pred, c) and
first(this.getPrefixElement(i + 1), succ) and
c.(MatchingCompletion).getValue() = true
)
or
last(this.getRestVariableAccess(), pred, c) and
first(this.getSuffixElement(0), succ) and
c instanceof SimpleCompletion
or
exists(int i |
last(this.getSuffixElement(i), pred, c) and
first(this.getSuffixElement(i + 1), succ) and
c.(MatchingCompletion).getValue() = true
)
}
}
private class FindPatternTree extends ControlFlowTree, FindPattern {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getClass() or
child = this.getPrefixVariableAccess() or
child = this.getElement(_) or
child = this.getSuffixVariableAccess()
}
final override predicate first(AstNode first) {
first(this.getClass(), first)
or
not exists(this.getClass()) and first = this
}
final override predicate last(AstNode last, Completion c) {
last(this.getSuffixVariableAccess(), last, c)
or
last(max(int i | | this.getElement(i) order by i), last, c) and
not exists(this.getSuffixVariableAccess())
or
c.(MatchingCompletion).getValue() = false and
(
last = this
or
exists(AstNode node | node = this.getClass() or node = this.getElement(_) |
last(node, last, c)
)
)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
last(this.getClass(), pred, c) and
succ = this and
c.(MatchingCompletion).getValue() = true
or
pred = this and
first(this.getPrefixVariableAccess(), succ) and
c.(MatchingCompletion).getValue() = true
or
pred = this and
first(this.getElement(0), succ) and
not exists(this.getPrefixVariableAccess()) and
c.(MatchingCompletion).getValue() = true
or
last(this.getPrefixVariableAccess(), pred, c) and
first(this.getElement(0), succ) and
c instanceof SimpleCompletion
or
c.(MatchingCompletion).getValue() = true and
exists(int i |
last(this.getElement(i), pred, c) and
first(this.getElement(i + 1), succ)
)
or
c.(MatchingCompletion).getValue() = true and
last(max(int i | | this.getElement(i) order by i), pred, c) and
first(this.getSuffixVariableAccess(), succ)
}
}
private class HashPatternTree extends ControlFlowTree, HashPattern {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getClass() or
child = this.getValue(_) or
child = this.getRestVariableAccess()
}
final override predicate first(AstNode first) {
first(this.getClass(), first)
or
not exists(this.getClass()) and first = this
}
final override predicate last(AstNode last, Completion c) {
c.(MatchingCompletion).getValue() = false and
(
last = this
or
exists(AstNode node |
node = this.getClass() or
node = this.getValue(_)
|
last(node, last, c)
)
)
or
c.(MatchingCompletion).getValue() = true and
last = this and
not exists(this.getValue(_)) and
not exists(this.getRestVariableAccess())
or
c.(MatchingCompletion).getValue() = true and
last(max(int i | | this.getValue(i) order by i), last, c) and
not exists(this.getRestVariableAccess())
or
last(this.getRestVariableAccess(), last, c)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
last(this.getClass(), pred, c) and
succ = this and
c.(MatchingCompletion).getValue() = true
or
pred = this and
first(this.getValue(0), succ) and
c.(MatchingCompletion).getValue() = true
or
not exists(this.getValue(_)) and
pred = this and
first(this.getRestVariableAccess(), succ) and
c.(MatchingCompletion).getValue() = true
or
last(max(int i | | this.getValue(i) order by i), pred, c) and
first(this.getRestVariableAccess(), succ) and
c.(MatchingCompletion).getValue() = true
or
exists(int i |
last(this.getValue(i), pred, c) and
first(this.getValue(i + 1), succ) and
c.(MatchingCompletion).getValue() = true
)
}
}
private class LineLiteralTree extends LeafTree, LineLiteral { }
private class FileLiteralTree extends LeafTree, FileLiteral { }
private class EncodingLiteralTree extends LeafTree, EncodingLiteral { }
private class AlternativePatternTree extends PreOrderTree, AlternativePattern {
final override predicate propagatesAbnormal(AstNode child) { child = this.getAnAlternative() }
final override predicate last(AstNode last, Completion c) {
last(this.getAnAlternative(), last, c) and
c.(MatchingCompletion).getValue() = true
or
last(max(int i | | this.getAlternative(i) order by i), last, c) and
c.(MatchingCompletion).getValue() = false
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
first(this.getAlternative(0), succ) and
c instanceof SimpleCompletion
or
exists(int i |
last(this.getAlternative(i), pred, c) and
first(this.getAlternative(i + 1), succ) and
c.(MatchingCompletion).getValue() = false
)
}
}
private class AsPatternTree extends StandardPreOrderTree, AsPattern {
override ControlFlowTree getChildElement(int i) {
result = this.getPattern() and i = 0
or
result = this.getVariableAccess() and i = 1
}
}
private class ParenthesizedPatternTree extends StandardPreOrderTree, ParenthesizedPattern {
override ControlFlowTree getChildElement(int i) { result = this.getPattern() and i = 0 }
}
private class VariableReferencePatternTree extends StandardPostOrderTree, VariableReferencePattern {
override ControlFlowTree getChildElement(int i) { result = this.getVariableAccess() and i = 0 }
}
private class InClauseTree extends PreOrderTree, InClause {
final override predicate propagatesAbnormal(AstNode child) {
child = this.getPattern() or
child = this.getCondition()
}
final override predicate last(AstNode last, Completion c) {
last(this.getPattern(), last, c) and
c.(MatchingCompletion).getValue() = false
or
exists(Completion pc |
last(this.getCondition(), last, pc) and
pc.(ConditionalCompletion).getValue() = false and
c.(MatchingCompletion).getValue() = false
)
or
last(this.getBody(), last, c)
or
not exists(this.getBody()) and last(this.getCondition(), last, c)
or
not exists(this.getBody()) and
not exists(this.getCondition()) and
last(this.getPattern(), last, c)
}
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
pred = this and
first(this.getPattern(), succ) and
c instanceof SimpleCompletion
or
exists(Expr next |
last(this.getPattern(), pred, c) and
c.(MatchingCompletion).getValue() = true and
first(next, succ)
|
next = this.getCondition()
or
not exists(this.getCondition()) and next = this.getBody()
)
or
exists(Completion pc, boolean flag |
flag = true and this.hasIfCondition()
or
flag = false and this.hasUnlessCondition()
|
last(this.getCondition(), pred, pc) and
pc.(ConditionalCompletion).getValue() = flag and
first(this.getBody(), succ) and
c.(MatchingCompletion).getValue() = true
)
}
}
private class CharacterTree extends LeafTree, CharacterLiteral { }
private class ClassDeclarationTree extends NamespaceTree, ClassDeclaration {

View File

@@ -176,6 +176,7 @@
| control/cases.rb:76:13:76:13 | :b | b |
| control/cases.rb:84:7:84:8 | 42 | 42 |
| control/cases.rb:87:6:87:6 | 5 | 5 |
| control/cases.rb:88:7:88:9 | foo | 42 |
| control/cases.rb:90:6:90:13 | "string" | string |
| control/cases.rb:91:9:91:11 | "foo" | foo |
| control/cases.rb:91:13:91:15 | "bar" | bar |