Skip to content

Commit

Permalink
Make OverflowError more informative
Browse files Browse the repository at this point in the history
[ci skip]
  • Loading branch information
timholy committed Jul 11, 2017
1 parent 37ca8c7 commit 01a95a8
Show file tree
Hide file tree
Showing 14 changed files with 39 additions and 21 deletions.
5 changes: 4 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ struct BoundsError <: Exception
end
struct DivideError <: Exception end
struct DomainError <: Exception end
struct OverflowError <: Exception end
struct FieldOverflowError <: Exception end
struct OutOfMemoryError <: Exception end
struct ReadOnlyMemoryError<: Exception end
struct SegmentationFault <: Exception end
Expand All @@ -229,6 +229,9 @@ struct InexactError <: Exception

InexactError(f::Symbol, T::ANY, val::ANY) = (@_noinline_meta; new(f, T, val))
end
struct OverflowError <: Exception
args
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("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("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, T) = (@_noinline_meta;
throw(OverflowError("$x $op $y overflowed for type $T")))

"""
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, T)
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, T)
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, T)
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 > 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 @@ -1561,6 +1561,12 @@ function InexactError()
InexactError(:none, Any, nothing)
end

# PR #??
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 @@ -1593,7 +1593,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 @@ -482,6 +482,8 @@ isqrt(x::BigInt) = MPZ.sqrt(x)
^(x::BigInt, y::Culong) = MPZ.pow_ui(x, y)

function bigint_pow(x::BigInt, y::Integer)
@noinline throw1(y) =
throw(OverflowError("exponent $y is too large and computation will overflow"))
if y<0; throw(DomainError()); end
if x== 1; return x; end
if x==-1; return isodd(y) ? x : -x; end
Expand All @@ -496,7 +498,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 @@ -824,6 +825,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 @@ -844,7 +846,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: 1 addition & 1 deletion src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6242,7 +6242,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_fieldoverflow_exception", &jl_fieldoverflow_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_fieldoverflow_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_fieldoverflow_exception = jl_new_struct_uninit((jl_datatype_t*)core("FieldOverflowError"));
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_fieldoverflow_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 @@ -528,7 +528,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_fieldoverflow_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 01a95a8

Please sign in to comment.