Julia crashes when DataFrames emits a setproperty! warning:
Julia 1.2.0 or 1.3-rc1 on Ubuntu 18.04, 64 bit, DataFrames v0.19.2.
julia> using DataFrames
julia> df = DataFrame(X = ['A', 'B', 'C'], Y = ["a|b", "a|c", "b|b"])
3Γ2 DataFrame
β Row β X β Y β
β β Char β String β
βββββββΌβββββββΌβββββββββ€
β 1 β 'A' β a|b β
β 2 β 'B' β a|c β
β 3 β 'C' β b|b β
julia> (df.Y1,df.Y2) = [(split.(df.Y, '|')[i][1], split.(df.Y, '|')[i][2]) for i in 1:size(df)[1]]
β Warning: `setproperty!(df::DataFrame, col_ind::Symbol, v)` is deprecated, use `df[!, col_ind] .= v` instead.
β caller = top-level scope at REPL[4]:1
β @ Core REPL[4]:1
Unreachable reached at 0x7f6947b6b339
signal (4): Illegal instruction
in expression starting at REPL[4]:1
ntuple at ./ntuple.jl:43
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2197
copy at ./broadcast.jl:1002 [inlined]
materialize at ./broadcast.jl:798 [inlined]
copyto! at /home/lobianco/.julia/packages/DataFrames/Iyo5L/src/other/broadcasting.jl:118
materialize! at ./broadcast.jl:801 [inlined]
setproperty! at ./deprecated.jl:67
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2197
do_call at /buildworker/worker/package_linux64/build/src/interpreter.c:323
eval_value at /buildworker/worker/package_linux64/build/src/interpreter.c:411
eval_stmt_value at /buildworker/worker/package_linux64/build/src/interpreter.c:362 [inlined]
eval_body at /buildworker/worker/package_linux64/build/src/interpreter.c:772
jl_interpret_toplevel_thunk_callback at /buildworker/worker/package_linux64/build/src/interpreter.c:884
unknown function (ip: 0xfffffffffffffffe)
unknown function (ip: 0x7f6941c3f98f)
unknown function (ip: 0xd)
jl_interpret_toplevel_thunk at /buildworker/worker/package_linux64/build/src/interpreter.c:893
jl_toplevel_eval_flex at /buildworker/worker/package_linux64/build/src/toplevel.c:815
jl_toplevel_eval_flex at /buildworker/worker/package_linux64/build/src/toplevel.c:764
jl_toplevel_eval_in at /buildworker/worker/package_linux64/build/src/toplevel.c:844
eval at ./boot.jl:330
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2191
eval_user_input at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.2/REPL/src/REPL.jl:86
macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.2/REPL/src/REPL.jl:118 [inlined]
#26 at ./task.jl:268
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2191
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1614 [inlined]
start_task at /buildworker/worker/package_linux64/build/src/task.c:596
unknown function (ip: 0xffffffffffffffff)
Allocations: 18028421 (Pool: 18025068; Big: 3353); GC: 39
Illegal instruction (core dumped)
FWIW, this happens even without the deprecation. My suspicion is that inference is that setproperty! is causing inference to turn on aggressive const prop, which then confuses it somewhere later down the road.
Actually, looks like potentially a bug with @inbounds in broadcast:
julia> f = eval(Expr(:new, getfield(Base.Broadcast, Symbol("##19#20")){Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple}, Tuple{Base.OneTo{Int64}}, typeof(Base.identity), Tuple{Tuple{String, String}}}}, Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple}, Tuple{Base.OneTo{Int64}}, typeof(Base.identity), Tuple{Tuple{String, String}}}(identity, (("a", "b"),), (Base.OneTo{Int64}(3),))))
#19 (generic function with 1 method)
julia> f(2)
"b"
julia> f(3)
MethodInstance for REPL.Terminals.TerminalBuffer(::Base.GenericIOBuffer{Array{UInt8,1}})
Reduced to the lack of error in this call:
julia> f(a) = a .= (1,2)
f (generic function with 1 method)
julia> f([1,2,3])
3-element Array{Int64,1}:
1
2
20
(try with Any to see segfaults, but this one might be easier for debugging).
FWIW, the debugger does a pretty good job here:
```jl
julia> using Debugger, DataFrames
julia> df = DataFrame(X = ['A', 'B', 'C'], Y = ["a|b", "a|c", "b|b"]);
julia> g() = (df.Y1,df.Y2) = [(split.(df.Y, '|')[i][1], split.(df.Y, '|')[i][2]) for i in 1:size(df)[1]];
julia> break_on(:error)
julia> @run g()
Warning: setproperty!(df::DataFrame, col_ind::Symbol, v) is deprecated, use df[!, col_ind] .= v instead.
β caller = ip:0x0
β @ Core :-1
Breaking for error:
ERROR: BoundsError: attempt to access ("a", "b")
at index [3]
Stacktrace:
[1] getindex(::Tuple{SubString{String},SubString{String}}, ::Int64) at tuple.jl:24
[2] _broadcast_getindex(::Tuple{SubString{String},SubString{String}}, ::Int64) at broadcast.jl:576
[3] _getindex(::Tuple{Tuple{SubString{String},SubString{String}}}, ::Int64) at broadcast.jl:622
[4] _broadcast_getindex(::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}, ::Int64) at broadcast.jl:597
[5] (::getfield(Base.Broadcast, Symbol("##19#20")){Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}})(::Int64) at broadcast.jl:1002
[6] ntuple(::getfield(Base.Broadcast, Symbol("##19#20")){Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}}, ::Val{3}) at ntuple.jl:43
[7] copy(::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}) at broadcast.jl:1002
[8] materialize(::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}) at broadcast.jl:798
[9] copyto!(::DataFrames.LazyNewColDataFrame{Symbol}, ::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Tuple{Base.OneTo{Int64}},typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}) at /Users/kristoffer/.julia/packages/DataFrames/Iyo5L/src/other/broadcasting.jl:118
[10] materialize!(::DataFrames.LazyNewColDataFrame{Symbol}, ::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(identity),Tuple{Tuple{SubString{String},SubString{String}}}}) at broadcast.jl:801
[11] setproperty!(::DataFrame, ::Symbol, ::Tuple{SubString{String},SubString{String}}) at deprecated.jl:67
In getindex(t, i) at tuple.jl:24
24 @eval getindex(@nospecialize(t::Tuple), i::Int) = getfield(t, i, $(Expr(:boundscheck)))
As does --check-bounds=yes. Interestingly I was using the debugger to try to figure out where we missed the check prior to that error and it was fairly unhelpful because the "missed branch" was hidden inside method dispatch. The trick was to change the test-case to the case that properly threw the error I wanted βΒ assigning from an array instead βΒ and then it became very obvious which method specialization was wrong. Of course it's impossible to meaningfully show all the methods that didn't get chosen.
Most helpful comment
Reduced to the lack of error in this call:
(try with
Anyto see segfaults, but this one might be easier for debugging).