Skip to content

Commit

Permalink
Fix integer overflow in skip(s::IOBuffer, typemax(Int64)) (JuliaLan…
Browse files Browse the repository at this point in the history
…g#54070)

Fixes JuliaLang#53908  by clamping before doing addition.

This also fixes an issue with negative skips if `io.offset` isn't zero.

I am assuming that `io.size+1` cannot overflow.
  • Loading branch information
nhz2 authored Apr 17, 2024
1 parent 159f4d7 commit 306124c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 7 deletions.
24 changes: 17 additions & 7 deletions base/iobuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -260,22 +260,32 @@ bytesavailable(io::GenericIOBuffer) = io.size - io.ptr + 1
position(io::GenericIOBuffer) = io.ptr - io.offset - 1

function skip(io::GenericIOBuffer, n::Integer)
seekto = io.ptr + n
n < 0 && return seek(io, seekto-1) # Does error checking
io.ptr = min(seekto, io.size+1)
return io
skip(io, clamp(n, Int))
end
function skip(io::GenericIOBuffer, n::Int)
if signbit(n)
seekto = clamp(widen(position(io)) + widen(n), Int)
seek(io, seekto) # Does error checking
else
n_max = io.size + 1 - io.ptr
io.ptr += min(n, n_max)
io
end
end

function seek(io::GenericIOBuffer, n::Integer)
seek(io, clamp(n, Int))
end
function seek(io::GenericIOBuffer, n::Int)
if !io.seekable
ismarked(io) || throw(ArgumentError("seek failed, IOBuffer is not seekable and is not marked"))
n == io.mark || throw(ArgumentError("seek failed, IOBuffer is not seekable and n != mark"))
end
# TODO: REPL.jl relies on the fact that this does not throw (by seeking past the beginning or end
# of an GenericIOBuffer), so that would need to be fixed in order to throw an error here
#(n < 0 || n > io.size) && throw(ArgumentError("Attempted to seek outside IOBuffer boundaries."))
#io.ptr = n+1
io.ptr = min(max(0, n)+io.offset, io.size)+1
#(n < 0 || n > io.size - io.offset) && throw(ArgumentError("Attempted to seek outside IOBuffer boundaries."))
#io.ptr = n + io.offset + 1
io.ptr = clamp(n, 0, io.size - io.offset) + io.offset + 1
return io
end

Expand Down
25 changes: 25 additions & 0 deletions test/iobuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,31 @@ end
@test position(skip(io, -3)) == 0
end

@testset "issue #53908" begin
@testset "offset $first" for first in (false, true)
b = collect(0x01:0x05)
sizehint!(b, 100; first) # make offset non zero
io = IOBuffer(b)
@test position(skip(io, 4)) == 4
@test position(skip(io, typemax(Int))) == 5
@test position(skip(io, typemax(Int128))) == 5
@test position(skip(io, typemax(Int32))) == 5
@test position(skip(io, typemin(Int))) == 0
@test position(skip(io, typemin(Int128))) == 0
@test position(skip(io, typemin(Int32))) == 0
@test position(skip(io, 4)) == 4
@test position(skip(io, -2)) == 2
@test position(skip(io, -2)) == 0
@test position(seek(io, -2)) == 0
@test position(seek(io, typemax(Int))) == 5
@test position(seek(io, typemax(Int128))) == 5
@test position(seek(io, typemax(Int32))) == 5
@test position(seek(io, typemin(Int))) == 0
@test position(seek(io, typemin(Int128))) == 0
@test position(seek(io, typemin(Int32))) == 0
end
end

@testset "pr #11554" begin
io = IOBuffer(SubString("***αhelloworldω***", 4, 16))
io2 = IOBuffer(Vector{UInt8}(b"goodnightmoon"), read=true, write=true)
Expand Down

0 comments on commit 306124c

Please sign in to comment.