changeset 30392:5793f0355bfa stable

Ensure integer ranges do not exceed limits (bug #61300). * liboctave/array/Range.h (range::init): Use C++ types instead of octave_int<T> to get truncating behavior for division. * test/range.tst: Add tests for integer ranges.
author Arun Giridhar <arungiridhar@gmail.com>
date Sun, 28 Nov 2021 16:31:21 -0500
parents a61e1a0f6024
children cfee9398503d f3f3e3793fb5
files liboctave/array/Range.h test/range.tst
diffstat 2 files changed, 44 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/array/Range.h	Sun Nov 28 21:52:08 2021 -0800
+++ b/liboctave/array/Range.h	Sun Nov 28 16:31:21 2021 -0500
@@ -322,11 +322,15 @@
 
     void init (void)
     {
+      // We need an integer division that is truncating decimals instead of
+      // rounding.  So, use underlying C++ types instead of octave_int<T>.
+      // FIXME: The numerator might underflow or overflow. Add checks for that.
       m_numel = ((m_increment == T (0)
                   || (m_limit > m_base && m_increment < T (0))
                   || (m_limit < m_base && m_increment > T (0)))
-                 ? T (0)
-                 : (m_limit - m_base + m_increment) / m_increment);
+                 ? 0
+                 : (m_limit.value () - m_base.value () + m_increment.value ())
+                   / m_increment.value ());
 
       m_final = m_base + (m_numel - 1) * m_increment;
     }
--- a/test/range.tst	Sun Nov 28 21:52:08 2021 -0800
+++ b/test/range.tst	Sun Nov 28 16:31:21 2021 -0500
@@ -511,3 +511,41 @@
 %!   assert (numel (rlo), n+1);
 %!   assert (numel (rhi), n+1);
 %! endfor
+
+## Test that ranges do not exceed limits for integer types
+
+## Ascending ranges, signed
+%!test <*61300>
+%! int_types = {@int8, @int16, @int32, @int64};
+%! for i_type = 1:numel (int_types)
+%!   for i_start = 0:4
+%!     assert ((int_types{i_type} (i_start) : 6 : 100)([1,end]), ...
+%!             [int_types{i_type}(i_start), int_types{i_type}(96+i_start)]);
+%!   endfor
+%!   assert ((int_types{i_type} (5) : 6 : 100)([1,end]), ...
+%!           [int_types{i_type}(5), int_types{i_type}(95)]);
+%! endfor
+
+## Ascending ranges, unsigned
+%!test <*61300>
+%! int_types = {@uint8, @uint16, @uint32, @uint64};
+%! for i_type = 1:numel (int_types)
+%!   for i_start = 0:4
+%!     assert ((int_types{i_type} (i_start) : 6 : 100)([1,end]), ...
+%!             [int_types{i_type}(i_start), int_types{i_type}(96+i_start)]);
+%!   endfor
+%!   assert ((int_types{i_type} (5) : 6 : 100)([1,end]), ...
+%!           [int_types{i_type}(5), int_types{i_type}(95)]);
+%! endfor
+
+## Descending ranges, signed
+%!test <*61300>
+%! int_types = {@int8, @int16, @int32, @int64};
+%! for i_type = 1:numel (int_types)
+%!   for i_start = 0:4
+%!     assert ((int_types{i_type} (100-i_start) : -6 : 0)([1,end]), ...
+%!             [int_types{i_type}(100-i_start), int_types{i_type}(4-i_start)]);
+%!   endfor
+%!   assert ((int_types{i_type} (95) : -6 : 0)([1,end]), ...
+%!           [int_types{i_type}(95), int_types{i_type}(5)]);
+%! endfor