Skip to content

Commit 1ed6a9f

Browse files
authored
Try giving some more informative errors for various malformed input (#54458)
I was playing with generating some code for OpaqueClosures. It's pretty easy to generate IR that will pass the verifier, but cause assertion errors in codegen. This tries to make the experience slightly nicer by turning some of them into proper error messages (thus letting the runtime discover, so that e.g. the code can be inspected at the REPL) rather than assertions.
1 parent cd41d6f commit 1ed6a9f

File tree

7 files changed

+52
-14
lines changed

7 files changed

+52
-14
lines changed

src/codegen.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5252,8 +5252,12 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR
52525252
Value *r = emit_jlcall(ctx, jlinvoke_func, boxed(ctx, lival), argv, nargs, julia_call2);
52535253
result = mark_julia_type(ctx, r, true, rt);
52545254
}
5255-
if (result.typ == jl_bottom_type)
5255+
if (result.typ == jl_bottom_type) {
5256+
#ifndef JL_NDEBUG
5257+
emit_error(ctx, "(Internal Error - IR Validity): Returned from function we expected not to.");
5258+
#endif
52565259
CreateTrap(ctx.builder);
5260+
}
52575261
return result;
52585262
}
52595263

@@ -6524,7 +6528,12 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
65246528

65256529
SmallVector<jl_value_t *, 0> env_component_ts(nargs-4);
65266530
for (size_t i = 0; i < nargs - 4; ++i) {
6527-
env_component_ts[i] = argv[4+i].typ;
6531+
jl_value_t *typ = argv[4+i].typ;
6532+
if (typ == jl_bottom_type) {
6533+
JL_GC_POP();
6534+
return jl_cgval_t();
6535+
}
6536+
env_component_ts[i] = typ;
65286537
}
65296538

65306539
env_t = jl_apply_tuple_type_v(env_component_ts.data(), nargs-4);
@@ -9751,9 +9760,6 @@ jl_llvm_functions_t jl_emit_code(
97519760
jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception(jl_current_task));
97529761
jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
97539762
jlbacktrace(); // written to STDERR_FILENO
9754-
#ifndef JL_NDEBUG
9755-
abort();
9756-
#endif
97579763
}
97589764

97599765
return decls;

src/interpreter.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,13 @@ jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *oc, jl_value_t **ar
805805
assert(jl_is_method_instance(specializations));
806806
jl_method_instance_t *mi = (jl_method_instance_t *)specializations;
807807
jl_code_instance_t *ci = jl_atomic_load_relaxed(&mi->cache);
808-
code = jl_uncompress_ir(source, ci, jl_atomic_load_relaxed(&ci->inferred));
808+
jl_value_t *src = jl_atomic_load_relaxed(&ci->inferred);
809+
if (!src) {
810+
// This can happen if somebody did :new_opaque_closure with broken IR. This is definitely bad
811+
// and UB, but let's try to be slightly nicer than segfaulting here for people debugging.
812+
jl_error("Internal Error: Opaque closure with no source at all");
813+
}
814+
code = jl_uncompress_ir(source, ci, src);
809815
}
810816
interpreter_state *s;
811817
unsigned nroots = jl_source_nslots(code) + jl_source_nssavalues(code) + 2;

src/opaque_closure.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,15 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t
5050
JL_GC_PUSH2(&sigtype, &selected_rt);
5151
sigtype = jl_argtype_with_function(captures, (jl_value_t*)argt);
5252

53-
jl_method_instance_t *mi = jl_specializations_get_linfo(source, sigtype, jl_emptysvec);
53+
jl_method_instance_t *mi = NULL;
54+
if (source->source) {
55+
mi = jl_specializations_get_linfo(source, sigtype, jl_emptysvec);
56+
} else {
57+
mi = (jl_method_instance_t *)jl_atomic_load_relaxed(&source->specializations);
58+
if (!jl_subtype(sigtype, mi->specTypes)) {
59+
jl_error("sigtype mismatch in optimized opaque closure");
60+
}
61+
}
5462
jl_task_t *ct = jl_current_task;
5563
size_t world = ct->world_age;
5664
jl_code_instance_t *ci = NULL;
@@ -147,7 +155,8 @@ JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info(jl_tuplet
147155
jl_atomic_store_release(&meth->deleted_world, world);
148156

149157
if (isinferred) {
150-
sigtype = jl_argtype_with_function(env, (jl_value_t*)argt);
158+
jl_value_t *argslotty = jl_array_ptr_ref(ci->slottypes, 0);
159+
sigtype = jl_argtype_with_function_type(argslotty, (jl_value_t*)argt);
151160
jl_method_instance_t *mi = jl_specializations_get_linfo((jl_method_t*)root, sigtype, jl_emptysvec);
152161
inst = jl_new_codeinst(mi, jl_nothing, rt_ub, (jl_value_t*)jl_any_type, NULL, (jl_value_t*)ci,
153162
0, world, world, 0, 0, jl_nothing, 0, ci->debuginfo);

stdlib/InteractiveUtils/test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ end
748748
@testset "code_llvm on opaque_closure" begin
749749
let ci = code_typed(+, (Int, Int))[1][1]
750750
ir = Core.Compiler.inflate_ir(ci)
751+
ir.argtypes[1] = Tuple{}
751752
@test ir.debuginfo.def === nothing
752753
ir.debuginfo.def = Symbol(@__FILE__)
753754
oc = Core.OpaqueClosure(ir)

test/compiler/AbstractInterpreter.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,30 @@ CC.method_table(interp::OverlaySinInterp) = CC.OverlayMethodTable(CC.get_inferen
163163
overlay_sin1(x) = error("Not supposed to be called.")
164164
@overlay OverlaySinMT overlay_sin1(x) = cos(x)
165165
@overlay OverlaySinMT Base.sin(x::Union{Float32,Float64}) = overlay_sin1(x)
166-
let oc = Base.code_ircode(; interp=OverlaySinInterp()) do
166+
let ir = Base.code_ircode(; interp=OverlaySinInterp()) do
167167
sin(0.)
168-
end |> only |> first |> Core.OpaqueClosure
168+
end |> only |> first
169+
ir.argtypes[1] = Tuple{}
170+
oc = Core.OpaqueClosure(ir)
169171
@test oc() == cos(0.)
170172
end
171173
@overlay OverlaySinMT Base.sin(x::Union{Float32,Float64}) = @noinline overlay_sin1(x)
172-
let oc = Base.code_ircode(; interp=OverlaySinInterp()) do
174+
let ir = Base.code_ircode(; interp=OverlaySinInterp()) do
173175
sin(0.)
174-
end |> only |> first |> Core.OpaqueClosure
176+
end |> only |> first
177+
ir.argtypes[1] = Tuple{}
178+
oc = Core.OpaqueClosure(ir)
175179
@test oc() == cos(0.)
176180
end
177181
_overlay_sin2(x) = error("Not supposed to be called.")
178182
@overlay OverlaySinMT _overlay_sin2(x) = cos(x)
179183
overlay_sin2(x) = _overlay_sin2(x)
180184
@overlay OverlaySinMT Base.sin(x::Union{Float32,Float64}) = @noinline overlay_sin2(x)
181-
let oc = Base.code_ircode(; interp=OverlaySinInterp()) do
185+
let ir = Base.code_ircode(; interp=OverlaySinInterp()) do
182186
sin(0.)
183-
end |> only |> first |> Core.OpaqueClosure
187+
end |> only |> first
188+
ir.argtypes[1] = Tuple{}
189+
oc = Core.OpaqueClosure(ir)
184190
@test oc() == cos(0.)
185191
end
186192

test/compiler/inline.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,7 @@ issue52644(::UnionAll) = :UnionAll
22002200
let ir = Base.code_ircode((Issue52644,); optimize_until="Inlining") do t
22012201
issue52644(t.tuple)
22022202
end |> only |> first
2203+
ir.argtypes[1] = Tuple{}
22032204
irfunc = Core.OpaqueClosure(ir)
22042205
@test irfunc(Issue52644(Tuple{})) === :DataType
22052206
@test irfunc(Issue52644(Tuple{<:Integer})) === :UnionAll
@@ -2208,6 +2209,7 @@ issue52644_single(x::DataType) = :DataType
22082209
let ir = Base.code_ircode((Issue52644,); optimize_until="Inlining") do t
22092210
issue52644_single(t.tuple)
22102211
end |> only |> first
2212+
ir.argtypes[1] = Tuple{}
22112213
irfunc = Core.OpaqueClosure(ir)
22122214
@test irfunc(Issue52644(Tuple{})) === :DataType
22132215
@test_throws MethodError irfunc(Issue52644(Tuple{<:Integer}))

test/opaque_closure.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ end
253253
# constructing an opaque closure from IRCode
254254
let src = first(only(code_typed(+, (Int, Int))))
255255
ir = Core.Compiler.inflate_ir(src, Core.Compiler.VarState[], src.slottypes)
256+
ir.argtypes[1] = Tuple{}
256257
@test ir.debuginfo.def === nothing
257258
ir.debuginfo.def = Symbol(@__FILE__)
258259
@test OpaqueClosure(src; sig=Tuple{Int, Int}, rettype=Int, nargs=2)(40, 2) == 42
@@ -263,10 +264,12 @@ let src = first(only(code_typed(+, (Int, Int))))
263264
@test OpaqueClosure(ir)(40, 2) == 42 # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
264265
end
265266
let ir = first(only(Base.code_ircode(sin, (Int,))))
267+
ir.argtypes[1] = Tuple{}
266268
@test OpaqueClosure(ir)(42) == sin(42)
267269
@test OpaqueClosure(ir)(42) == sin(42) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
268270
@test length(code_typed(OpaqueClosure(ir))) == 1
269271
ir = first(only(Base.code_ircode(sin, (Float64,))))
272+
ir.argtypes[1] = Tuple{}
270273
@test OpaqueClosure(ir)(42.) == sin(42.)
271274
@test OpaqueClosure(ir)(42.) == sin(42.) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
272275
end
@@ -275,6 +278,7 @@ end
275278
let src = code_typed((Int,Int)) do x, y...
276279
return (x, y)
277280
end |> only |> first
281+
src.slottypes[1] = Tuple{}
278282
let oc = OpaqueClosure(src; rettype=Tuple{Int, Tuple{Int}}, sig=Tuple{Int, Int}, nargs=2, isva=true)
279283
@test oc(1,2) === (1,(2,))
280284
@test_throws MethodError oc(1,2,3)
@@ -315,6 +319,7 @@ f_oc_throws() = error("oops")
315319
@noinline function make_oc_and_collect_bt()
316320
did_gc = Ref{Bool}(false)
317321
bt = let ir = first(only(Base.code_ircode(f_oc_throws, ())))
322+
ir.argtypes[1] = Tuple
318323
sentinel = Ref{Any}(nothing)
319324
oc = OpaqueClosure(ir, sentinel)
320325
finalizer(sentinel) do x
@@ -351,6 +356,7 @@ ccall_op_arg_restrict2_bad_args() = op_arg_restrict2((1.,), 2)
351356
let ir = Base.code_ircode((Int,Int)) do x, y
352357
@noinline x * y
353358
end |> only |> first
359+
ir.argtypes[1] = Tuple{}
354360
oc = Core.OpaqueClosure(ir)
355361
io = IOBuffer()
356362
code_llvm(io, oc, Tuple{Int,Int})
@@ -364,11 +370,13 @@ foopaque() = Base.Experimental.@opaque(@noinline x::Int->println(x))(1)
364370
code_llvm(devnull,foopaque,()) #shouldn't crash
365371

366372
let ir = first(only(Base.code_ircode(sin, (Int,))))
373+
ir.argtypes[1] = Tuple{}
367374
oc = Core.OpaqueClosure(ir)
368375
@test (Base.show_method(IOBuffer(), oc.source::Method); true)
369376
end
370377

371378
let ir = first(only(Base.code_ircode(sin, (Int,))))
379+
ir.argtypes[1] = Tuple{}
372380
oc = Core.OpaqueClosure(ir; do_compile=false)
373381
@test oc(1) == sin(1)
374382
end

0 commit comments

Comments
 (0)