Skip to content

Commit 306124c

Browse files
authored
Fix integer overflow in skip(s::IOBuffer, typemax(Int64)) (#54070)
Fixes #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.
1 parent 159f4d7 commit 306124c

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

base/iobuffer.jl

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,22 +260,32 @@ bytesavailable(io::GenericIOBuffer) = io.size - io.ptr + 1
260260
position(io::GenericIOBuffer) = io.ptr - io.offset - 1
261261

262262
function skip(io::GenericIOBuffer, n::Integer)
263-
seekto = io.ptr + n
264-
n < 0 && return seek(io, seekto-1) # Does error checking
265-
io.ptr = min(seekto, io.size+1)
266-
return io
263+
skip(io, clamp(n, Int))
264+
end
265+
function skip(io::GenericIOBuffer, n::Int)
266+
if signbit(n)
267+
seekto = clamp(widen(position(io)) + widen(n), Int)
268+
seek(io, seekto) # Does error checking
269+
else
270+
n_max = io.size + 1 - io.ptr
271+
io.ptr += min(n, n_max)
272+
io
273+
end
267274
end
268275

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

test/iobuffer.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,31 @@ end
196196
@test position(skip(io, -3)) == 0
197197
end
198198

199+
@testset "issue #53908" begin
200+
@testset "offset $first" for first in (false, true)
201+
b = collect(0x01:0x05)
202+
sizehint!(b, 100; first) # make offset non zero
203+
io = IOBuffer(b)
204+
@test position(skip(io, 4)) == 4
205+
@test position(skip(io, typemax(Int))) == 5
206+
@test position(skip(io, typemax(Int128))) == 5
207+
@test position(skip(io, typemax(Int32))) == 5
208+
@test position(skip(io, typemin(Int))) == 0
209+
@test position(skip(io, typemin(Int128))) == 0
210+
@test position(skip(io, typemin(Int32))) == 0
211+
@test position(skip(io, 4)) == 4
212+
@test position(skip(io, -2)) == 2
213+
@test position(skip(io, -2)) == 0
214+
@test position(seek(io, -2)) == 0
215+
@test position(seek(io, typemax(Int))) == 5
216+
@test position(seek(io, typemax(Int128))) == 5
217+
@test position(seek(io, typemax(Int32))) == 5
218+
@test position(seek(io, typemin(Int))) == 0
219+
@test position(seek(io, typemin(Int128))) == 0
220+
@test position(seek(io, typemin(Int32))) == 0
221+
end
222+
end
223+
199224
@testset "pr #11554" begin
200225
io = IOBuffer(SubString("***αhelloworldω***", 4, 16))
201226
io2 = IOBuffer(Vector{UInt8}(b"goodnightmoon"), read=true, write=true)

0 commit comments

Comments
 (0)