Skip to content

Commit 21ccfc0

Browse files
mbaumanKristofferC
authored andcommitted
mapreduce: don't inbounds unknown functions (#55329)
More finely scope the `@inbounds` annotations to ensure neither `f` nor `op` are erroneously `@inbounds`ed. (cherry picked from commit 1dffd77)
1 parent 6f3fdf7 commit 21ccfc0

File tree

3 files changed

+48
-23
lines changed

3 files changed

+48
-23
lines changed

base/reduce.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,11 @@ function mapreduce_impl(f, op::Union{typeof(max), typeof(min)},
649649
start = first + 1
650650
simdstop = start + chunk_len - 4
651651
while simdstop <= last - 3
652-
@inbounds for i in start:4:simdstop
653-
v1 = _fast(op, v1, f(A[i+0]))
654-
v2 = _fast(op, v2, f(A[i+1]))
655-
v3 = _fast(op, v3, f(A[i+2]))
656-
v4 = _fast(op, v4, f(A[i+3]))
652+
for i in start:4:simdstop
653+
v1 = _fast(op, v1, f(@inbounds(A[i+0])))
654+
v2 = _fast(op, v2, f(@inbounds(A[i+1])))
655+
v3 = _fast(op, v3, f(@inbounds(A[i+2])))
656+
v4 = _fast(op, v4, f(@inbounds(A[i+3])))
657657
end
658658
checkbounds(A, simdstop+3)
659659
start += chunk_len

base/reducedim.jl

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -302,19 +302,20 @@ function _mapreducedim!(f, op, R::AbstractArray, A::AbstractArrayOrBroadcasted)
302302
if reducedim1(R, A)
303303
# keep the accumulator as a local variable when reducing along the first dimension
304304
i1 = first(axes1(R))
305-
@inbounds for IA in CartesianIndices(indsAt)
305+
for IA in CartesianIndices(indsAt)
306306
IR = Broadcast.newindex(IA, keep, Idefault)
307-
r = R[i1,IR]
307+
@inbounds r = R[i1,IR]
308308
@simd for i in axes(A, 1)
309-
r = op(r, f(A[i, IA]))
309+
r = op(r, f(@inbounds(A[i, IA])))
310310
end
311-
R[i1,IR] = r
311+
@inbounds R[i1,IR] = r
312312
end
313313
else
314-
@inbounds for IA in CartesianIndices(indsAt)
314+
for IA in CartesianIndices(indsAt)
315315
IR = Broadcast.newindex(IA, keep, Idefault)
316316
@simd for i in axes(A, 1)
317-
R[i,IR] = op(R[i,IR], f(A[i,IA]))
317+
v = op(@inbounds(R[i,IR]), f(@inbounds(A[i,IA])))
318+
@inbounds R[i,IR] = v
318319
end
319320
end
320321
end
@@ -1058,33 +1059,33 @@ function findminmax!(f, op, Rval, Rind, A::AbstractArray{T,N}) where {T,N}
10581059
zi = zero(eltype(ks))
10591060
if reducedim1(Rval, A)
10601061
i1 = first(axes1(Rval))
1061-
@inbounds for IA in CartesianIndices(indsAt)
1062+
for IA in CartesianIndices(indsAt)
10621063
IR = Broadcast.newindex(IA, keep, Idefault)
1063-
tmpRv = Rval[i1,IR]
1064-
tmpRi = Rind[i1,IR]
1064+
@inbounds tmpRv = Rval[i1,IR]
1065+
@inbounds tmpRi = Rind[i1,IR]
10651066
for i in axes(A,1)
10661067
k, kss = y::Tuple
1067-
tmpAv = f(A[i,IA])
1068+
tmpAv = f(@inbounds(A[i,IA]))
10681069
if tmpRi == zi || op(tmpRv, tmpAv)
10691070
tmpRv = tmpAv
10701071
tmpRi = k
10711072
end
10721073
y = iterate(ks, kss)
10731074
end
1074-
Rval[i1,IR] = tmpRv
1075-
Rind[i1,IR] = tmpRi
1075+
@inbounds Rval[i1,IR] = tmpRv
1076+
@inbounds Rind[i1,IR] = tmpRi
10761077
end
10771078
else
1078-
@inbounds for IA in CartesianIndices(indsAt)
1079+
for IA in CartesianIndices(indsAt)
10791080
IR = Broadcast.newindex(IA, keep, Idefault)
10801081
for i in axes(A, 1)
10811082
k, kss = y::Tuple
1082-
tmpAv = f(A[i,IA])
1083-
tmpRv = Rval[i,IR]
1084-
tmpRi = Rind[i,IR]
1083+
tmpAv = f(@inbounds(A[i,IA]))
1084+
@inbounds tmpRv = Rval[i,IR]
1085+
@inbounds tmpRi = Rind[i,IR]
10851086
if tmpRi == zi || op(tmpRv, tmpAv)
1086-
Rval[i,IR] = tmpAv
1087-
Rind[i,IR] = k
1087+
@inbounds Rval[i,IR] = tmpAv
1088+
@inbounds Rind[i,IR] = k
10881089
end
10891090
y = iterate(ks, kss)
10901091
end

test/reducedim.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,30 @@ end
575575
@test B[argmin(B, dims=[2, 3])] == @inferred(minimum(B, dims=[2, 3]))
576576
end
577577

578+
@testset "careful with @inbounds" begin
579+
Base.@propagate_inbounds f(x) = x == 2 ? x[-10000] : x
580+
Base.@propagate_inbounds op(x,y) = x[-10000] + y[-10000]
581+
for (arr, dims) in (([1,1,2], 1), ([1 1 2], 2), ([ones(Int,256);2], 1))
582+
@test_throws BoundsError mapreduce(f, +, arr)
583+
@test_throws BoundsError mapreduce(f, +, arr; dims)
584+
@test_throws BoundsError mapreduce(f, +, arr; dims, init=0)
585+
@test_throws BoundsError mapreduce(identity, op, arr)
586+
try
587+
#=@test_throws BoundsError=# mapreduce(identity, op, arr; dims)
588+
catch ex
589+
@test_broken ex isa BoundsError
590+
end
591+
@test_throws BoundsError mapreduce(identity, op, arr; dims, init=0)
592+
593+
@test_throws BoundsError findmin(f, arr)
594+
@test_throws BoundsError findmin(f, arr; dims)
595+
596+
@test_throws BoundsError mapreduce(f, max, arr)
597+
@test_throws BoundsError mapreduce(f, max, arr; dims)
598+
@test_throws BoundsError mapreduce(f, max, arr; dims, init=0)
599+
end
600+
end
601+
578602
@testset "in-place reductions with mismatched dimensionalities" begin
579603
B = reshape(1:24, 4, 3, 2)
580604
for R in (fill(0, 4), fill(0, 4, 1), fill(0, 4, 1, 1))

0 commit comments

Comments
 (0)