Skip to content
This repository
Browse code

BUG: sparse/arpack: fix an out-of-bounds memory write bug in ARPACK

For small matrices, ARPACK's S/DNAUP2 could crash for some starting
vectors, when its stagnation avoidance heuristics would make NEV too
large.

Apparently, it was forgotten in the heuristics that a call to S/DNGETS
following the NEV adjustment could in some rare cases increase NEV by 1,
leading to out-of-bounds memory write in the next iteration.
  • Loading branch information...
commit 1857a29d2b313cfe2b18e191eb1fef49273719cc 1 parent 266a36f
Pauli Virtanen authored June 14, 2011
12  scipy/sparse/linalg/eigen/arpack/ARPACK/SRC/dnaup2.f
@@ -664,6 +664,18 @@ subroutine dnaup2
664 664
             else if (nev .eq. 1 .and. kplusp .gt. 3) then
665 665
                nev = 2
666 666
             end if
  667
+c
  668
+c           %---- Scipy fix ------------------------------------------------
  669
+c           | We must keep nev below this value, as otherwise we can get
  670
+c           | np == 0 (note that dngets below can bump nev by 1). If np == 0,
  671
+c           | the next call to `dnaitr` will write out-of-bounds.
  672
+c           |
  673
+            if (nev .gt. kplusp - 2) then
  674
+               nev = kplusp - 2
  675
+            end if
  676
+c           |
  677
+c           %---- Scipy fix end --------------------------------------------
  678
+c
667 679
             np = kplusp - nev
668 680
 c     
669 681
 c           %---------------------------------------%
12  scipy/sparse/linalg/eigen/arpack/ARPACK/SRC/snaup2.f
@@ -664,6 +664,18 @@ subroutine snaup2
664 664
             else if (nev .eq. 1 .and. kplusp .gt. 3) then
665 665
                nev = 2
666 666
             end if
  667
+c
  668
+c           %---- Scipy fix ------------------------------------------------
  669
+c           | We must keep nev below this value, as otherwise we can get
  670
+c           | np == 0 (note that sngets below can bump nev by 1). If np == 0,
  671
+c           | the next call to `snaitr` will write out-of-bounds.
  672
+c           |
  673
+            if (nev .gt. kplusp - 2) then
  674
+               nev = kplusp - 2
  675
+            end if
  676
+c           |
  677
+c           %---- Scipy fix end --------------------------------------------
  678
+c
667 679
             np = kplusp - nev
668 680
 c     
669 681
 c           %---------------------------------------%
17  scipy/sparse/linalg/eigen/arpack/tests/test_arpack.py
@@ -359,6 +359,23 @@ def test_eigen_bad_kwargs():
359 359
     A = csc_matrix(np.zeros((2,2)))
360 360
     assert_raises(ValueError, eigs, A, which='XX')
361 361
 
  362
+def test_ticket_1459_arpack_crash():
  363
+    for dtype in [np.float32, np.float64]:
  364
+        # XXX: this test does not seem to catch the issue for float32,
  365
+        #      but we made the same fix there, just to be sure
  366
+
  367
+        N = 6
  368
+        k = 2
  369
+
  370
+        np.random.seed(2301)
  371
+        A = np.random.random((N, N)).astype(dtype)
  372
+        v0 = np.array([-0.71063568258907849895, -0.83185111795729227424,
  373
+                       -0.34365925382227402451, 0.46122533684552280420,
  374
+                       -0.58001341115969040629, -0.78844877570084292984e-01],
  375
+                      dtype=dtype)
  376
+
  377
+        # Should not crash:
  378
+        evals, evecs = eigs(A, k, v0=v0)
362 379
 
363 380
 def test_eigs_operator():
364 381
     # Check inferring LinearOperator dtype

0 notes on commit 1857a29

Please sign in to comment.
Something went wrong with that request. Please try again.