Skip to content
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

Canonicalize IR to disallow throwing GlobalRef in value position #36450

Merged
merged 1 commit into from
Jun 29, 2020
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
2 changes: 2 additions & 0 deletions base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ function fixemup!(cond, rename, ir::IRCode, ci::CodeInfo, idx::Int, @nospecializ
return nothing
end
op[] = x
elseif isa(val, GlobalRef) && !isdefined(val.mod, val.name)
op[] = NewSSAValue(insert_node!(ir, idx, Any, val).id - length(ir.stmts))
end
end
return urs[]
Expand Down
18 changes: 12 additions & 6 deletions base/compiler/ssair/verify.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

if !isdefined(@__MODULE__, Symbol("@verify_error"))
macro verify_error(arg)
arg isa String && return esc(:(println(stderr, $arg)))
arg isa String && return esc(:(print && println(stderr, $arg)))
(arg isa Expr && arg.head === :string) || error("verify_error macro expected a string expression")
pushfirst!(arg.args, GlobalRef(Core, :stderr))
pushfirst!(arg.args, :println)
Expand All @@ -11,7 +11,7 @@ if !isdefined(@__MODULE__, Symbol("@verify_error"))
end
end

function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, use_idx::Int)
function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, use_idx::Int, print::Bool)
if isa(op, SSAValue)
if op.id > length(ir.stmts)
def_bb = block_for_inst(ir.cfg, ir.new_nodes[op.id - length(ir.stmts)].pos)
Expand All @@ -35,6 +35,11 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
error()
end
end
elseif isa(op, GlobalRef)
if !isdefined(op.mod, op.name)
@verify_error "Unbound GlobalRef not allowed in value position"
error()
end
elseif isa(op, Union{OldSSAValue, NewSSAValue})
#@Base.show ir
@verify_error "Left over SSA marker"
Expand All @@ -55,7 +60,7 @@ function count_int(val::Int, arr::Vector{Int})
n
end

function verify_ir(ir::IRCode)
function verify_ir(ir::IRCode, print::Bool=true)
# For now require compact IR
# @assert isempty(ir.new_nodes)
# Verify CFG
Expand Down Expand Up @@ -169,7 +174,7 @@ function verify_ir(ir::IRCode)
@verify_error "GlobalRefs and Exprs are not allowed as PhiNode values"
error()
end
check_op(ir, domtree, val, edge, last(ir.cfg.blocks[stmt.edges[i]].stmts)+1)
check_op(ir, domtree, val, edge, last(ir.cfg.blocks[stmt.edges[i]].stmts)+1, print)
end
elseif isa(stmt, PhiCNode)
for i = 1:length(stmt.values)
Expand Down Expand Up @@ -206,17 +211,18 @@ function verify_ir(ir::IRCode)
end
for op in userefs(stmt)
op = op[]
check_op(ir, domtree, op, bb, idx)
check_op(ir, domtree, op, bb, idx, print)
end
end
end
end

function verify_linetable(linetable::Vector{LineInfoNode})
function verify_linetable(linetable::Vector{LineInfoNode}, print::Bool=true)
for i in 1:length(linetable)
line = linetable[i]
if i <= line.inlined_at
@verify_error "Misordered linetable"
error()
end
end
end
28 changes: 22 additions & 6 deletions test/compiler/ssair.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,14 @@ let ci = (Meta.@lower 1 + 1).args[1]
Core.PhiNode(),
Core.Compiler.ReturnNode(),
# block 4
Expr(:call,
GlobalRef(Main, :something),
GlobalRef(Main, :somethingelse)),
Core.Compiler.GotoIfNot(Core.SSAValue(6), 9),
GlobalRef(Main, :something),
GlobalRef(Main, :somethingelse),
Expr(:call, Core.SSAValue(6), Core.SSAValue(7)),
Core.Compiler.GotoIfNot(Core.SSAValue(8), 11),
# block 5
Core.Compiler.ReturnNode(Core.SSAValue(6)),
Core.Compiler.ReturnNode(Core.SSAValue(8)),
# block 6
Core.Compiler.ReturnNode(Core.SSAValue(6))
Core.Compiler.ReturnNode(Core.SSAValue(8))
]
nstmts = length(ci.code)
ci.ssavaluetypes = nstmts
Expand All @@ -164,3 +164,19 @@ let ci = (Meta.@lower 1 + 1).args[1]
ir = Core.Compiler.compact!(ir, true)
@test Core.Compiler.verify_ir(ir) == nothing
end

# Test that GlobalRef in value position is non-canonical
using Base.Meta
let ci = (Meta.@lower 1 + 1).args[1]
ci.code = [
Expr(:call, GlobalRef(Main, :something_not_defined_please))
ReturnNode(SSAValue(1))
]
nstmts = length(ci.code)
ci.ssavaluetypes = nstmts
ci.codelocs = fill(Int32(1), nstmts)
ci.ssaflags = fill(Int32(0), nstmts)
ir = Core.Compiler.inflate_ir(ci)
ir = Core.Compiler.compact!(ir, true)
@test_throws ErrorException Core.Compiler.verify_ir(ir, false)
end