Skip to content

Commit 20e8f46

Browse files
authored
Fix assumption about underflow on AbstractUnitrange{<:Unsigned} (JuliaLang#42632)
As mentioned in JuliaLang#42528 after the initial PR, just removing `ifelse` is not enough. This fixes the behavior for creating empty UnitRanges of unsigned integers to avoid assuming overflow is safe.
1 parent 05515f4 commit 20e8f46

File tree

2 files changed

+12
-3
lines changed

2 files changed

+12
-3
lines changed

base/range.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ UnitRange(start::T, stop::T) where {T<:Real} = UnitRange{T}(start, stop)
394394

395395
unitrange_last(::Bool, stop::Bool) = stop
396396
unitrange_last(start::T, stop::T) where {T<:Integer} =
397-
stop >= start ? stop : convert(T,start-oneunit(stop-start))
397+
stop >= start ? stop : convert(T,start-oneunit(start-stop))
398398
unitrange_last(start::T, stop::T) where {T} =
399399
stop >= start ? convert(T,start+floor(stop-start)) :
400400
convert(T,start-oneunit(stop-start))
@@ -734,8 +734,14 @@ end
734734

735735
function length(r::AbstractUnitRange{T}) where T
736736
@inline
737-
a = last(r) - first(r) # even when isempty, by construction (with overflow)
738-
return Integer(a + oneunit(a))
737+
start, stop = first(r), last(r)
738+
a = oneunit(zero(stop) - zero(start))
739+
if a isa Signed || stop >= start
740+
a += stop - start # Signed are allowed to go negative
741+
else
742+
a = zero(a) # Unsigned don't necessarily underflow
743+
end
744+
return Integer(a)
739745
end
740746

741747
length(r::OneTo) = Integer(r.stop - zero(r.stop))

test/ranges.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ struct OverflowingReal <: Real
582582
val::UInt8
583583
end
584584
OverflowingReal(x::OverflowingReal) = x
585+
Base.:<(x::OverflowingReal, y::OverflowingReal) = x.val < y.val
586+
Base.:(==)(x::OverflowingReal, y::OverflowingReal) = x.val == y.val
585587
Base.:<=(x::OverflowingReal, y::OverflowingReal) = x.val <= y.val
586588
Base.:+(x::OverflowingReal, y::OverflowingReal) = OverflowingReal(x.val + y.val)
587589
Base.:-(x::OverflowingReal, y::OverflowingReal) = OverflowingReal(x.val - y.val)
@@ -2204,5 +2206,6 @@ end
22042206
end
22052207
Base.one(::Type{Fix42528}) = Fix42528(0x1)
22062208
@test Fix42528(0x0):Fix42528(0x1) == [Fix42528(0x0), Fix42528(0x01)]
2209+
@test iszero(length(Fix42528(0x1):Fix42528(0x0)))
22072210
@test_throws DomainError Fix42528(0x0) - Fix42528(0x1)
22082211
end

0 commit comments

Comments
 (0)