Skip to content

Commit f57d831

Browse files
bounds check thisind, nextind and prevind as well
1 parent 01cb162 commit f57d831

File tree

8 files changed

+168
-118
lines changed

8 files changed

+168
-118
lines changed

base/repl/REPL.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,11 @@ function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, respo
609609

610610
# Alright, first try to see if the current match still works
611611
a = position(response_buffer) + 1 # position is zero-indexed
612-
b = min(endof(response_str), prevind(response_str, a + sizeof(searchdata))) # ensure that b is valid
612+
# FIXME: I'm pretty sure this is broken since it uses an index
613+
# into the search data to index into the response string
614+
b = a + sizeof(searchdata)
615+
b = b  ncodeunits(response_str) ? prevind(response_str, b) : b-1
616+
b = min(endof(response_str), b) # ensure that b is valid
613617

614618
!skip_current && searchdata == response_str[a:b] && return true
615619

base/strings/basic.jl

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,12 @@ julia> thisind("αβγdef", 10)
383383
julia> thisind("αβγdef", 20)
384384
20
385385
"""
386-
function thisind(s::AbstractString, i::Integer)
387-
i  ncodeunits(s) || return i
386+
thisind(s::AbstractString, i::Integer) = thisind(s, Int(i))
387+
388+
function thisind(s::AbstractString, i::Int)
389+
z = ncodeunits(s) + 1
390+
i == z && return i
391+
@boundscheck 0  i z || throw(BoundsError(s, i))
388392
@inbounds while 1 < i && !isvalid(s, i)
389393
i -= 1
390394
end
@@ -415,13 +419,14 @@ julia> prevind("αβγdef", 3, 2)
415419
0
416420
```
417421
"""
418-
function prevind(s::AbstractString, i::Integer, n::Integer=1)
422+
prevind(s::AbstractString, i::Integer, n::Integer) = prevind(s, Int(i), Int(n))
423+
prevind(s::AbstractString, i::Integer) = prevind(s, Int(i))
424+
prevind(s::AbstractString, i::Int) = prevind(s, i, 1)
425+
426+
function prevind(s::AbstractString, i::Int, n::Int)
419427
n < 0 && throw(ArgumentError("n cannot be negative: $n"))
420428
z = ncodeunits(s) + 1
421-
if i > z
422-
n -= i - z
423-
i = z
424-
end
429+
@boundscheck 0 < i z || throw(BoundsError(s, i))
425430
while n > 0 && 1 < i
426431
@inbounds n -= isvalid(s, i -= 1)
427432
end
@@ -452,13 +457,14 @@ julia> nextind(str, 9)
452457
10
453458
```
454459
"""
455-
function nextind(s::AbstractString, i::Integer, n::Integer=1)
460+
nextind(s::AbstractString, i::Integer, n::Integer) = nextind(s, Int(i), Int(n))
461+
nextind(s::AbstractString, i::Integer) = nextind(s, Int(i))
462+
nextind(s::AbstractString, i::Int) = nextind(s, i, 1)
463+
464+
function nextind(s::AbstractString, i::Int, n::Int)
456465
n < 0 && throw(ArgumentError("n cannot be negative: $n"))
457-
if i < 1
458-
n += i - 1
459-
i = 1
460-
end
461466
z = ncodeunits(s)
467+
@boundscheck 0 i z || throw(BoundsError(s, i))
462468
while n > 0 && i < z
463469
@inbounds n -= isvalid(s, i += 1)
464470
end

base/strings/search.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,8 @@ function rsearchindex(s::String, t::String, i::Integer)
412412
if endof(t) == 1
413413
rsearch(s, t[1], i)
414414
elseif endof(t) != 0
415-
_rsearchindex(s, t, nextind(s, i)-1)
415+
j = i ncodeunits(s) ? nextind(s, i)-1 : i
416+
_rsearchindex(s, t, j)
416417
elseif i > sizeof(s)
417418
return 0
418419
elseif i == 0

base/strings/string.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,12 @@ function ==(a::String, b::String)
9292
al == sizeof(b) && 0 == ccall(:memcmp, Int32, (Ptr{UInt8}, Ptr{UInt8}, UInt), a, b, al)
9393
end
9494

95-
## thisind, nextind, prevind ##
96-
97-
thisind(s::String, i::Integer) = oftype(i, thisind(s, Int(i)))
98-
nextind(s::String, i::Integer) = oftype(i, nextind(s, Int(i)))
95+
## thisind, prevind, nextind ##
9996

10097
function thisind(s::String, i::Int)
10198
n = ncodeunits(s)
102-
between(i, 2, n) || return i
99+
i == n + 1 && return i
100+
@boundscheck between(i, 0, n) || throw(BoundsError(s, i))
103101
@inbounds b = codeunit(s, i)
104102
b & 0xc0 == 0x80 || return i
105103
@inbounds b = codeunit(s, i-1)
@@ -114,8 +112,9 @@ function thisind(s::String, i::Int)
114112
end
115113

116114
function nextind(s::String, i::Int)
115+
i == 0 && return 1
117116
n = ncodeunits(s)
118-
between(i, 1, n-1) || return i+1
117+
@boundscheck between(i, 1, n) || throw(BoundsError(s, i))
119118
@inbounds l = codeunit(s, i)
120119
(l < 0x80) | (0xf8 l) && return i+1
121120
if l < 0xc0

base/strings/substring.jl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,26 @@ function isvalid(s::SubString, i::Integer)
7878
@inbounds return ib && isvalid(s.string, s.offset + i)
7979
end
8080

81-
thisind(s::SubString, i::Integer) = thisind(s.string, s.offset + i) - s.offset
82-
nextind(s::SubString, i::Integer) = nextind(s.string, s.offset + i) - s.offset
83-
prevind(s::SubString, i::Integer) = prevind(s.string, s.offset + i) - s.offset
81+
function thisind(s::SubString, i::Int)
82+
@boundscheck 0 i  ncodeunits(s)+1 || throw(BoundsError(s, i))
83+
@inbounds return thisind(s.string, s.offset + i) - s.offset
84+
end
85+
function nextind(s::SubString, i::Int, n::Int)
86+
@boundscheck 0 i < ncodeunits(s)+1 || throw(BoundsError(s, i))
87+
@inbounds return nextind(s.string, s.offset + i, n) - s.offset
88+
end
89+
function nextind(s::SubString, i::Int)
90+
@boundscheck 0 i < ncodeunits(s)+1 || throw(BoundsError(s, i))
91+
@inbounds return nextind(s.string, s.offset + i) - s.offset
92+
end
93+
function prevind(s::SubString, i::Int, n::Int)
94+
@boundscheck 0 < i  ncodeunits(s)+1 || throw(BoundsError(s, i))
95+
@inbounds return prevind(s.string, s.offset + i, n) - s.offset
96+
end
97+
function prevind(s::SubString, i::Int)
98+
@boundscheck 0 < i  ncodeunits(s)+1 || throw(BoundsError(s, i))
99+
@inbounds return prevind(s.string, s.offset + i) - s.offset
100+
end
84101

85102
function cmp(a::SubString{String}, b::SubString{String})
86103
na = sizeof(a)

base/strings/util.jl

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,20 @@ function _split(str::AbstractString, splitter, limit::Integer, keep_empty::Bool,
281281
i = start(str)
282282
n = endof(str)
283283
r = search(str,splitter,i)
284-
j, k = first(r), nextind(str,last(r))
285-
while 0 < j <= n && length(strs) != limit-1
286-
if i < k
287-
if keep_empty || i < j
288-
push!(strs, SubString(str,i,prevind(str,j)))
284+
if r != 0:-1
285+
j, k = first(r), nextind(str,last(r))
286+
while 0 < j <= n && length(strs) != limit-1
287+
if i < k
288+
if keep_empty || i < j
289+
push!(strs, SubString(str,i,prevind(str,j)))
290+
end
291+
i = k
289292
end
290-
i = k
293+
(k <= j) && (k = nextind(str,j))
294+
r = search(str,splitter,k)
295+
r == 0:-1 && break
296+
j, k = first(r), nextind(str,last(r))
291297
end
292-
(k <= j) && (k = nextind(str,j))
293-
r = search(str,splitter,k)
294-
j, k = first(r), nextind(str,last(r))
295298
end
296299
if keep_empty || !done(str,i)
297300
push!(strs, SubString(str,i))
@@ -377,18 +380,16 @@ function replace_new(str::String, pattern, repl, count::Integer)
377380
unsafe_write(out, pointer(str, i), UInt(j-i))
378381
_replace(out, repl, str, r, pattern)
379382
end
380-
if k<j
383+
if k < j
381384
i = j
385+
j > e && break
382386
k = nextind(str, j)
383387
else
384388
i = k = nextind(str, k)
385389
end
386-
if j > e
387-
break
388-
end
389390
r = search(str,pattern,k)
391+
r == 0:-1 || n == count && break
390392
j, k = first(r), last(r)
391-
n == count && break
392393
n += 1
393394
end
394395
write(out, SubString(str,i))

test/strings/basic.jl

Lines changed: 86 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ end
9999
end
100100

101101
@testset "issue #7248" begin
102-
@test_throws BoundsError length("hello", 1, -1) == 0
103-
@test prevind("hello", 0, 1) == -1
104-
@test_throws BoundsError length("hellø", 1, -1) == 0
105-
@test prevind("hellø", 0, 1) == -1
106-
@test_throws BoundsError length("hello", 1, 10) == 10
102+
@test_throws BoundsError length("hello", 1, -1)
103+
@test_throws BoundsError prevind("hello", 0, 1)
104+
@test_throws BoundsError length("hellø", 1, -1)
105+
@test_throws BoundsError prevind("hellø", 0, 1)
106+
@test_throws BoundsError length("hello", 1, 10)
107107
@test nextind("hello", 0, 10) == 10
108108
@test_throws BoundsError length("hellø", 1, 10) == 9
109109
@test nextind("hellø", 0, 10) == 11
@@ -579,7 +579,8 @@ end
579579
SubString("123∀α>β:α+1>β123", 4, 18),
580580
SubString(s"123∀α>β:α+1>β123", 4, 18)]
581581
for s in strs
582-
@test thisind(s, -2) == -2
582+
@test_throws BoundsError thisind(s, -2)
583+
@test_throws BoundsError thisind(s, -1)
583584
@test thisind(s, 0) == 0
584585
@test thisind(s, 1) == 1
585586
@test thisind(s, 2) == 1
@@ -590,86 +591,97 @@ end
590591
@test thisind(s, 15) == 15
591592
@test thisind(s, 16) == 15
592593
@test thisind(s, 17) == 17
593-
@test thisind(s, 30) == 30
594+
@test_throws BoundsError thisind(s, 18)
595+
@test_throws BoundsError thisind(s, 19)
594596
end
595597
end
596598

597599
let strs = Any["", s"", SubString("123", 2, 1), SubString(s"123", 2, 1)]
598-
for s in strs, i in -2:2
599-
@test thisind(s, i) == i
600+
for s in strs
601+
@test_throws BoundsError thisind(s, -1)
602+
@test thisind(s, 0) == 0
603+
@test thisind(s, 1) == 1
604+
@test_throws BoundsError thisind(s, 2)
600605
end
601606
end
602607
end
603608

604609
@testset "prevind and nextind" begin
605-
let strs = Any["∀α>β:α+1>β", GenericString("∀α>β:α+1>β")]
606-
for i in 1:2
607-
@test prevind(strs[i], 1) == 0
608-
@test prevind(strs[i], 1, 1) == 0
609-
@test prevind(strs[i], 2) == 1
610-
@test prevind(strs[i], 2, 1) == 1
611-
@test prevind(strs[i], 4) == 1
612-
@test prevind(strs[i], 4, 1) == 1
613-
@test prevind(strs[i], 5) == 4
614-
@test prevind(strs[i], 5, 1) == 4
615-
@test prevind(strs[i], 5, 2) == 1
616-
@test prevind(strs[i], 5, 3) == 0
617-
@test prevind(strs[i], 15) == 14
618-
@test prevind(strs[i], 15, 1) == 14
619-
@test prevind(strs[i], 15, 2) == 13
620-
@test prevind(strs[i], 15, 3) == 12
621-
@test prevind(strs[i], 15, 4) == 10
622-
@test prevind(strs[i], 15, 10) == 0
623-
@test prevind(strs[i], 15, 9) == 1
624-
@test prevind(strs[i], 16) == 15
625-
@test prevind(strs[i], 16, 1) == 15
626-
@test prevind(strs[i], 16, 2) == 14
627-
@test prevind(strs[i], 20) == 19
628-
@test prevind(strs[i], 20, 1) == 19
629-
@test prevind(strs[i], 20, 10) == 7
630-
@test prevind(strs[i], 20, 0) == 20
631-
632-
@test nextind(strs[i], -1) == 0
633-
@test nextind(strs[i], -1, 1) == 0
634-
@test nextind(strs[i], -1, 2) == 1
635-
@test nextind(strs[i], -1, 3) == 4
636-
@test nextind(strs[i], 0, 2) == 4
637-
@test nextind(strs[i], 0, 20) == 26
638-
@test nextind(strs[i], 0, 10) == 15
639-
@test nextind(strs[i], 1) == 4
640-
@test nextind(strs[i], 1, 1) == 4
641-
@test nextind(strs[i], 1, 2) == 6
642-
@test nextind(strs[i], 1, 9) == 15
643-
@test nextind(strs[i], 1, 10) == 17
644-
@test nextind(strs[i], 2) == 4
645-
@test nextind(strs[i], 2, 1) == 4
646-
@test nextind(strs[i], 3) == 4
647-
@test nextind(strs[i], 3, 1) == 4
648-
@test nextind(strs[i], 4) == 6
649-
@test nextind(strs[i], 4, 1) == 6
650-
@test nextind(strs[i], 14) == 15
651-
@test nextind(strs[i], 14, 1) == 15
652-
@test nextind(strs[i], 15) == 17
653-
@test nextind(strs[i], 15, 1) == 17
654-
@test nextind(strs[i], 20) == 21
655-
@test nextind(strs[i], 20, 1) == 21
656-
@test nextind(strs[i], 20, 0) == 20
657-
658-
for x in -10:20
659-
n = p = x
660-
for j in 1:40
661-
p = prevind(strs[i], p)
662-
@test prevind(strs[i], x, j) == p
663-
n = nextind(strs[i], n)
664-
@test nextind(strs[i], x, j) == n
610+
for s in Any["∀α>β:α+1>β", GenericString("∀α>β:α+1>β")]
611+
@test_throws BoundsError prevind(s, 0)
612+
@test_throws BoundsError prevind(s, 0, 0)
613+
@test_throws BoundsError prevind(s, 0, 1)
614+
@test prevind(s, 1) == 0
615+
@test prevind(s, 1, 1) == 0
616+
@test prevind(s, 1, 0) == 1
617+
@test prevind(s, 2) == 1
618+
@test prevind(s, 2, 1) == 1
619+
@test prevind(s, 4) == 1
620+
@test prevind(s, 4, 1) == 1
621+
@test prevind(s, 5) == 4
622+
@test prevind(s, 5, 1) == 4
623+
@test prevind(s, 5, 2) == 1
624+
@test prevind(s, 5, 3) == 0
625+
@test prevind(s, 15) == 14
626+
@test prevind(s, 15, 1) == 14
627+
@test prevind(s, 15, 2) == 13
628+
@test prevind(s, 15, 3) == 12
629+
@test prevind(s, 15, 4) == 10
630+
@test prevind(s, 15, 10) == 0
631+
@test prevind(s, 15, 9) == 1
632+
@test prevind(s, 16) == 15
633+
@test prevind(s, 16, 1) == 15
634+
@test prevind(s, 16, 2) == 14
635+
@test prevind(s, 17) == 15
636+
@test prevind(s, 17, 1) == 15
637+
@test prevind(s, 17, 2) == 14
638+
@test_throws BoundsError prevind(s, 18)
639+
@test_throws BoundsError prevind(s, 18, 0)
640+
@test_throws BoundsError prevind(s, 18, 1)
641+
642+
@test_throws BoundsError nextind(s, -1)
643+
@test_throws BoundsError nextind(s, -1, 0)
644+
@test_throws BoundsError nextind(s, -1, 1)
645+
@test nextind(s, 0, 2) == 4
646+
@test nextind(s, 0, 20) == 26
647+
@test nextind(s, 0, 10) == 15
648+
@test nextind(s, 1) == 4
649+
@test nextind(s, 1, 1) == 4
650+
@test nextind(s, 1, 2) == 6
651+
@test nextind(s, 1, 9) == 15
652+
@test nextind(s, 1, 10) == 17
653+
@test nextind(s, 2) == 4
654+
@test nextind(s, 2, 1) == 4
655+
@test nextind(s, 3) == 4
656+
@test nextind(s, 3, 1) == 4
657+
@test nextind(s, 4) == 6
658+
@test nextind(s, 4, 1) == 6
659+
@test nextind(s, 14) == 15
660+
@test nextind(s, 14, 1) == 15
661+
@test nextind(s, 15) == 17
662+
@test nextind(s, 15, 1) == 17
663+
@test nextind(s, 15, 2) == 18
664+
@test nextind(s, 16) == 17
665+
@test nextind(s, 16, 1) == 17
666+
@test nextind(s, 16, 2) == 18
667+
@test nextind(s, 16, 3) == 19
668+
@test_throws BoundsError nextind(s, 17)
669+
@test_throws BoundsError nextind(s, 17, 0)
670+
@test_throws BoundsError nextind(s, 17, 1)
671+
672+
for x in 0:ncodeunits(s)+1
673+
n = p = x
674+
for j in 1:40
675+
if 1 p
676+
p = prevind(s, p)
677+
@test prevind(s, x, j) == p
678+
end
679+
if n  ncodeunits(s)
680+
n = nextind(s, n)
681+
@test nextind(s, x, j) == n
665682
end
666683
end
667684
end
668-
@test prevind(strs[1], -1) == -2
669-
@test prevind(strs[1], -1, 1) == -2
670-
671-
@test prevind(strs[2], -1) == -2
672-
@test prevind(strs[2], -1, 1) == -2
673685
end
674686
end
675687

0 commit comments

Comments
 (0)