Skip to content

Commit 3da897b

Browse files
authored
Don't access uninitialized indices in tril!/triu! for numeric arrays (#52528)
This specializes the generic `triu!` and `tril!` methods for arrays of numbers, where a zero is known to exist. In such cases, we don't need to read the possibly uninitialized values of the elements at the indices that are to be assigned to. After this, the following would be possible: ```julia julia> M = Matrix{BigFloat}(undef, 3, 3) 3×3 Matrix{BigFloat}: #undef #undef #undef #undef #undef #undef #undef #undef #undef julia> triu!(M) 3×3 Matrix{BigFloat}: #undef #undef #undef 0.0 #undef #undef 0.0 0.0 #undef ```
1 parent ca7b9c3 commit 3da897b

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

stdlib/LinearAlgebra/src/dense.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ norm1(x::Union{Array{T},StridedVector{T}}) where {T<:BlasReal} =
106106
norm2(x::Union{Array{T},StridedVector{T}}) where {T<:BlasFloat} =
107107
length(x) < NRM2_CUTOFF ? generic_norm2(x) : BLAS.nrm2(x)
108108

109+
# Conservative assessment of types that have zero(T) defined for themselves
110+
haszero(::Type) = false
111+
haszero(::Type{T}) where {T<:Number} = isconcretetype(T)
112+
@propagate_inbounds _zero(M::AbstractArray{T}, i, j) where {T} = haszero(T) ? zero(T) : zero(M[i,j])
113+
109114
"""
110115
triu!(M, k::Integer)
111116
@@ -136,7 +141,7 @@ function triu!(M::AbstractMatrix, k::Integer)
136141
m, n = size(M)
137142
for j in 1:min(n, m + k)
138143
for i in max(1, j - k + 1):m
139-
@inbounds M[i,j] = zero(M[i,j])
144+
@inbounds M[i,j] = _zero(M, i,j)
140145
end
141146
end
142147
M
@@ -173,12 +178,13 @@ function tril!(M::AbstractMatrix, k::Integer)
173178
require_one_based_indexing(M)
174179
m, n = size(M)
175180
for j in max(1, k + 1):n
176-
@inbounds for i in 1:min(j - k - 1, m)
177-
M[i,j] = zero(M[i,j])
181+
for i in 1:min(j - k - 1, m)
182+
@inbounds M[i,j] = _zero(M, i,j)
178183
end
179184
end
180185
M
181186
end
187+
182188
tril(M::Matrix, k::Integer) = tril!(copy(M), k)
183189

184190
"""

stdlib/LinearAlgebra/test/triangular.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,35 @@ end
897897
end
898898
end
899899

900+
@testset "tril!/triu! for non-bitstype matrices" begin
901+
@testset "numeric" begin
902+
M = Matrix{BigFloat}(undef, 3, 3)
903+
tril!(M)
904+
L = LowerTriangular(ones(3,3))
905+
copytrito!(M, L, 'L')
906+
@test M == L
907+
908+
M = Matrix{BigFloat}(undef, 3, 3)
909+
triu!(M)
910+
U = UpperTriangular(ones(3,3))
911+
copytrito!(M, U, 'U')
912+
@test M == U
913+
end
914+
@testset "array elements" begin
915+
M = fill(ones(2,2), 4, 4)
916+
tril!(M)
917+
L = LowerTriangular(fill(fill(2,2,2),4,4))
918+
copytrito!(M, L, 'L')
919+
@test M == L
920+
921+
M = fill(ones(2,2), 4, 4)
922+
triu!(M)
923+
U = UpperTriangular(fill(fill(2,2,2),4,4))
924+
copytrito!(M, U, 'U')
925+
@test M == U
926+
end
927+
end
928+
900929
@testset "avoid matmul ambiguities with ::MyMatrix * ::AbstractMatrix" begin
901930
A = [i+j for i in 1:2, j in 1:2]
902931
S = SizedArrays.SizedArray{(2,2)}(A)

0 commit comments

Comments
 (0)