Skip to content

Commit 8221b50

Browse files
committed
Try giving some more informative errors for various malformed input
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 5f7bfc0 commit 8221b50

File tree

6 files changed

+51
-14
lines changed

6 files changed

+51
-14
lines changed

src/codegen.cpp

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

@@ -6523,7 +6527,12 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
65236527

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

65296538
env_t = jl_apply_tuple_type_v(env_component_ts.data(), nargs-4);
@@ -9754,9 +9763,6 @@ jl_llvm_functions_t jl_emit_code(
97549763
jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception(jl_current_task));
97559764
jl_printf((JL_STREAM*)STDERR_FILENO, "\n");
97569765
jlbacktrace(); // written to STDERR_FILENO
9757-
#ifndef JL_NDEBUG
9758-
abort();
9759-
#endif
97609766
}
97619767

97629768
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);

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
@@ -251,6 +251,7 @@ end
251251
# constructing an opaque closure from IRCode
252252
let src = first(only(code_typed(+, (Int, Int))))
253253
ir = Core.Compiler.inflate_ir(src, Core.Compiler.VarState[], src.slottypes)
254+
ir.argtypes[1] = Tuple{}
254255
@test ir.debuginfo.def === nothing
255256
ir.debuginfo.def = Symbol(@__FILE__)
256257
@test OpaqueClosure(src; sig=Tuple{Int, Int}, rettype=Int, nargs=2)(40, 2) == 42
@@ -261,10 +262,12 @@ let src = first(only(code_typed(+, (Int, Int))))
261262
@test OpaqueClosure(ir)(40, 2) == 42 # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
262263
end
263264
let ir = first(only(Base.code_ircode(sin, (Int,))))
265+
ir.argtypes[1] = Tuple{}
264266
@test OpaqueClosure(ir)(42) == sin(42)
265267
@test OpaqueClosure(ir)(42) == sin(42) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
266268
@test length(code_typed(OpaqueClosure(ir))) == 1
267269
ir = first(only(Base.code_ircode(sin, (Float64,))))
270+
ir.argtypes[1] = Tuple{}
268271
@test OpaqueClosure(ir)(42.) == sin(42.)
269272
@test OpaqueClosure(ir)(42.) == sin(42.) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
270273
end
@@ -273,6 +276,7 @@ end
273276
let src = code_typed((Int,Int)) do x, y...
274277
return (x, y)
275278
end |> only |> first
279+
src.slottypes[1] = Tuple{}
276280
let oc = OpaqueClosure(src; rettype=Tuple{Int, Tuple{Int}}, sig=Tuple{Int, Int}, nargs=2, isva=true)
277281
@test oc(1,2) === (1,(2,))
278282
@test_throws MethodError oc(1,2,3)
@@ -313,6 +317,7 @@ f_oc_throws() = error("oops")
313317
@noinline function make_oc_and_collect_bt()
314318
did_gc = Ref{Bool}(false)
315319
bt = let ir = first(only(Base.code_ircode(f_oc_throws, ())))
320+
ir.argtypes[1] = Tuple
316321
sentinel = Ref{Any}(nothing)
317322
oc = OpaqueClosure(ir, sentinel)
318323
finalizer(sentinel) do x
@@ -349,6 +354,7 @@ ccall_op_arg_restrict2_bad_args() = op_arg_restrict2((1.,), 2)
349354
let ir = Base.code_ircode((Int,Int)) do x, y
350355
@noinline x * y
351356
end |> only |> first
357+
ir.argtypes[1] = Tuple{}
352358
oc = Core.OpaqueClosure(ir)
353359
io = IOBuffer()
354360
code_llvm(io, oc, Tuple{Int,Int})
@@ -362,11 +368,13 @@ foopaque() = Base.Experimental.@opaque(@noinline x::Int->println(x))(1)
362368
code_llvm(devnull,foopaque,()) #shouldn't crash
363369

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

369376
let ir = first(only(Base.code_ircode(sin, (Int,))))
377+
ir.argtypes[1] = Tuple{}
370378
oc = Core.OpaqueClosure(ir; do_compile=false)
371379
@test oc(1) == sin(1)
372380
end

0 commit comments

Comments
 (0)