Skip to content

Commit

Permalink
Make OverflowError more informative
Browse files Browse the repository at this point in the history
  • Loading branch information
timholy committed Aug 7, 2017
1 parent 9363b49 commit eb2cfbd
Show file tree
Hide file tree
Showing 16 changed files with 47 additions and 25 deletions.
10 changes: 6 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,12 @@ Deprecated or removed
* `fieldnames` now operates only on types. To get the names of fields in an object, use
`fieldnames(typeof(x))` ([#22350]).

* `InexactError` and `DomainError` now take
* `InexactError`, `DomainError`, and `OverflowError` now take
arguments. `InexactError(func::Symbol, type, -3)` now prints as
`ERROR: InexactError: func(type, -3)`, and `DomainError(val,
[msg])` prints as `ERROR: DomainError with val:\nmsg`. ([#20005],
[#22751])
"ERROR: InexactError: func(type, -3)", `DomainError(val,
[msg])` prints as "ERROR: DomainError with val:\nmsg",
and `OverflowError(msg)` prints as "ERROR: OverflowError: msg".
([#20005], [#22751], [#22761])

* The operating system identification functions: `is_linux`, `is_bsd`, `is_apple`, `is_unix`,
and `is_windows`, have been deprecated in favor of `Sys.islinux`, `Sys.isbsd`, `Sys.isapple`,
Expand Down Expand Up @@ -1118,6 +1119,7 @@ Command-line option changes
[#22723]: https://github.com/JuliaLang/julia/issues/22723
[#22732]: https://github.com/JuliaLang/julia/issues/22732
[#22751]: https://github.com/JuliaLang/julia/issues/22751
[#22761]: https://github.com/JuliaLang/julia/issues/22761
[#22762]: https://github.com/JuliaLang/julia/issues/22762
[#22793]: https://github.com/JuliaLang/julia/issues/22793
[#22796]: https://github.com/JuliaLang/julia/issues/22796
Expand Down
5 changes: 4 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ struct BoundsError <: Exception
BoundsError(@nospecialize(a), i) = (@_noinline_meta; new(a,i))
end
struct DivideError <: Exception end
struct OverflowError <: Exception end
struct COverflowError <: Exception end
struct OutOfMemoryError <: Exception end
struct ReadOnlyMemoryError<: Exception end
struct SegmentationFault <: Exception end
Expand Down Expand Up @@ -241,6 +241,9 @@ struct InexactError <: Exception

InexactError(f::Symbol, @nospecialize(T), @nospecialize(val)) = (@_noinline_meta; new(f, T, val))
end
struct OverflowError <: Exception
msg
end

abstract type DirectIndexString <: AbstractString end

Expand Down
19 changes: 12 additions & 7 deletions base/checked.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Core.Intrinsics:
checked_srem_int,
checked_uadd_int, checked_usub_int, checked_umul_int, checked_udiv_int,
checked_urem_int
import Base: no_op_err, @_inline_meta
import Base: no_op_err, @_inline_meta, @_noinline_meta

# define promotion behavior for checked operations
checked_add(x::Integer, y::Integer) = checked_add(promote(x,y)...)
Expand Down Expand Up @@ -90,16 +90,18 @@ The overflow protection may impose a perceptible performance penalty.
function checked_neg(x::T) where T<:Integer
checked_sub(T(0), x)
end
throw_overflowerr_negation(x) = (@_noinline_meta;
throw(OverflowError("checked arithmetic: cannot compute -x for x = $x::$(typeof(x))")))
if BrokenSignedInt != Union{}
function checked_neg(x::BrokenSignedInt)
r = -x
(x<0) & (r<0) && throw(OverflowError())
(x<0) & (r<0) && throw_overflowerr_negation(x)
r
end
end
if BrokenUnsignedInt != Union{}
function checked_neg(x::T) where T<:BrokenUnsignedInt
x != 0 && throw(OverflowError())
x != 0 && throw_overflowerr_negation(x)
T(0)
end
end
Expand All @@ -117,7 +119,7 @@ function checked_abs end

function checked_abs(x::SignedInt)
r = ifelse(x<0, -x, x)
r<0 && throw(OverflowError())
r<0 && throw(OverflowError(string("checked arithmetic: cannot compute |x| for x = ", x, "::", typeof(x))))
r
end
checked_abs(x::UnsignedInt) = x
Expand Down Expand Up @@ -152,6 +154,9 @@ end
end


throw_overflowerr_binaryop(op, x, y) = (@_noinline_meta;
throw(OverflowError("$x $op $y overflowed for type $(typeof(x))")))

"""
Base.checked_add(x, y)
Expand All @@ -162,7 +167,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_add(x::T, y::T) where T<:Integer
@_inline_meta
z, b = add_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:+, x, y)
z
end

Expand Down Expand Up @@ -219,7 +224,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_sub(x::T, y::T) where T<:Integer
@_inline_meta
z, b = sub_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:-, x, y)
z
end

Expand Down Expand Up @@ -284,7 +289,7 @@ The overflow protection may impose a perceptible performance penalty.
function checked_mul(x::T, y::T) where T<:Integer
@_inline_meta
z, b = mul_with_overflow(x, y)
b && throw(OverflowError())
b && throw_overflowerr_binaryop(:*, x, y)
z
end

Expand Down
2 changes: 1 addition & 1 deletion base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ end

function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError(n, "`n` must not be negative."))
n > lim && throw(OverflowError())
n > lim && throw(OverflowError(string(n, " is too large to look up in the table")))
n == 0 && return one(n)
@inbounds f = table[n]
return oftype(n, f)
Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,12 @@ function DomainError()
DomainError(nothing)
end

# PR #22761
function OverflowError()
depwarn("OverflowError now supports a message string, use `OverflowError(msg)` instead.", :OverflowError)
OverflowError("")
end

# PR #22703
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, isupper::Bool) Bidiagonal(dv, ev, ifelse(isupper, :U, :L))
@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, uplo::Char) Bidiagonal(dv, ev, ifelse(uplo == 'U', :U, :L))
Expand Down
2 changes: 1 addition & 1 deletion base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1509,7 +1509,7 @@ used only with extreme caution, as it can cause memory use to grow without bound
gc_enable

"""
OverflowError()
OverflowError(msg)
The result of an expression is too large for the specified type and will cause a wraparound.
"""
Expand Down
4 changes: 3 additions & 1 deletion base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ isqrt(x::BigInt) = MPZ.sqrt(x)

function bigint_pow(x::BigInt, y::Integer)
if y<0; throw(DomainError(y, "`y` cannot be negative.")); end
@noinline throw1(y) =
throw(OverflowError("exponent $y is too large and computation will overflow"))
if x== 1; return x; end
if x==-1; return isodd(y) ? x : -x; end
if y>typemax(Culong)
Expand All @@ -507,7 +509,7 @@ function bigint_pow(x::BigInt, y::Integer)
#
#Assume that the answer will definitely overflow.

throw(OverflowError())
throw1(y)
end
return x^convert(Culong, y)
end
Expand Down
6 changes: 4 additions & 2 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ end
# binary GCD (aka Stein's) algorithm
# about 1.7x (2.1x) faster for random Int64s (Int128s)
function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
@noinline throw1(a, b) = throw(OverflowError("gcd($a, $b) overflows"))
a == 0 && return abs(b)
b == 0 && return abs(a)
za = trailing_zeros(a)
Expand All @@ -44,7 +45,7 @@ function gcd(a::T, b::T) where T<:Union{Int64,UInt64,Int128,UInt128}
end
r = u << k
# T(r) would throw InexactError; we want OverflowError instead
r > typemax(T) && throw(OverflowError())
r > typemax(T) && throw1(a, b)
r % T
end

Expand Down Expand Up @@ -841,6 +842,7 @@ julia> factorial(5) ÷ (factorial(5-3) * factorial(3))
```
"""
function binomial(n::T, k::T) where T<:Integer
n0, k0 = n, k
k < 0 && return zero(T)
sgn = one(T)
if n < 0
Expand All @@ -861,7 +863,7 @@ function binomial(n::T, k::T) where T<:Integer
while rr <= k
xt = div(widemul(x, nn), rr)
x = xt
x == xt || throw(OverflowError())
x == xt || throw(OverflowError("binomial($n0, $k0) overflows"))
rr += 1
nn += 1
end
Expand Down
2 changes: 1 addition & 1 deletion base/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::
n, ov_mul = mul_with_overflow(n, base)
n, ov_add = add_with_overflow(n, d)
if ov_mul | ov_add
raise && throw(OverflowError())
raise && throw(OverflowError("overflow parsing $(repr(SubString(s,startpos,endpos)))"))
return _n
end
(i > endpos) && return Nullable{T}(n)
Expand Down
4 changes: 2 additions & 2 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,11 @@ isinteger(x::Rational) = x.den == 1

-(x::Rational) = (-x.num) // x.den
function -(x::Rational{T}) where T<:Signed
x.num == typemin(T) && throw(OverflowError())
x.num == typemin(T) && throw(OverflowError("rational numerator is typemin(T)"))
(-x.num) // x.den
end
function -(x::Rational{T}) where T<:Unsigned
x.num != zero(T) && throw(OverflowError())
x.num != zero(T) && throw(OverflowError("cannot negate unsigned number"))
x
end

Expand Down
2 changes: 2 additions & 0 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ function showerror(io::IO, ex::SystemError)
end
end
showerror(io::IO, ::DivideError) = print(io, "DivideError: integer division error")
showerror(io::IO, ::Core.COverflowError) = print(io, "COverflowError:")
showerror(io::IO, ::StackOverflowError) = print(io, "StackOverflowError:")
showerror(io::IO, ::UndefRefError) = print(io, "UndefRefError: access to undefined reference")
showerror(io::IO, ::EOFError) = print(io, "EOFError: read end of file")
Expand All @@ -275,6 +276,7 @@ showerror(io::IO, ex::KeyError) = print(io, "KeyError: key $(repr(ex.key)) not f
showerror(io::IO, ex::InterruptException) = print(io, "InterruptException:")
showerror(io::IO, ex::ArgumentError) = print(io, "ArgumentError: $(ex.msg)")
showerror(io::IO, ex::AssertionError) = print(io, "AssertionError: $(ex.msg)")
showerror(io::IO, ex::OverflowError) = print(io, "OverflowError: $(ex.msg)")

function showerror(io::IO, ex::UndefVarError)
if ex.var in [:UTF16String, :UTF32String, :WString, :utf16, :utf32, :wstring, :RepString]
Expand Down
2 changes: 1 addition & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6015,7 +6015,7 @@ static void init_julia_llvm_env(Module *m)
global_jlvalue_to_llvm("jl_emptytuple", &jl_emptytuple, m);
global_jlvalue_to_llvm("jl_diverror_exception", &jl_diverror_exception, m);
global_jlvalue_to_llvm("jl_undefref_exception", &jl_undefref_exception, m);
global_jlvalue_to_llvm("jl_overflow_exception", &jl_overflow_exception, m);
global_jlvalue_to_llvm("jl_c_overflow_exception", &jl_c_overflow_exception, m);

jlRTLD_DEFAULT_var =
new GlobalVariable(*m, T_pint8,
Expand Down
2 changes: 1 addition & 1 deletion src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ void jl_compute_field_offsets(jl_datatype_t *st)
return;
throw_ovf:
if (descsz >= jl_page_size) free(desc);
jl_throw(jl_overflow_exception);
jl_throw(jl_c_overflow_exception);
}

extern int jl_boot_file_loaded;
Expand Down
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ void jl_get_builtin_hooks(void)
jl_errorexception_type = (jl_datatype_t*)core("ErrorException");
jl_stackovf_exception = jl_new_struct_uninit((jl_datatype_t*)core("StackOverflowError"));
jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError"));
jl_overflow_exception = jl_new_struct_uninit((jl_datatype_t*)core("OverflowError"));
jl_c_overflow_exception = jl_new_struct_uninit((jl_datatype_t*)core("COverflowError"));
jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError"));
jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError");
jl_interrupt_exception = jl_new_struct_uninit((jl_datatype_t*)core("InterruptException"));
Expand Down
2 changes: 1 addition & 1 deletion src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jl_value_t *jl_segv_exception;
#endif
JL_DLLEXPORT jl_value_t *jl_diverror_exception;
JL_DLLEXPORT jl_value_t *jl_domain_exception;
JL_DLLEXPORT jl_value_t *jl_overflow_exception;
JL_DLLEXPORT jl_value_t *jl_c_overflow_exception;
JL_DLLEXPORT jl_value_t *jl_undefref_exception;
jl_value_t *jl_interrupt_exception;
jl_datatype_t *jl_boundserror_type;
Expand Down
2 changes: 1 addition & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ extern JL_DLLEXPORT jl_value_t *jl_stackovf_exception;
extern JL_DLLEXPORT jl_value_t *jl_memory_exception;
extern JL_DLLEXPORT jl_value_t *jl_readonlymemory_exception;
extern JL_DLLEXPORT jl_value_t *jl_diverror_exception;
extern JL_DLLEXPORT jl_value_t *jl_overflow_exception;
extern JL_DLLEXPORT jl_value_t *jl_c_overflow_exception;
extern JL_DLLEXPORT jl_value_t *jl_undefref_exception;
extern JL_DLLEXPORT jl_value_t *jl_interrupt_exception;
extern JL_DLLEXPORT jl_datatype_t *jl_boundserror_type;
Expand Down

0 comments on commit eb2cfbd

Please sign in to comment.