Skip to content

Commit 8de25f5

Browse files
bounds check thisind, nextind and prevind as well
1 parent feb1f68 commit 8de25f5

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
@@ -512,7 +512,8 @@ end
512512
SubString("123∀α>β:α+1>β123", 4, 18),
513513
SubString(s"123∀α>β:α+1>β123", 4, 18)]
514514
for s in strs
515-
@test thisind(s, -2) == -2
515+
@test_throws BoundsError thisind(s, -2)
516+
@test_throws BoundsError thisind(s, -1)
516517
@test thisind(s, 0) == 0
517518
@test thisind(s, 1) == 1
518519
@test thisind(s, 2) == 1
@@ -523,86 +524,97 @@ end
523524
@test thisind(s, 15) == 15
524525
@test thisind(s, 16) == 15
525526
@test thisind(s, 17) == 17
526-
@test thisind(s, 30) == 30
527+
@test_throws BoundsError thisind(s, 18)
528+
@test_throws BoundsError thisind(s, 19)
527529
end
528530
end
529531

530532
let strs = Any["", s"", SubString("123", 2, 1), SubString(s"123", 2, 1)]
531-
for s in strs, i in -2:2
532-
@test thisind(s, i) == i
533+
for s in strs
534+
@test_throws BoundsError thisind(s, -1)
535+
@test thisind(s, 0) == 0
536+
@test thisind(s, 1) == 1
537+
@test_throws BoundsError thisind(s, 2)
533538
end
534539
end
535540
end
536541

537542
@testset "prevind and nextind" begin
538-
let strs = Any["∀α>β:α+1>β", GenericString("∀α>β:α+1>β")]
539-
for i in 1:2
540-
@test prevind(strs[i], 1) == 0
541-
@test prevind(strs[i], 1, 1) == 0
542-
@test prevind(strs[i], 2) == 1
543-
@test prevind(strs[i], 2, 1) == 1
544-
@test prevind(strs[i], 4) == 1
545-
@test prevind(strs[i], 4, 1) == 1
546-
@test prevind(strs[i], 5) == 4
547-
@test prevind(strs[i], 5, 1) == 4
548-
@test prevind(strs[i], 5, 2) == 1
549-
@test prevind(strs[i], 5, 3) == 0
550-
@test prevind(strs[i], 15) == 14
551-
@test prevind(strs[i], 15, 1) == 14
552-
@test prevind(strs[i], 15, 2) == 13
553-
@test prevind(strs[i], 15, 3) == 12
554-
@test prevind(strs[i], 15, 4) == 10
555-
@test prevind(strs[i], 15, 10) == 0
556-
@test prevind(strs[i], 15, 9) == 1
557-
@test prevind(strs[i], 16) == 15
558-
@test prevind(strs[i], 16, 1) == 15
559-
@test prevind(strs[i], 16, 2) == 14
560-
@test prevind(strs[i], 20) == 19
561-
@test prevind(strs[i], 20, 1) == 19
562-
@test prevind(strs[i], 20, 10) == 7
563-
@test prevind(strs[i], 20, 0) == 20
564-
565-
@test nextind(strs[i], -1) == 0
566-
@test nextind(strs[i], -1, 1) == 0
567-
@test nextind(strs[i], -1, 2) == 1
568-
@test nextind(strs[i], -1, 3) == 4
569-
@test nextind(strs[i], 0, 2) == 4
570-
@test nextind(strs[i], 0, 20) == 26
571-
@test nextind(strs[i], 0, 10) == 15
572-
@test nextind(strs[i], 1) == 4
573-
@test nextind(strs[i], 1, 1) == 4
574-
@test nextind(strs[i], 1, 2) == 6
575-
@test nextind(strs[i], 1, 9) == 15
576-
@test nextind(strs[i], 1, 10) == 17
577-
@test nextind(strs[i], 2) == 4
578-
@test nextind(strs[i], 2, 1) == 4
579-
@test nextind(strs[i], 3) == 4
580-
@test nextind(strs[i], 3, 1) == 4
581-
@test nextind(strs[i], 4) == 6
582-
@test nextind(strs[i], 4, 1) == 6
583-
@test nextind(strs[i], 14) == 15
584-
@test nextind(strs[i], 14, 1) == 15
585-
@test nextind(strs[i], 15) == 17
586-
@test nextind(strs[i], 15, 1) == 17
587-
@test nextind(strs[i], 20) == 21
588-
@test nextind(strs[i], 20, 1) == 21
589-
@test nextind(strs[i], 20, 0) == 20
590-
591-
for x in -10:20
592-
n = p = x
593-
for j in 1:40
594-
p = prevind(strs[i], p)
595-
@test prevind(strs[i], x, j) == p
596-
n = nextind(strs[i], n)
597-
@test nextind(strs[i], x, j) == n
543+
for s in Any["∀α>β:α+1>β", GenericString("∀α>β:α+1>β")]
544+
@test_throws BoundsError prevind(s, 0)
545+
@test_throws BoundsError prevind(s, 0, 0)
546+
@test_throws BoundsError prevind(s, 0, 1)
547+
@test prevind(s, 1) == 0
548+
@test prevind(s, 1, 1) == 0
549+
@test prevind(s, 1, 0) == 1
550+
@test prevind(s, 2) == 1
551+
@test prevind(s, 2, 1) == 1
552+
@test prevind(s, 4) == 1
553+
@test prevind(s, 4, 1) == 1
554+
@test prevind(s, 5) == 4
555+
@test prevind(s, 5, 1) == 4
556+
@test prevind(s, 5, 2) == 1
557+
@test prevind(s, 5, 3) == 0
558+
@test prevind(s, 15) == 14
559+
@test prevind(s, 15, 1) == 14
560+
@test prevind(s, 15, 2) == 13
561+
@test prevind(s, 15, 3) == 12
562+
@test prevind(s, 15, 4) == 10
563+
@test prevind(s, 15, 10) == 0
564+
@test prevind(s, 15, 9) == 1
565+
@test prevind(s, 16) == 15
566+
@test prevind(s, 16, 1) == 15
567+
@test prevind(s, 16, 2) == 14
568+
@test prevind(s, 17) == 15
569+
@test prevind(s, 17, 1) == 15
570+
@test prevind(s, 17, 2) == 14
571+
@test_throws BoundsError prevind(s, 18)
572+
@test_throws BoundsError prevind(s, 18, 0)
573+
@test_throws BoundsError prevind(s, 18, 1)
574+
575+
@test_throws BoundsError nextind(s, -1)
576+
@test_throws BoundsError nextind(s, -1, 0)
577+
@test_throws BoundsError nextind(s, -1, 1)
578+
@test nextind(s, 0, 2) == 4
579+
@test nextind(s, 0, 20) == 26
580+
@test nextind(s, 0, 10) == 15
581+
@test nextind(s, 1) == 4
582+
@test nextind(s, 1, 1) == 4
583+
@test nextind(s, 1, 2) == 6
584+
@test nextind(s, 1, 9) == 15
585+
@test nextind(s, 1, 10) == 17
586+
@test nextind(s, 2) == 4
587+
@test nextind(s, 2, 1) == 4
588+
@test nextind(s, 3) == 4
589+
@test nextind(s, 3, 1) == 4
590+
@test nextind(s, 4) == 6
591+
@test nextind(s, 4, 1) == 6
592+
@test nextind(s, 14) == 15
593+
@test nextind(s, 14, 1) == 15
594+
@test nextind(s, 15) == 17
595+
@test nextind(s, 15, 1) == 17
596+
@test nextind(s, 15, 2) == 18
597+
@test nextind(s, 16) == 17
598+
@test nextind(s, 16, 1) == 17
599+
@test nextind(s, 16, 2) == 18
600+
@test nextind(s, 16, 3) == 19
601+
@test_throws BoundsError nextind(s, 17)
602+
@test_throws BoundsError nextind(s, 17, 0)
603+
@test_throws BoundsError nextind(s, 17, 1)
604+
605+
for x in 0:ncodeunits(s)+1
606+
n = p = x
607+
for j in 1:40
608+
if 1 p
609+
p = prevind(s, p)
610+
@test prevind(s, x, j) == p
611+
end
612+
if n  ncodeunits(s)
613+
n = nextind(s, n)
614+
@test nextind(s, x, j) == n
598615
end
599616
end
600617
end
601-
@test prevind(strs[1], -1) == -2
602-
@test prevind(strs[1], -1, 1) == -2
603-
604-
@test prevind(strs[2], -1) == -2
605-
@test prevind(strs[2], -1, 1) == -2
606618
end
607619
end
608620

0 commit comments

Comments
 (0)