Skip to content

Commit d17c055

Browse files
committed
CFG
1 parent 44a6158 commit d17c055

File tree

3 files changed

+363
-1
lines changed

3 files changed

+363
-1
lines changed

ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
private import codeql.ruby.AST
88
private import codeql.ruby.ast.internal.AST
9+
private import codeql.ruby.ast.internal.Control
910
private import codeql.ruby.controlflow.ControlFlowGraph
1011
private import ControlFlowGraphImpl
1112
private import NonReturning
@@ -100,7 +101,11 @@ abstract class Completion extends TCompletion {
100101
or
101102
n = any(RescueModifierExpr parent).getBody() and this = TRaiseCompletion()
102103
or
103-
mayRaise(n) and
104+
(
105+
mayRaise(n)
106+
or
107+
n instanceof CaseMatch and not exists(n.(CaseExpr).getElseBranch())
108+
) and
104109
this = TRaiseCompletion()
105110
or
106111
not n instanceof NonReturningCall and
@@ -172,6 +177,8 @@ private predicate inBooleanContext(AstNode n) {
172177
or
173178
n = any(ConditionalLoop parent).getCondition()
174179
or
180+
n = any(InClause parent).getCondition()
181+
or
175182
exists(LogicalAndExpr parent |
176183
n = parent.getLeftOperand()
177184
or
@@ -218,6 +225,14 @@ private predicate inMatchingContext(AstNode n) {
218225
w.getPattern(_) = n
219226
)
220227
or
228+
n instanceof CasePattern
229+
or
230+
n = any(ArrayPattern p).getClass()
231+
or
232+
n = any(FindPattern p).getClass()
233+
or
234+
n = any(HashPattern p).getClass()
235+
or
221236
n.(Trees::DefaultValueParameterTree).hasDefaultValue()
222237
}
223238

ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,352 @@ module Trees {
419419
}
420420
}
421421

422+
private class CaseMatchTree extends PreOrderTree, CaseExpr, ASTInternal::TCaseMatch {
423+
final override predicate propagatesAbnormal(AstNode child) {
424+
child = this.getValue() or child = this.getABranch()
425+
}
426+
427+
final override predicate last(AstNode last, Completion c) {
428+
last(this.getABranch(), last, c) and
429+
not c.(MatchingCompletion).getValue() = false
430+
or
431+
not exists(this.getElseBranch()) and
432+
exists(Completion lc, Expr lastBranch |
433+
lastBranch = max(int i | | this.getBranch(i) order by i) and
434+
lc.(MatchingCompletion).getValue() = false and
435+
last(lastBranch, last, lc) and
436+
c.getInnerCompletion() = lc and
437+
c instanceof RaiseCompletion
438+
)
439+
}
440+
441+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
442+
pred = this and
443+
first(this.getValue(), succ) and
444+
c instanceof SimpleCompletion
445+
or
446+
last(this.getValue(), pred, c) and
447+
first(this.getBranch(0), succ) and
448+
c instanceof SimpleCompletion
449+
or
450+
exists(int i, Expr branch | branch = this.getBranch(i) |
451+
last(branch, pred, c) and
452+
first(this.getBranch(i + 1), succ) and
453+
c.(MatchingCompletion).getValue() = false
454+
)
455+
}
456+
}
457+
458+
private class PatternVariableAccessTree extends LocalVariableAccessTree, CasePattern {
459+
final override predicate last(AstNode last, Completion c) {
460+
super.last(last, c) and
461+
c.(MatchingCompletion).getValue() = true
462+
}
463+
}
464+
465+
private class ArrayPatternTree extends ControlFlowTree, ArrayPattern {
466+
final override predicate propagatesAbnormal(AstNode child) {
467+
child = this.getClass() or
468+
child = this.getPrefixElement(_) or
469+
child = this.getRestVariableAccess() or
470+
child = this.getSuffixElement(_)
471+
}
472+
473+
final override predicate first(AstNode first) {
474+
first(this.getClass(), first)
475+
or
476+
not exists(this.getClass()) and first = this
477+
}
478+
479+
final override predicate last(AstNode last, Completion c) {
480+
c.(MatchingCompletion).getValue() = false and
481+
(
482+
last = this
483+
or
484+
exists(AstNode node |
485+
node = this.getClass() or
486+
node = this.getPrefixElement(_) or
487+
node = this.getSuffixElement(_)
488+
|
489+
last(node, last, c)
490+
)
491+
)
492+
or
493+
c.(MatchingCompletion).getValue() = true and
494+
last = this and
495+
not exists(this.getPrefixElement(_)) and
496+
not exists(this.getRestVariableAccess())
497+
or
498+
c.(MatchingCompletion).getValue() = true and
499+
last(max(int i | | this.getPrefixElement(i) order by i), last, c) and
500+
not exists(this.getRestVariableAccess())
501+
or
502+
last(this.getRestVariableAccess(), last, c) and
503+
not exists(this.getSuffixElement(_))
504+
or
505+
c.(MatchingCompletion).getValue() = true and
506+
last(max(int i | | this.getSuffixElement(i) order by i), last, c)
507+
}
508+
509+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
510+
last(this.getClass(), pred, c) and
511+
succ = this and
512+
c.(MatchingCompletion).getValue() = true
513+
or
514+
pred = this and
515+
first(this.getPrefixElement(0), succ) and
516+
c.(MatchingCompletion).getValue() = true
517+
or
518+
not exists(this.getPrefixElement(_)) and
519+
pred = this and
520+
first(this.getRestVariableAccess(), succ) and
521+
c.(MatchingCompletion).getValue() = true
522+
or
523+
last(max(int i | | this.getPrefixElement(i) order by i), pred, c) and
524+
first(this.getRestVariableAccess(), succ) and
525+
c.(MatchingCompletion).getValue() = true
526+
or
527+
exists(int i |
528+
last(this.getPrefixElement(i), pred, c) and
529+
first(this.getPrefixElement(i + 1), succ) and
530+
c.(MatchingCompletion).getValue() = true
531+
)
532+
or
533+
last(this.getRestVariableAccess(), pred, c) and
534+
first(this.getSuffixElement(0), succ) and
535+
c instanceof SimpleCompletion
536+
or
537+
exists(int i |
538+
last(this.getSuffixElement(i), pred, c) and
539+
first(this.getSuffixElement(i + 1), succ) and
540+
c.(MatchingCompletion).getValue() = true
541+
)
542+
}
543+
}
544+
545+
private class FindPatternTree extends ControlFlowTree, FindPattern {
546+
final override predicate propagatesAbnormal(AstNode child) {
547+
child = this.getClass() or
548+
child = this.getPrefixVariableAccess() or
549+
child = this.getElement(_) or
550+
child = this.getSuffixVariableAccess()
551+
}
552+
553+
final override predicate first(AstNode first) {
554+
first(this.getClass(), first)
555+
or
556+
not exists(this.getClass()) and first = this
557+
}
558+
559+
final override predicate last(AstNode last, Completion c) {
560+
last(this.getSuffixVariableAccess(), last, c)
561+
or
562+
last(max(int i | | this.getElement(i) order by i), last, c) and
563+
not exists(this.getSuffixVariableAccess())
564+
or
565+
c.(MatchingCompletion).getValue() = false and
566+
(
567+
last = this
568+
or
569+
exists(AstNode node | node = this.getClass() or node = this.getElement(_) |
570+
last(node, last, c)
571+
)
572+
)
573+
}
574+
575+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
576+
last(this.getClass(), pred, c) and
577+
succ = this and
578+
c.(MatchingCompletion).getValue() = true
579+
or
580+
pred = this and
581+
first(this.getPrefixVariableAccess(), succ) and
582+
c.(MatchingCompletion).getValue() = true
583+
or
584+
pred = this and
585+
first(this.getElement(0), succ) and
586+
not exists(this.getPrefixVariableAccess()) and
587+
c.(MatchingCompletion).getValue() = true
588+
or
589+
last(this.getPrefixVariableAccess(), pred, c) and
590+
first(this.getElement(0), succ) and
591+
c instanceof SimpleCompletion
592+
or
593+
c.(MatchingCompletion).getValue() = true and
594+
exists(int i |
595+
last(this.getElement(i), pred, c) and
596+
first(this.getElement(i + 1), succ)
597+
)
598+
or
599+
c.(MatchingCompletion).getValue() = true and
600+
last(max(int i | | this.getElement(i) order by i), pred, c) and
601+
first(this.getSuffixVariableAccess(), succ)
602+
}
603+
}
604+
605+
private class HashPatternTree extends ControlFlowTree, HashPattern {
606+
final override predicate propagatesAbnormal(AstNode child) {
607+
child = this.getClass() or
608+
child = this.getValue(_) or
609+
child = this.getRestVariableAccess()
610+
}
611+
612+
final override predicate first(AstNode first) {
613+
first(this.getClass(), first)
614+
or
615+
not exists(this.getClass()) and first = this
616+
}
617+
618+
final override predicate last(AstNode last, Completion c) {
619+
c.(MatchingCompletion).getValue() = false and
620+
(
621+
last = this
622+
or
623+
exists(AstNode node |
624+
node = this.getClass() or
625+
node = this.getValue(_)
626+
|
627+
last(node, last, c)
628+
)
629+
)
630+
or
631+
c.(MatchingCompletion).getValue() = true and
632+
last = this and
633+
not exists(this.getValue(_)) and
634+
not exists(this.getRestVariableAccess())
635+
or
636+
c.(MatchingCompletion).getValue() = true and
637+
last(max(int i | | this.getValue(i) order by i), last, c) and
638+
not exists(this.getRestVariableAccess())
639+
or
640+
last(this.getRestVariableAccess(), last, c)
641+
}
642+
643+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
644+
last(this.getClass(), pred, c) and
645+
succ = this and
646+
c.(MatchingCompletion).getValue() = true
647+
or
648+
pred = this and
649+
first(this.getValue(0), succ) and
650+
c.(MatchingCompletion).getValue() = true
651+
or
652+
not exists(this.getValue(_)) and
653+
pred = this and
654+
first(this.getRestVariableAccess(), succ) and
655+
c.(MatchingCompletion).getValue() = true
656+
or
657+
last(max(int i | | this.getValue(i) order by i), pred, c) and
658+
first(this.getRestVariableAccess(), succ) and
659+
c.(MatchingCompletion).getValue() = true
660+
or
661+
exists(int i |
662+
last(this.getValue(i), pred, c) and
663+
first(this.getValue(i + 1), succ) and
664+
c.(MatchingCompletion).getValue() = true
665+
)
666+
}
667+
}
668+
669+
private class LineLiteralTree extends LeafTree, LineLiteral { }
670+
671+
private class FileLiteralTree extends LeafTree, FileLiteral { }
672+
673+
private class EncodingLiteralTree extends LeafTree, EncodingLiteral { }
674+
675+
private class AlternativePatternTree extends PreOrderTree, AlternativePattern {
676+
final override predicate propagatesAbnormal(AstNode child) { child = this.getAnAlternative() }
677+
678+
final override predicate last(AstNode last, Completion c) {
679+
last(this.getAnAlternative(), last, c) and
680+
c.(MatchingCompletion).getValue() = true
681+
or
682+
last(max(int i | | this.getAlternative(i) order by i), last, c) and
683+
c.(MatchingCompletion).getValue() = false
684+
}
685+
686+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
687+
pred = this and
688+
first(this.getAlternative(0), succ) and
689+
c instanceof SimpleCompletion
690+
or
691+
exists(int i |
692+
last(this.getAlternative(i), pred, c) and
693+
first(this.getAlternative(i + 1), succ) and
694+
c.(MatchingCompletion).getValue() = false
695+
)
696+
}
697+
}
698+
699+
private class AsPatternTree extends StandardPreOrderTree, AsPattern {
700+
override ControlFlowTree getChildElement(int i) {
701+
result = this.getPattern() and i = 0
702+
or
703+
result = this.getVariableAccess() and i = 1
704+
}
705+
}
706+
707+
private class ParenthesizedPatternTree extends StandardPreOrderTree, ParenthesizedPattern {
708+
override ControlFlowTree getChildElement(int i) { result = this.getPattern() and i = 0 }
709+
}
710+
711+
private class VariableReferencePatternTree extends StandardPostOrderTree, VariableReferencePattern {
712+
override ControlFlowTree getChildElement(int i) { result = this.getVariableAccess() and i = 0 }
713+
}
714+
715+
private class InClauseTree extends PreOrderTree, InClause {
716+
final override predicate propagatesAbnormal(AstNode child) {
717+
child = this.getPattern() or
718+
child = this.getCondition()
719+
}
720+
721+
final override predicate last(AstNode last, Completion c) {
722+
last(this.getPattern(), last, c) and
723+
c.(MatchingCompletion).getValue() = false
724+
or
725+
exists(Completion pc |
726+
last(this.getCondition(), last, pc) and
727+
pc.(ConditionalCompletion).getValue() = false and
728+
c.(MatchingCompletion).getValue() = false
729+
)
730+
or
731+
last(this.getBody(), last, c)
732+
or
733+
not exists(this.getBody()) and last(this.getCondition(), last, c)
734+
or
735+
not exists(this.getBody()) and
736+
not exists(this.getCondition()) and
737+
last(this.getPattern(), last, c)
738+
}
739+
740+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
741+
pred = this and
742+
first(this.getPattern(), succ) and
743+
c instanceof SimpleCompletion
744+
or
745+
exists(Expr next |
746+
last(this.getPattern(), pred, c) and
747+
c.(MatchingCompletion).getValue() = true and
748+
first(next, succ)
749+
|
750+
next = this.getCondition()
751+
or
752+
not exists(this.getCondition()) and next = this.getBody()
753+
)
754+
or
755+
exists(Completion pc, boolean flag |
756+
flag = true and this.hasIfCondition()
757+
or
758+
flag = false and this.hasUnlessCondition()
759+
|
760+
last(this.getCondition(), pred, pc) and
761+
pc.(ConditionalCompletion).getValue() = flag and
762+
first(this.getBody(), succ) and
763+
c.(MatchingCompletion).getValue() = true
764+
)
765+
}
766+
}
767+
422768
private class CharacterTree extends LeafTree, CharacterLiteral { }
423769

424770
private class ClassDeclarationTree extends NamespaceTree, ClassDeclaration {

0 commit comments

Comments
 (0)