Description
openedon Oct 3, 2022
Reduced from FunctionWrappers example to the code below.
f(a) = a .+ 1
const AT = Union{Vector{Int},Vector{Float64}}
function gen_fptr(::Type{T}) where {T}
@cfunction(f, Ref{AT}, (Ref{AT},))
end
fptr = gen_fptr(Int)
# @show fptr
# ccall(:jl_breakpoint, Cvoid, (Ptr{Cvoid},), fptr)
ccall(fptr, Ref{AT}, (Ref{AT},), [1])
println(1)
GC.gc()
ccall(fptr, Ref{AT}, (Ref{AT},), [1])
The first ccall should complete without much issue but the GC call causes the second ccall to refer to a dangling pointer which may either throw a non-sense type error or just crash while trying to throw that error.
During codegen of gen_fptr
. emit_cfunction
added a UnionAll
wrapper on the return type Ref{AT}
. This got passed down to the emit_typecheck
call in gen_cfunc_wrapper
without any further processing. This type then bypasses the union type check optimization in emit_isa
, which should only be a performance issue and not a correctness one, before finally get embedded in the code without being rooted anywhere.
It seems that some optimizations could be added to hide this issue. However, I assume it's the callers responsibility to root the argument to emit_typecheck
/emit_isa
. In fact, emit_cfunction
does root rt
but never the wrapped declrt
.