Skip to content

Commit 3dedc52

Browse files
mbaumanlazarusA
authored andcommitted
mapreduce: don't inbounds unknown functions (JuliaLang#55329)
More finely scope the `@inbounds` annotations to ensure neither `f` nor `op` are erroneously `@inbounds`ed.
1 parent 7545b18 commit 3dedc52

File tree

3 files changed

+48
-23
lines changed

3 files changed

+48
-23
lines changed

base/reduce.jl

+5-5
Original file line numberDiff line numberDiff line change
@@ -638,11 +638,11 @@ function mapreduce_impl(f, op::Union{typeof(max), typeof(min)},
638638
start = first + 1
639639
simdstop = start + chunk_len - 4
640640
while simdstop <= last - 3
641-
@inbounds for i in start:4:simdstop
642-
v1 = _fast(op, v1, f(A[i+0]))
643-
v2 = _fast(op, v2, f(A[i+1]))
644-
v3 = _fast(op, v3, f(A[i+2]))
645-
v4 = _fast(op, v4, f(A[i+3]))
641+
for i in start:4:simdstop
642+
v1 = _fast(op, v1, f(@inbounds(A[i+0])))
643+
v2 = _fast(op, v2, f(@inbounds(A[i+1])))
644+
v3 = _fast(op, v3, f(@inbounds(A[i+2])))
645+
v4 = _fast(op, v4, f(@inbounds(A[i+3])))
646646
end
647647
checkbounds(A, simdstop+3)
648648
start += chunk_len

base/reducedim.jl

+19-18
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,20 @@ function _mapreducedim!(f, op, R::AbstractArray, A::AbstractArrayOrBroadcasted)
269269
if reducedim1(R, A)
270270
# keep the accumulator as a local variable when reducing along the first dimension
271271
i1 = first(axes1(R))
272-
@inbounds for IA in CartesianIndices(indsAt)
272+
for IA in CartesianIndices(indsAt)
273273
IR = Broadcast.newindex(IA, keep, Idefault)
274-
r = R[i1,IR]
274+
@inbounds r = R[i1,IR]
275275
@simd for i in axes(A, 1)
276-
r = op(r, f(A[i, IA]))
276+
r = op(r, f(@inbounds(A[i, IA])))
277277
end
278-
R[i1,IR] = r
278+
@inbounds R[i1,IR] = r
279279
end
280280
else
281-
@inbounds for IA in CartesianIndices(indsAt)
281+
for IA in CartesianIndices(indsAt)
282282
IR = Broadcast.newindex(IA, keep, Idefault)
283283
@simd for i in axes(A, 1)
284-
R[i,IR] = op(R[i,IR], f(A[i,IA]))
284+
v = op(@inbounds(R[i,IR]), f(@inbounds(A[i,IA])))
285+
@inbounds R[i,IR] = v
285286
end
286287
end
287288
end
@@ -1025,33 +1026,33 @@ function findminmax!(f, op, Rval, Rind, A::AbstractArray{T,N}) where {T,N}
10251026
zi = zero(eltype(ks))
10261027
if reducedim1(Rval, A)
10271028
i1 = first(axes1(Rval))
1028-
@inbounds for IA in CartesianIndices(indsAt)
1029+
for IA in CartesianIndices(indsAt)
10291030
IR = Broadcast.newindex(IA, keep, Idefault)
1030-
tmpRv = Rval[i1,IR]
1031-
tmpRi = Rind[i1,IR]
1031+
@inbounds tmpRv = Rval[i1,IR]
1032+
@inbounds tmpRi = Rind[i1,IR]
10321033
for i in axes(A,1)
10331034
k, kss = y::Tuple
1034-
tmpAv = f(A[i,IA])
1035+
tmpAv = f(@inbounds(A[i,IA]))
10351036
if tmpRi == zi || op(tmpRv, tmpAv)
10361037
tmpRv = tmpAv
10371038
tmpRi = k
10381039
end
10391040
y = iterate(ks, kss)
10401041
end
1041-
Rval[i1,IR] = tmpRv
1042-
Rind[i1,IR] = tmpRi
1042+
@inbounds Rval[i1,IR] = tmpRv
1043+
@inbounds Rind[i1,IR] = tmpRi
10431044
end
10441045
else
1045-
@inbounds for IA in CartesianIndices(indsAt)
1046+
for IA in CartesianIndices(indsAt)
10461047
IR = Broadcast.newindex(IA, keep, Idefault)
10471048
for i in axes(A, 1)
10481049
k, kss = y::Tuple
1049-
tmpAv = f(A[i,IA])
1050-
tmpRv = Rval[i,IR]
1051-
tmpRi = Rind[i,IR]
1050+
tmpAv = f(@inbounds(A[i,IA]))
1051+
@inbounds tmpRv = Rval[i,IR]
1052+
@inbounds tmpRi = Rind[i,IR]
10521053
if tmpRi == zi || op(tmpRv, tmpAv)
1053-
Rval[i,IR] = tmpAv
1054-
Rind[i,IR] = k
1054+
@inbounds Rval[i,IR] = tmpAv
1055+
@inbounds Rind[i,IR] = k
10551056
end
10561057
y = iterate(ks, kss)
10571058
end

test/reducedim.jl

+24
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,30 @@ end
587587
@test B[argmin(B, dims=[2, 3])] == @inferred(minimum(B, dims=[2, 3]))
588588
end
589589

590+
@testset "careful with @inbounds" begin
591+
Base.@propagate_inbounds f(x) = x == 2 ? x[-10000] : x
592+
Base.@propagate_inbounds op(x,y) = x[-10000] + y[-10000]
593+
for (arr, dims) in (([1,1,2], 1), ([1 1 2], 2), ([ones(Int,256);2], 1))
594+
@test_throws BoundsError mapreduce(f, +, arr)
595+
@test_throws BoundsError mapreduce(f, +, arr; dims)
596+
@test_throws BoundsError mapreduce(f, +, arr; dims, init=0)
597+
@test_throws BoundsError mapreduce(identity, op, arr)
598+
try
599+
#=@test_throws BoundsError=# mapreduce(identity, op, arr; dims)
600+
catch ex
601+
@test_broken ex isa BoundsError
602+
end
603+
@test_throws BoundsError mapreduce(identity, op, arr; dims, init=0)
604+
605+
@test_throws BoundsError findmin(f, arr)
606+
@test_throws BoundsError findmin(f, arr; dims)
607+
608+
@test_throws BoundsError mapreduce(f, max, arr)
609+
@test_throws BoundsError mapreduce(f, max, arr; dims)
610+
@test_throws BoundsError mapreduce(f, max, arr; dims, init=0)
611+
end
612+
end
613+
590614
@testset "in-place reductions with mismatched dimensionalities" begin
591615
B = reshape(1:24, 4, 3, 2)
592616
for R in (fill(0, 4), fill(0, 4, 1), fill(0, 4, 1, 1))

0 commit comments

Comments
 (0)