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

Segfault when defining show for types #22363

Closed
quinnj opened this issue Jun 14, 2017 · 11 comments
Closed

Segfault when defining show for types #22363

quinnj opened this issue Jun 14, 2017 · 11 comments

Comments

@quinnj
Copy link
Member

quinnj commented Jun 14, 2017

Here's the minimum repro

   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.7.0-DEV.511 (2017-06-08 21:22 UTC)
 _/ |\__'_|_|_|\__'_|  |  (HEAD detached at origin/jb/namedtuples)/e2c2724982* (fork: 6 commits, 5 days)
|__/                   |  x86_64-apple-darwin16.6.0

julia> struct Null end

julia> Base.show(io::IO, ::Type{Union{T, Null}}) where {T} = print(io, "?$T")

julia> struct WeakRefString{T} <: AbstractString
           ptr::Ptr{T}
           len::Int # of code units
           ind::Int # used to keep track of a string data index
       end

julia> Base.show(io::IO, ::Type{WeakRefString{T}}) where {T} = print(io, "WeakRefString{$T}")

julia> temp = []
Segmentation fault: 11
jq-mbp:julia jacobquinn$

Note the last thing that happens is it's trying to display 0-element Array{Any,1}.

@martinholters
Copy link
Member

I see a StackOverflowError for the slightly simpler

julia> struct Null end

julia> Base.show(io::IO, ::Type{Union{T, Null}}) where {T} = print(io, "?$T")

julia> struct WeakRefString{T} end

julia> Base.show(io::IO, ::Type{WeakRefString{T}}) where {T} = print(io, "WeakRefString{$T}")

julia> temp = []

The backtrace repeats this snippet:

unknown function (ip: 0x7fe856fd2fd6)
jl_call_fptr_internal at src/julia_internal.h:350 [inlined]
jl_call_method_internal at src/julia_internal.h:369 [inlined]
jl_apply_generic at src/gf.c:1925
print at ./strings/io.jl:29
unknown function (ip: 0x7fe875794eff)
jl_call_fptr_internal at src/julia_internal.h:350 [inlined]
jl_call_method_internal at src/julia_internal.h:369 [inlined]
jl_apply_generic at src/gf.c:1925
#print_to_string#232 at ./strings/io.jl:102
show at ./REPL[2]:1

@JeffBezanson
Copy link
Sponsor Member

Note Any == Union{Any,Void}.

@JeffBezanson
Copy link
Sponsor Member

I think the best way to make this work --- even though I never condone defining show for particular types, which goes beyond "type piracy" and into "type treason" --- is to actually overwrite the method show(io::IO, x::Union) and look for Null inside the Union.

@quinnj
Copy link
Member Author

quinnj commented Jun 14, 2017

The other alternative that seems to work is by also defining Base.show(io::IO, ::Type{Any}) = print(io, "Any"), which I guess goes from "type treason" to "type high treason", right? 😄

It also seems like this would be a great use-case for being able to specify "only-the-strict-subtypes-of-T" as a subtype relation; not sure if that's ever been brought up before or is possible at all, but seems like that would be a workable solution here.

@martinholters
Copy link
Member

But why does it need the second show method to crash?

@JeffBezanson
Copy link
Sponsor Member

Very valid question @martinholters !

@nalimilan
Copy link
Member

Just found this, which might be related: #13306

@martinholters
Copy link
Member

Something isn't invalidated correctly:

julia> struct Null end

julia> struct WeakRefString{T} end

julia> methods(show, Tuple{IO,Type{Any}})
# 1 method for generic function "show":
[1] show(io::IO, x::DataType) in Base at show.jl:211

julia> foo() = show(Any)
foo (generic function with 1 method)

julia> foo()
Any
julia> Base.show(io::IO, ::Type{Union{T, Null}}) where {T} = print(io, "?$T")

julia> methods(show, Tuple{IO,Type{Any}})
# 1 method for generic function "show":
[1] show(io::IO, ::Type{Union{Null, T}}) where T in Main at REPL[6]:1

julia> foo()
Any
julia> show(Any)
?Any

So foo() hasn't been recompiled. And neither have the innards of the "?$T". Defining the second show method at least triggers recompilation of the latter:

julia> Base.show(io::IO, ::Type{WeakRefString{T}}) where {T} = print(io, "WeakRefString{$T}")

julia> foo()
Any
julia> show(Any)
ERROR: StackOverflowError:
[...]

@martinholters
Copy link
Member

Further reduced a bit:

julia> foo(::DataType) = 1
foo (generic function with 1 method)

julia> bar() = foo(Any)
bar (generic function with 1 method)

julia> bar()
1

julia> foo(::Type{Union{T,Void}}) where {T} = 2
foo (generic function with 2 methods)

julia> foo(Any)
2

julia> bar()
1

@AzamatB
Copy link
Contributor

AzamatB commented Oct 9, 2019

bump

@vtjnash
Copy link
Sponsor Member

vtjnash commented Mar 16, 2021

This appears to be fixed now, though I will reiterate Jeff's warning not to define show for particular types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants