Mercurial > octave
changeset 23323:31be59137160 stable
Don't error out if RANGE specification for dlmread contains large values.
* dlmread.cc (idx_max): Redefine static const variable that holds the maximum
row or column idx for a range specification to be max octave_idx_type - 1.
* dlmread.cc (idx_max_dbl): New static const variable that holds the maximum
possible row or column idx for a range specification as a double value.
* dlmread.cc (parse_range_spec): Use new idx_max constant.
Use std::min (x, idx_max_dbl) to eliminate overflow when casting double to
octave_idx_type.
* dlmread.cc (Fdlmread): Use new idx_max constant. After parsing range
specification, return an empty matrix immediately if range is empty. When
skipping lines at beginning of file, look at both the number of lines to skip
and the output of getline; The EOF may be reached before the number of lines to
skip.
author | Rik <rik@octave.org> |
---|---|
date | Tue, 21 Mar 2017 23:15:53 -0700 |
parents | fc344de3afc9 |
children | 336f2e8331fa |
files | libinterp/corefcn/dlmread.cc |
diffstat | 1 files changed, 27 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/dlmread.cc Tue Mar 21 08:32:44 2017 -0400 +++ b/libinterp/corefcn/dlmread.cc Tue Mar 21 23:15:53 2017 -0700 @@ -42,7 +42,9 @@ #include "utils.h" static const octave_idx_type idx_max = - std::numeric_limits<octave_idx_type>::max (); + std::numeric_limits<octave_idx_type>::max () - 1; + +static const double idx_max_dbl = double (idx_max); static bool read_cell_spec (std::istream& is, octave_idx_type& row, octave_idx_type& col) @@ -122,8 +124,8 @@ stat = false; } - rup = idx_max - 1; - cup = idx_max - 1; + rup = idx_max; + cup = idx_max; } else { @@ -143,12 +145,12 @@ } else if (range_spec.is_real_matrix () && range_spec.numel () == 4) { - ColumnVector range(range_spec.vector_value ()); - // double --> unsigned int - rlo = static_cast<octave_idx_type> (range(0)); - clo = static_cast<octave_idx_type> (range(1)); - rup = static_cast<octave_idx_type> (range(2)); - cup = static_cast<octave_idx_type> (range(3)); + ColumnVector range (range_spec.vector_value ()); + // double --> unsigned int avoiding any overflow + rlo = static_cast<octave_idx_type> (std::min (range(0), idx_max_dbl)); + clo = static_cast<octave_idx_type> (std::min (range(1), idx_max_dbl)); + rup = static_cast<octave_idx_type> (std::min (range(2), idx_max_dbl)); + cup = static_cast<octave_idx_type> (std::min (range(3), idx_max_dbl)); } else stat = false; @@ -249,8 +251,8 @@ // Take a subset if a range was given. octave_idx_type r0 = 0; octave_idx_type c0 = 0; - octave_idx_type r1 = idx_max-1; - octave_idx_type c1 = idx_max-1; + octave_idx_type r1 = idx_max; + octave_idx_type c1 = idx_max; if (nargin > 2) { if (nargin == 3) @@ -266,6 +268,10 @@ if (r0 < 0 || c0 < 0) error ("dlmread: left & top must be positive"); + + // Short-circuit and return if range is empty + if (r1 < r0 || c1 < c0) + return ovl (Matrix (0,0)); } octave_idx_type i = 0; @@ -283,10 +289,15 @@ std::string line; - // Skip the r0 leading lines as these might be a header. - for (octave_idx_type m = 0; m < r0; m++) - getline (*input, line); - r1 -= r0; + // Skip the r0 leading lines + octave_idx_type rcnt = r0; + while (rcnt > 0 && getline (*input, line)) + rcnt--; + + if (rcnt > 0) + return ovl (Matrix (0,0)); // Not enough lines in file to satisfy RANGE + else + r1 -= r0; std::istringstream tmp_stream; @@ -509,6 +520,7 @@ %! assert (dlmread (file, ",", "A2.."), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]); %! assert (dlmread (file, ",", 10, 0), []); %! assert (dlmread (file, ",", 0, 10), []); +%! assert (dlmread (file, ",", [0, 4, 0, Inf]), []); %! unwind_protect_cleanup %! unlink (file); %! end_unwind_protect