Skip to content

Commit

Permalink
Base: prevent precision infinite recursion
Browse files Browse the repository at this point in the history
Make the single-argument method of `_precision` into its own function.

Now `precision(Union{Float16,Float32})` results in a `MethodError`
instead of in a `StackOverflowError`.

Fixes #52909
  • Loading branch information
nsajko committed Jan 15, 2024
1 parent fc6295d commit 1af46b8
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
8 changes: 4 additions & 4 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -836,12 +836,12 @@ number of significand digits in that base.
"""
function precision end

_precision(::Type{Float16}) = 11
_precision(::Type{Float32}) = 24
_precision(::Type{Float64}) = 53
precision_with_base_2(::Type{Float16}) = 11
precision_with_base_2(::Type{Float32}) = 24
precision_with_base_2(::Type{Float64}) = 53
function _precision(x, base::Integer=2)
base > 1 || throw(DomainError(base, "`base` cannot be less than 2."))
p = _precision(x)
p = precision_with_base_2(x)
return base == 2 ? Int(p) : floor(Int, p / log2(base))
end
precision(::Type{T}; base::Integer=2) where {T<:AbstractFloat} = _precision(T, base)
Expand Down
10 changes: 5 additions & 5 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import
cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, lerpi,
cbrt, typemax, typemin, unsafe_trunc, floatmin, floatmax, rounding,
setrounding, maxintfloat, widen, significand, frexp, tryparse, iszero,
isone, big, _string_n, decompose, minmax,
isone, big, _string_n, decompose, minmax, precision_with_base_2,
sinpi, cospi, sincospi, tanpi, sind, cosd, tand, asind, acosd, atand,
uinttype, exponent_max, exponent_min, ieee754_representation, significand_mask,
RawBigIntRoundingIncrementHelper, truncated, RawBigInt
Expand Down Expand Up @@ -221,7 +221,7 @@ widen(::Type{Float64}) = BigFloat
widen(::Type{BigFloat}) = BigFloat

function BigFloat(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::Integer=DEFAULT_PRECISION[])
if precision == _precision(x)
if precision == precision(x)
return x
else
z = BigFloat(;precision=precision)
Expand All @@ -232,7 +232,7 @@ function BigFloat(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::I
end

function _duplicate(x::BigFloat)
z = BigFloat(;precision=_precision(x))
z = BigFloat(;precision=precision(x))
ccall((:mpfr_set, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, 0)
return z
end
Expand Down Expand Up @@ -954,12 +954,12 @@ function sign(x::BigFloat)
return c < 0 ? -one(x) : one(x)
end

function _precision(x::BigFloat) # precision of an object of type BigFloat
function precision_with_base_2(x::BigFloat) # precision of an object of type BigFloat
return ccall((:mpfr_get_prec, libmpfr), Clong, (Ref{BigFloat},), x)
end
precision(x::BigFloat; base::Integer=2) = _precision(x, base)

_precision(::Type{BigFloat}) = Int(DEFAULT_PRECISION[]) # default precision of the type BigFloat itself
precision_with_base_2(::Type{BigFloat}) = Int(DEFAULT_PRECISION[]) # default precision of the type BigFloat itself

"""
setprecision([T=BigFloat,] precision::Int; base=2)
Expand Down
11 changes: 11 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3141,3 +3141,14 @@ end
@test n == G(F(n)) == F(G(n))
end
end

@testset "`precision` of `Union` shouldn't recur infinitely, #52909" begin
Fs = (Float16, Float32, Float64, BigFloat)
@testset "i: $i" for i eachindex(Fs)
@testset "j: $j" for j (i + 1):lastindex(Fs)
S = Fs[i]
T = Fs[j]
@test_throws MethodError precision(Union{S,T})
end
end
end

0 comments on commit 1af46b8

Please sign in to comment.