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

fatal and strange: errors when overwriting Base.<, Base.==, etc. for Int64,Float64,etc. using @eval in v0.6.0 #23605

Closed
turtleslow opened this issue Sep 6, 2017 · 11 comments

Comments

@turtleslow
Copy link

Reproduces 100% of the time for me [fatal]:

               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0 (2017-06-19 13:05 UTC)
 _/ |\__'_|_|_|\__'_|  |  
|__/                   |  x86_64-suse-linux

julia> versioninfo()
Julia Version 0.6.0
Commit 903644385b* (2017-06-19 13:05 UTC)
Platform Info:
  OS: Linux (x86_64-suse-linux)
  CPU: Intel(R) Core(TM) i5-3470T CPU @ 2.90GHz
  WORD_SIZE: 64
  BLAS: libopenblas (DYNAMIC_ARCH Sandybridge)
  LAPACK: libopenblas_openmp.so.0
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, ivybridge)

julia> op = :<
:<

julia> @eval Base.$op(x1::Int64,x2::Int64) = "boom ... crash"

fatal: error thrown and no exception handler available.
TypeError(func=:display_error, context="select_value", expected=Bool, got="boom ... crash")
rec_backtrace at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/stackwalk.c:84
record_backtrace at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/task.c:245
jl_throw at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/task.c:564
jl_type_error_rt at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/rtutils.c:118
_length at ./abstractarray.jl:132 [inlined]
isempty at ./abstractarray.jl:830 [inlined]
display_error at ./client.jl:125
unknown function (ip: 0x7fe05046ad5d)
jl_call_fptr_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:358 [inlined]
jl_apply_generic at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/gf.c:1933
display_error at ./client.jl:140
unknown function (ip: 0x7fe05046ac16)
jl_call_fptr_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:358 [inlined]
jl_apply_generic at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/gf.c:1933
do_call at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/interpreter.c:75
eval at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/interpreter.c:242
eval_body at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/interpreter.c:539
jl_toplevel_eval_body at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/interpreter.c:511
jl_toplevel_eval_flex at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/toplevel.c:571
jl_toplevel_eval_in at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/builtins.c:496
eval at ./boot.jl:235
unknown function (ip: 0x7fe06cc7e4ff)
jl_call_fptr_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:358 [inlined]
jl_apply_generic at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/gf.c:1933
_start at ./client.jl:417
unknown function (ip: 0x7fe06ccc2c08)
jl_call_fptr_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/julia_internal.h:358 [inlined]
jl_apply_generic at /home/abuild/rpmbuild/BUILD/julia-0.6.0/src/gf.c:1933
unknown function (ip: 0x401b58)
unknown function (ip: 0x4015d2)
__libc_start_main at /lib64/libc.so.6 (unknown line)
unknown function (ip: 0x401689)
TypeError
atexit hook threw an error: TypeError(func=:uv_write, context="if", expected=Bool, got="boom ... crash")

This is also 100% reproducible, but you must type each line after line 2 to get the same output [strange]:

               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0 (2017-06-19 13:05 UTC)
 _/ |\__'_|_|_|\__'_|  |  
|__/                   |  x86_64-suse-linux

julia> op = :<
:<

julia> @eval Base.$op(x1::Float64,x2::Float64) = "no crash"
WARNING: Method definition <(Float64, Float64) in module Base at float.jl:432 overwritten in module Main at REPL[2]:1.

julia> "why do my strings"
ERROR (in the keymap): TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] convert(::Type{Int64}, ::Float64) at ./float.jl:676
 [2] Base.Libc.TmStruct(::Float64) at ./libc.jl:158
 [3] add_history(::Base.REPL.REPLHistoryProvider, ::Base.LineEdit.PromptState) at ./REPL.jl:404
 [4] add_history(::Base.LineEdit.PromptState) at ./LineEdit.jl:596
 [5] commit_line(::Base.LineEdit.MIState) at ./LineEdit.jl:1306
 [6] (::Base.LineEdit.##92#122)(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL, ::Vararg{Any,N} where N) at ./LineEdit.jl:1357
 [7] (::Base.LineEdit.##13#14{Base.LineEdit.##92#122,String})(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL) at ./LineEdit.jl:740
 [8] prompt!(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./LineEdit.jl:1618
 [9] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1578
 [10] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:945
 [11] run_repl(::Base.REPL.LineEditREPL, ::Base.##507#508) at ./REPL.jl:180
 [12] _start() at ./client.jl:413
julia> 
julia> "result in errors?"
ERROR (in the keymap): TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] convert(::Type{Int64}, ::Float64) at ./float.jl:676
 [2] Base.Libc.TmStruct(::Float64) at ./libc.jl:158
 [3] add_history(::Base.REPL.REPLHistoryProvider, ::Base.LineEdit.PromptState) at ./REPL.jl:404
 [4] add_history(::Base.LineEdit.PromptState) at ./LineEdit.jl:596
 [5] commit_line(::Base.LineEdit.MIState) at ./LineEdit.jl:1306
 [6] (::Base.LineEdit.##92#122)(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL, ::Vararg{Any,N} where N) at ./LineEdit.jl:1357
 [7] (::Base.LineEdit.##13#14{Base.LineEdit.##92#122,String})(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL) at ./LineEdit.jl:740
 [8] prompt!(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./LineEdit.jl:1618
 [9] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1578
 [10] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:945
 [11] run_repl(::Base.REPL.LineEditREPL, ::Base.##507#508) at ./REPL.jl:180
 [12] _start() at ./client.jl:413
julia> 
julia> @eval Base.$op(x1::Int64,x2::Int64) = "no crash"
ERROR (in the keymap): TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] convert(::Type{Int64}, ::Float64) at ./float.jl:676
 [2] Base.Libc.TmStruct(::Float64) at ./libc.jl:158
 [3] add_history(::Base.REPL.REPLHistoryProvider, ::Base.LineEdit.PromptState) at ./REPL.jl:404
 [4] add_history(::Base.LineEdit.PromptState) at ./LineEdit.jl:596
 [5] commit_line(::Base.LineEdit.MIState) at ./LineEdit.jl:1306
 [6] (::Base.LineEdit.##92#122)(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL, ::Vararg{Any,N} where N) at ./LineEdit.jl:1357
 [7] (::Base.LineEdit.##13#14{Base.LineEdit.##92#122,String})(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL) at ./LineEdit.jl:740
 [8] prompt!(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./LineEdit.jl:1618
 [9] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1578
 [10] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:945
 [11] run_repl(::Base.REPL.LineEditREPL, ::Base.##507#508) at ./REPL.jl:180
 [12] _start() at ./client.jl:413
julia> 
julia> "...exit() twice now before you can leave ..."
ERROR (in the keymap): TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] convert(::Type{Int64}, ::Float64) at ./float.jl:676
 [2] Base.Libc.TmStruct(::Float64) at ./libc.jl:158
 [3] add_history(::Base.REPL.REPLHistoryProvider, ::Base.LineEdit.PromptState) at ./REPL.jl:404
 [4] add_history(::Base.LineEdit.PromptState) at ./LineEdit.jl:596
 [5] commit_line(::Base.LineEdit.MIState) at ./LineEdit.jl:1306
 [6] (::Base.LineEdit.##92#122)(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL, ::Vararg{Any,N} where N) at ./LineEdit.jl:1357
 [7] (::Base.LineEdit.##13#14{Base.LineEdit.##92#122,String})(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL) at ./LineEdit.jl:740
 [8] prompt!(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./LineEdit.jl:1618
 [9] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1578
 [10] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:945
 [11] run_repl(::Base.REPL.LineEditREPL, ::Base.##507#508) at ./REPL.jl:180
 [12] _start() at ./client.jl:413
julia> 
julia> exit()
ERROR (in the keymap): TypeError: non-boolean (String) used in boolean context
Stacktrace:
 [1] convert(::Type{Int64}, ::Float64) at ./float.jl:676
 [2] Base.Libc.TmStruct(::Float64) at ./libc.jl:158
 [3] add_history(::Base.REPL.REPLHistoryProvider, ::Base.LineEdit.PromptState) at ./REPL.jl:404
 [4] add_history(::Base.LineEdit.PromptState) at ./LineEdit.jl:596
 [5] commit_line(::Base.LineEdit.MIState) at ./LineEdit.jl:1306
 [6] (::Base.LineEdit.##92#122)(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL, ::Vararg{Any,N} where N) at ./LineEdit.jl:1357
 [7] (::Base.LineEdit.##13#14{Base.LineEdit.##92#122,String})(::Base.LineEdit.MIState, ::Base.REPL.LineEditREPL) at ./LineEdit.jl:740
 [8] prompt!(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface, ::Base.LineEdit.MIState) at ./LineEdit.jl:1618
 [9] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1578
 [10] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:945
 [11] run_repl(::Base.REPL.LineEditREPL, ::Base.##507#508) at ./REPL.jl:180
 [12] _start() at ./client.jl:413
julia> 
julia> exit()
@yuyichao
Copy link
Contributor

yuyichao commented Sep 6, 2017

Well, if you overwrite critical function incorrectly that's exactly what should happen.

@yuyichao yuyichao closed this as completed Sep 6, 2017
@turtleslow
Copy link
Author

Not sure I agree with your claim that that is what exactly what should happen. I think you mean "we don't prevent users from overwriting critical functions; doing so may result in gibberish".

Is that the approach being taken with the language in general?

@JeffBezanson
Copy link
Member

We tend to be permissive, but speaking in such general terms is not really useful. It would be very simple to make it an error to overwrite methods in Base, for example. It just hasn't seemed very urgent in practice.

@turtleslow
Copy link
Author

Ok, thanks for clarifying.

@turtleslow
Copy link
Author

Here's another piece of code, this time resulting in a segfault. Is this also in the camp of "don't write stupid code"?

Set{Array{T}}() where {T<:Float64} [segfault]

I guess I'm not that clear on what type of crashes are worth reporting given that the code is not supposed to work.

@yuyichao
Copy link
Contributor

yuyichao commented Sep 6, 2017

None of overwrite base function causing crash are worth reporting.

All of other segfaults/hard crashes that's not obviously using unsafe features are worth reporting and Set{Array{T}}() where {T<:Float64} does look like it should have a better error.

@JeffBezanson
Copy link
Member

@turtleslow We always appreciate bug reports and you should always report any possible issue you run into. Different cases are different. Even if two problems have the same underlying cause that is often not obvious at first.

In this case, IIUC, the original problem report did not involve a segfault, whereas your new example does. In any case we absolutely do not take the attitude that nothing is supposed to work and so bug reports are futile. That is not a terribly productive inference to make.

@turtleslow
Copy link
Author

Ok, thanks. I'll keep reporting then and you guys can ignore at your leisure if i report something that's a known philosophical issue. Let me know if you want me to open a separate issue for the segfault.

@yuyichao
Copy link
Contributor

yuyichao commented Sep 7, 2017

Let me know if you want me to open a separate issue for the segfault.

Please do.

@StefanKarpinski
Copy link
Member

StefanKarpinski commented Sep 7, 2017

@turtleslow, there's a notion of "type piracy" which not everyone buys into, but if you do not commit type piracy, you are definitely in the clear in the sense of "your code should not crash Julia". Type piracy is adding a method to a function that doesn't "belong" to you for arguments where none of the argument types "belong" to you. Or conversely, you are not committing an act of piracy if the function or one of the argument types belongs to you. In other words, you can be certain that what you define cannot conflict with anyone else.

In this case, redefining very basic operations like integer comparison is very much type piracy: the < operator and the type Int belong to Base (i.e. everyone), so changing what 1 < 2 means is going to mess with everything. If you want to define your own < operator which has different behavior, just don't qualify the overload. You can even do so with a fallback to call Base.:<.

@yuyichao
Copy link
Contributor

yuyichao commented Sep 7, 2017

there's a notion of "type piracy" which not everyone buys into, but if you do not commit type piracy, you are definitely in the clear in the sense of "your code should not crash Julia"

Just to clarify that type piracy is a concept that is related although not a requirement for overwriting low level/ fundamental Base functions. There are other Base functions that you can overwrite for your own types that can cause low level operations involving your type to crash in a bad way. You can get this effect easily with type reflection functions, e.g.

julia> struct A
           b
       end

julia> Base.isbits(::Type{A}) = true

julia> reinterpret(A, [1:3;])
3-element Array{A,1}:

signal (11): Segmentation fault
while loading no file, in expression starting on line 0
sig_match_simple at /build/julia-git/src/julia-avx2/src/typemap.c:125 [inlined]
jl_typemap_entry_assoc_exact at /build/julia-git/src/julia-avx2/src/typemap.c:763
jl_typemap_assoc_exact at /build/julia-git/src/julia-avx2/src/julia_internal.h:921 [inlined]

There's no type piracy involved here but it's in the same class as overwriting <(::Float64, ::Float64) (i.e. this code "should" crash julia). In both cases, Base code assumes certain functions to behave correctly and overwriting them can cause huge trouble.

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

4 participants