Skip to content

Fix bounds checking for certain sparse matrix cases #9864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,6 @@ function getindex_cols{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, J::AbstractVector)
# for indexing whole columns
(m, n) = size(A)
nJ = length(J)
nJ == 0 || maximum(J) <= n || throw(BoundsError())

colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval

Expand All @@ -905,6 +904,7 @@ function getindex_cols{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, J::AbstractVector)

@inbounds for j = 1:nJ
col = J[j]
1 <= col <= n || throw(BoundsError())
nnzS += colptrA[col+1] - colptrA[col]
colptrS[j+1] = nnzS + 1
end
Expand Down Expand Up @@ -933,19 +933,21 @@ function getindex{Tv,Ti<:Integer}(A::SparseMatrixCSC{Tv,Ti}, I::Range, J::Abstra
end

nI = length(I)
nI == 0 || (minimum(I) >= 1 && maximum(I) <= m) || throw(BoundsError())
nJ = length(J)
colptrA = A.colptr; rowvalA = A.rowval; nzvalA = A.nzval
colptrS = Array(Ti, nJ+1)
colptrS[1] = 1
nnzS = 0

# Form the structure of the result and compute space
for j = 1:nJ
@inbounds col = J[j]
@inbounds for j = 1:nJ
col = J[j]
1 <= col <= n || throw(BoundsError())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may not be required as colptrA[co+1] in the for loop condition would have done the check. Alternatively, we can probably have this check and mark the outer for loop @inbounds?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The colptrA access throws a BoundsError, but since #9534 the error message is more confusing than helpful:

julia> sparse(zeros(5, 5))[1:2, 5:6]
ERROR: BoundsError: attempt to access 6-element Array{Int64,1}:
 1
 1
 1
 1
 1
 1
  at index [7]
 in getindex at sparse/sparsematrix.jl:49

I think the extra @inbounds should be fine.

@simd for k in colptrA[col]:colptrA[col+1]-1
if rowvalA[k] in I; nnzS += 1 end # `in` is fast for ranges
nnzS += rowvalA[k] in I # `in` is fast for ranges
end
@inbounds colptrS[j+1] = nnzS+1
colptrS[j+1] = nnzS+1
end

# Populate the values in the result
Expand Down
18 changes: 18 additions & 0 deletions test/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,24 @@ for (aa116, ss116) in [(a116, s116), (ad116, sd116)]
@test full(ss116[li,empty]) == aa116[li,empty]
@test full(ss116[empty,empty]) == aa116[empty,empty]
end

# out of bounds indexing
@test_throws BoundsError ss116[0, 1]
@test_throws BoundsError ss116[end+1, 1]
@test_throws BoundsError ss116[1, 0]
@test_throws BoundsError ss116[1, end+1]
for j in (1, 1:size(s116,2), 1:1, Int[1], trues(size(s116, 2)), 1:0, Int[])
@test_throws BoundsError ss116[0:1, j]
@test_throws BoundsError ss116[[0, 1], j]
@test_throws BoundsError ss116[end:end+1, j]
@test_throws BoundsError ss116[[end, end+1], j]
end
for i in (1, 1:size(s116,1), 1:1, Int[1], trues(size(s116, 1)), 1:0, Int[])
@test_throws BoundsError ss116[i, 0:1]
@test_throws BoundsError ss116[i, [0, 1]]
@test_throws BoundsError ss116[i, end:end+1]
@test_throws BoundsError ss116[i, [end, end+1]]
end
end

# workaround issue #7197: comment out let-block
Expand Down