changeset 27781:61cc648ab034

prevent crash if dynamic printf field widths are out of range (bug #57368) * oct-stream.h, oct-stream.cc (printf_value_cache::int_value): Require value to be in range [0, INT_MAX] before conversion to int. (base_stream::field_width_error): New function. (base_stream::do_printf): Call field_width_error if val_cache::int_value conversion fails.
author John W. Eaton <jwe@octave.org>
date Fri, 06 Dec 2019 14:18:15 -0600
parents 0dad96574d12
children 566adf9d823b
files libinterp/corefcn/oct-stream.cc libinterp/corefcn/oct-stream.h
diffstat 2 files changed, 29 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc	Fri Dec 06 11:24:16 2019 -0800
+++ b/libinterp/corefcn/oct-stream.cc	Fri Dec 06 14:18:15 2019 -0600
@@ -5444,7 +5444,10 @@
     // Get the current value as a double and advance the internal pointer.
     octave_value get_next_value (char type = 0);
 
-    // Get the current value as an int and advance the internal pointer.
+    // Get the current value as an int and advance the internal
+    // pointer.  Value before conversion to int must be >= 0 and less
+    // than std::numeric_limits<int>::max ().
+
     int int_value (void);
 
     operator bool () const { return (curr_state == ok); }
@@ -5584,18 +5587,18 @@
   int
   printf_value_cache::int_value (void)
   {
-    int retval = 0;
-
     octave_value val = get_next_value ();
 
     double dval = val.double_value (true);
 
-    if (math::x_nint (dval) == dval)
-      retval = math::nint (dval);
-    else
-      curr_state = conversion_error;
-
-    return retval;
+    if (dval < 0 || dval > std::numeric_limits<int>::max ()
+        || math::x_nint (dval) != dval)
+      {
+        curr_state = conversion_error;
+        return -1;
+      }
+
+    return math::nint (dval);
   }
 
   // Ugh again and again.
@@ -5857,6 +5860,13 @@
     return retval;
   }
 
+  void
+  base_stream::field_width_error (const std::string& who) const
+  {
+    ::error ("%s: invalid field width, must be integer >= 0 and <= INT_MAX",
+             who.c_str ());
+  }
+
   int
   base_stream::do_printf (printf_format_list& fmt_list,
                           const octave_value_list& args,
@@ -5896,7 +5906,10 @@
                 sa_1 = val_cache.int_value ();
 
                 if (! val_cache)
-                  break;
+                  {
+                    field_width_error (who);
+                    break;
+                  }
                 else
                   {
                     if (nsa > 1)
@@ -5904,7 +5917,10 @@
                         sa_2 = val_cache.int_value ();
 
                         if (! val_cache)
-                          break;
+                          {
+                            field_width_error (who);
+                            break;
+                          }
                       }
                   }
               }
--- a/libinterp/corefcn/oct-stream.h	Fri Dec 06 11:24:16 2019 -0800
+++ b/libinterp/corefcn/oct-stream.h	Fri Dec 06 14:18:15 2019 -0600
@@ -229,6 +229,8 @@
                                 const octave_value& val,
                                 const std::string& who);
 
+    void field_width_error (const std::string& who) const;
+
     int do_printf (printf_format_list& fmt_list, const octave_value_list& args,
                    const std::string& who /* = "printf" */);