Skip to content

Ruby: Fix CFG for nodes that may raise #16122

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

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions ruby/ql/lib/codeql/ruby/controlflow/internal/Completion.qll
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ private predicate mayRaise(Call c) { c = getARescuableBodyChild() }

/** A completion of a statement or an expression. */
abstract class Completion extends TCompletion {
private predicate isValidForSpecific(AstNode n) {
exists(AstNode other | n = other.getDesugared() and this.isValidForSpecific(other))
or
private predicate isValidForSpecific0(AstNode n) {
this = n.(NonReturningCall).getACompletion()
or
completionIsValidForStmt(n, this)
Expand All @@ -110,12 +108,19 @@ abstract class Completion extends TCompletion {
or
n = any(RescueModifierExpr parent).getBody() and
this = [TSimpleCompletion().(TCompletion), TRaiseCompletion()]
}

private predicate isValidForSpecific(AstNode n) {
this.isValidForSpecific0(n)
or
exists(AstNode other | n = other.getDesugared() and this.isValidForSpecific(other))
or
mayRaise(n) and
(
this = TRaiseCompletion()
or
this = TSimpleCompletion() and not n instanceof NonReturningCall
not any(Completion c).isValidForSpecific0(n) and
this = TSimpleCompletion()
)
}

Expand Down
99 changes: 82 additions & 17 deletions ruby/ql/test/library-tests/controlflow/graph/Cfg.expected
Original file line number Diff line number Diff line change
Expand Up @@ -2397,18 +2397,9 @@ cfg.rb:
# 90| ...
#-----| -> $global

# 90| ... = ...
#-----| -> if ...

# 90| ... = ...
#-----| -> x

# 90| [false] ! ...
#-----| false -> if ...

# 90| [true] ! ...
#-----| true -> x

# 90| __synth__0__1
#-----| -> x

Expand All @@ -2418,10 +2409,6 @@ cfg.rb:
# 90| call to each
#-----| -> ...

# 90| defined? ...
#-----| false -> [true] ! ...
#-----| true -> [false] ! ...

# 90| enter { ... }
#-----| -> __synth__0__1

Expand All @@ -2430,6 +2417,22 @@ cfg.rb:
# 90| exit { ... } (normal)
#-----| -> exit { ... }

# 90| { ... }
#-----| -> call to each

# 90| ... = ...
#-----| -> if ...

# 90| [false] ! ...
#-----| false -> if ...

# 90| [true] ! ...
#-----| true -> x

# 90| defined? ...
#-----| false -> [true] ! ...
#-----| true -> [false] ! ...

# 90| if ...
#-----| -> Array

Expand All @@ -2442,9 +2445,6 @@ cfg.rb:
# 90| x
#-----| -> defined? ...

# 90| { ... }
#-----| -> call to each

# 90| x
#-----| -> __synth__0__1

Expand Down Expand Up @@ -6915,7 +6915,7 @@ raise.rb:
#-----| -> exit m

# 167| m
#-----| -> exit raise.rb (normal)
#-----| -> m16

# 167| self
#-----| -> m
Expand All @@ -6928,3 +6928,68 @@ raise.rb:

# 168| ""
#-----| -> call to raise

# 172| enter m16
#-----| -> b1

# 172| exit m16

# 172| exit m16 (abnormal)
#-----| -> exit m16

# 172| exit m16 (normal)
#-----| -> exit m16

# 172| m16
#-----| -> exit raise.rb (normal)

# 172| b1
#-----| -> b2

# 172| b2
#-----| -> b1

# 174| b1
#-----| true -> [true] ... || ...
#-----| false -> b2

# 174| [false] ... || ...
#-----| false -> 2
#-----| raise -> ExceptionA

# 174| [true] ... || ...
#-----| true -> 1
#-----| raise -> ExceptionA

# 174| b2
#-----| -> true

# 174| ... == ...
#-----| false -> [false] ... || ...
#-----| true -> [true] ... || ...
#-----| raise -> ExceptionA

# 174| true
#-----| -> ... == ...

# 175| return
#-----| return -> exit m16 (normal)

# 175| 1
#-----| -> return

# 177| return
#-----| return -> exit m16 (normal)

# 177| 2
#-----| -> return

# 179| ExceptionA
#-----| raise -> exit m16 (abnormal)
#-----| match -> 3

# 180| return
#-----| return -> exit m16 (normal)

# 180| 3
#-----| -> return
3 changes: 3 additions & 0 deletions ruby/ql/test/library-tests/controlflow/graph/Nodes.expected
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ positionalArguments
| raise.rb:160:5:162:7 | call to bar | raise.rb:160:9:162:7 | -> { ... } |
| raise.rb:161:7:161:14 | call to raise | raise.rb:161:13:161:14 | "" |
| raise.rb:168:5:168:12 | call to raise | raise.rb:168:11:168:12 | "" |
| raise.rb:174:8:174:23 | [false] ... \|\| ... | raise.rb:174:14:174:23 | ... == ... |
| raise.rb:174:8:174:23 | [true] ... \|\| ... | raise.rb:174:14:174:23 | ... == ... |
| raise.rb:174:14:174:23 | ... == ... | raise.rb:174:20:174:23 | true |
keywordArguments
| cfg.html.erb:6:9:6:58 | call to stylesheet_link_tag | media | cfg.html.erb:6:54:6:58 | "all" |
| cfg.html.erb:12:11:12:33 | call to link_to | id | cfg.html.erb:12:31:12:33 | "a" |
Expand Down
2 changes: 1 addition & 1 deletion ruby/ql/test/library-tests/controlflow/graph/ifs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ def disjunct (b1, b2)
if (b1 || b2) then
puts "b1 or b2"
end
end
end
12 changes: 12 additions & 0 deletions ruby/ql/test/library-tests/controlflow/graph/raise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,15 @@ def self.m()
raise ""
end
end

def m16(b1, b2)
begin
if b1 || b2 == true
return 1
else
return 2
end
rescue ExceptionA
return 3
end
end