changeset 21256:a93fa1b0796e stable

Avoid overflow while reshaping large sparse matrices (bug #42850). * Sparse.cc (reshape): track quotient and remainder of (i*old_nr) divided by new_nr, instead of evaluating i*old_nr explicitly.
author Lachlan Andrew <lachlanbis@gmail.com>
date Sat, 16 Jan 2016 14:03:45 +1100
parents 6209f428426c
children af8118df8292 8990b8c4f00a
files liboctave/array/Sparse.cc
diffstat 1 files changed, 28 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/array/Sparse.cc	Sat Jan 09 20:40:49 2016 +1100
+++ b/liboctave/array/Sparse.cc	Sat Jan 16 14:03:45 2016 +1100
@@ -842,22 +842,35 @@
 
           octave_idx_type kk = 0;
           retval.xcidx (0) = 0;
+          // quotient and remainder of  i * old_nr divided by new_nr
+          // Track them individually to avoid overflow (bug #42850).
+          octave_idx_type i_old_qu = 0;
+          octave_idx_type i_old_rm = static_cast<octave_idx_type> (-old_nr);
           for (octave_idx_type i = 0; i < old_nc; i++)
-            for (octave_idx_type j = cidx (i); j < cidx (i+1); j++)
-              {
-                octave_idx_type tmp = i * old_nr + ridx (j);
-                if (tmp < 0)
-                  (*current_liboctave_error_handler)
-                    ("reshape: overflow in octave_idx_type prevents reshaping array");
-
-                octave_idx_type ii = tmp % new_nr;
-                octave_idx_type jj = (tmp - ii) / new_nr;
-                for (octave_idx_type k = kk; k < jj; k++)
-                  retval.xcidx (k+1) = j;
-                kk = jj;
-                retval.xdata (j) = data (j);
-                retval.xridx (j) = ii;
-              }
+            {
+              i_old_rm += old_nr;
+              if (i_old_rm >= new_nr)
+                {
+                  i_old_qu += i_old_rm / new_nr;
+                  i_old_rm = i_old_rm % new_nr;
+                }
+              for (octave_idx_type j = cidx (i); j < cidx (i+1); j++)
+                {
+                  octave_idx_type ii, jj;
+                  ii = (i_old_rm + ridx (j)) % new_nr;
+                  jj = i_old_qu + (i_old_rm + ridx (j)) / new_nr;
+
+                  // Original calculation subject to overflow
+                  // ii = (i*old_nr + ridx (j)) % new_nr
+                  // jj = (i*old_nr + ridx (j)) / new_nr
+
+                  for (octave_idx_type k = kk; k < jj; k++)
+                    retval.xcidx (k+1) = j;
+                  kk = jj;
+                  retval.xdata (j) = data (j);
+                  retval.xridx (j) = ii;
+                }
+            }
           for (octave_idx_type k = kk; k < new_nc; k++)
             retval.xcidx (k+1) = new_nnz;
         }