diff libinterp/corefcn/oct-stream.cc @ 22996:36df0e0072a5 stable

distinguish elements vs. bytes in fread (bug #49699) * oct-stream.cc (get_size (double, ...)): Catch dimension overflow. Return octave_idx_type instead of int. (octave_stream::read): Use size_t to count bytes. Use ptrdiff_t to temporarily count elements, then check against octave_idx_type limits before copying data to output array.
author John W. Eaton <jwe@octave.org>
date Wed, 04 Jan 2017 15:23:40 -0500
parents 34ce5be04942
children ae6c01558d25 e9a0469dedd9
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc	Thu Dec 29 16:19:29 2016 -0800
+++ b/libinterp/corefcn/oct-stream.cc	Wed Jan 04 15:23:40 2017 -0500
@@ -112,10 +112,10 @@
   return retval;
 }
 
-static int
+static octave_idx_type
 get_size (double d, const std::string& who)
 {
-  int retval = -1;
+  octave_idx_type retval = -1;
 
   if (lo_ieee_isnan (d))
     ::error ("%s: NaN is invalid as size specification", who.c_str ());
@@ -128,7 +128,11 @@
         ::error ("%s: negative value invalid as size specification",
                  who.c_str ());
 
-      retval = octave::math::nint (d);
+      if (d > std::numeric_limits<octave_idx_type>::max ())
+        ::error ("%s: dimension too large for Octave's index type",
+                 who.c_str ());
+
+      retval = octave::math::nint_big (d);
     }
 
   return retval;
@@ -6466,9 +6470,9 @@
   // data_type enum in the oct_data_conv class.
 
   // Expose this in a future version?
-  octave_idx_type char_count = 0;
-
-  count = 0;
+  size_t char_count = 0;
+
+  ptrdiff_t tmp_count = 0;
 
   try
     {
@@ -6477,10 +6481,10 @@
   catch (const octave::execution_exception&)
     {
       invalid_operation ("fread", "reading");
+
+      return retval;
     }
 
-  octave_idx_type elts_to_read;
-
   if (one_elt_size_spec)
     {
       // If NR == 0, Matlab returns [](0x0).
@@ -6511,7 +6515,7 @@
   // FIXME: Ensure that this does not overflow.
   //        Maybe try comparing nr * nc computed in double with
   //        std::numeric_limits<octave_idx_type>::max ();
-  elts_to_read = nr * nc;
+  octave_idx_type elts_to_read = nr * nc;
 
   bool read_to_eof = elts_to_read < 0;
 
@@ -6530,7 +6534,8 @@
   octave_idx_type input_elt_size
     = oct_data_conv::data_type_size (input_type);
 
-  octave_idx_type input_buf_size = input_buf_elts * input_elt_size;
+  ptrdiff_t input_buf_size
+    = static_cast<ptrdiff_t> (input_buf_elts) * input_elt_size;
 
   assert (input_buf_size >= 0);
 
@@ -6547,11 +6552,11 @@
       std::list <void *> input_buf_list;
 
       while (is && ! is.eof ()
-             && (read_to_eof || count < elts_to_read))
+             && (read_to_eof || tmp_count < elts_to_read))
         {
           if (! read_to_eof)
             {
-              octave_idx_type remaining_elts = elts_to_read - count;
+              octave_idx_type remaining_elts = elts_to_read - tmp_count;
 
               if (remaining_elts < input_buf_elts)
                 input_buf_size = remaining_elts * input_elt_size;
@@ -6567,7 +6572,7 @@
 
           octave_idx_type nel = gcount / input_elt_size;
 
-          count += nel;
+          tmp_count += nel;
 
           input_buf_list.push_back (input_buf);
 
@@ -6602,30 +6607,35 @@
         {
           if (nc < 0)
             {
-              nc = count / nr;
-
-              if (count % nr != 0)
+              nc = tmp_count / nr;
+
+              if (tmp_count % nr != 0)
                 nc++;
             }
           else
-            nr = count;
+            nr = tmp_count;
         }
-      else if (count == 0)
+      else if (tmp_count == 0)
         {
           nr = 0;
           nc = 0;
         }
-      else if (count != nr * nc)
+      else if (tmp_count != nr * nc)
         {
-          if (count % nr != 0)
-            nc = count / nr + 1;
+          if (tmp_count % nr != 0)
+            nc = tmp_count / nr + 1;
           else
-            nc = count / nr;
-
-          if (count < nr)
-            nr = count;
+            nc = tmp_count / nr;
+
+          if (tmp_count < nr)
+            nr = tmp_count;
         }
 
+      if (tmp_count > std::numeric_limits<octave_idx_type>::max ())
+        error ("fread: number of elements read exceeds max index size");
+      else
+        count = static_cast<octave_idx_type> (tmp_count);
+
       retval = finalize_read (input_buf_list, input_buf_elts, count,
                               nr, nc, input_type, output_type, ffmt);
     }