# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1690554272 -7200
#      Fri Jul 28 16:24:32 2023 +0200
# Node ID 738d7ac93bcd6a33df1fdfb46e8868ec3b765189
# Parent  bc17da3679d88907d97693c25c4a4b3ce652f3bd
subsasgn: Avoid panic on invalid field names (bug #64213).

* libinterp/octave-value/ov-struct.cc (octave_struct::subsasgn,
octave_scalar_struct::subsasgn): Throw an exception if field name is not a
string instead of panicking. Add tests.

diff -r bc17da3679d8 -r 738d7ac93bcd libinterp/octave-value/ov-struct.cc
--- a/libinterp/octave-value/ov-struct.cc	Mon Jul 24 13:32:39 2023 -0400
+++ b/libinterp/octave-value/ov-struct.cc	Fri Jul 28 16:24:32 2023 +0200
@@ -307,7 +307,7 @@
   octave_value t_rhs = rhs;
 
   if (idx.front ().empty ())
-    error ("missing index in indexed assignment");
+    error ("subsasgn: missing index in indexed assignment");
 
   if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
     {
@@ -322,9 +322,11 @@
 
                 octave_value_list key_idx = *++p;
 
-                panic_if (key_idx.length () != 1);
-
-                std::string key = key_idx(0).string_value ();
+                if (key_idx.length () != 1)
+                  error ("subsasgn: dynamic structure field names must be strings");
+
+                std::string key
+                  = key_idx(0).xstring_value ("dynamic structure field names must be strings");
 
                 maybe_warn_invalid_field_name (key, "subsasgn");
 
@@ -378,9 +380,11 @@
           {
             octave_value_list key_idx = idx.front ();
 
-            panic_if (key_idx.length () != 1);
-
-            std::string key = key_idx(0).string_value ();
+            if (key_idx.length () != 1)
+              error ("subsasgn: dynamic structure field names must be strings");
+
+            std::string key
+              = key_idx(0).xstring_value ("subsasgn: dynamic structure field names must be strings");
 
             maybe_warn_invalid_field_name (key, "subsasgn");
 
@@ -444,9 +448,11 @@
             octave_value_list key_idx = *++p;
             octave_value_list idxf = idx.front ();
 
-            panic_if (key_idx.length () != 1);
-
-            std::string key = key_idx(0).string_value ();
+            if (key_idx.length () != 1)
+              error ("subsasgn: dynamic structure field names must be strings");
+
+            std::string key
+              = key_idx(0).xstring_value ("subsasgn: dynamic structure field names must be strings");
 
             maybe_warn_invalid_field_name (key, "subsasgn");
 
@@ -515,9 +521,11 @@
       {
         octave_value_list key_idx = idx.front ();
 
-        panic_if (key_idx.length () != 1);
-
-        std::string key = key_idx(0).string_value ();
+        if (key_idx.length () != 1)
+          error ("subsasgn: dynamic structure field names must be strings");
+
+        std::string key
+          = key_idx(0).xstring_value ("subsasgn: dynamic structure field names must be strings");
 
         maybe_warn_invalid_field_name (key, "subsasgn");
 
@@ -559,6 +567,21 @@
   return retval;
 }
 
+/*
+%!test
+%! x(1:2) = struct ();
+%! idx = struct ("type", {"()", ".", "."}, "subs", {{1}, "a", "b"});
+%! x = subsasgn (x, idx, 42);
+%! assert (x(1).a.b, 42);
+%! assert (isempty (x(2).a));
+
+%!test <*64213>
+%! x(1:2) = struct ();
+%! idx = struct ("type", {"()", "."}, "subs", {{1}, {"a", "b"}});
+%! fail ("x = subsasgn (x, idx, 42);", ...
+%!       "structure field names must be strings");
+*/
+
 octave_value
 octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
 {
@@ -1255,7 +1278,7 @@
   octave_value retval;
 
   if (idx.front ().empty ())
-    error ("missing index in indexed assignment");
+    error ("subsasgn: missing index in indexed assignment");
 
   if (type[0] == '.')
     {
@@ -1265,9 +1288,11 @@
 
       octave_value_list key_idx = idx.front ();
 
-      panic_if (key_idx.length () != 1);
-
-      std::string key = key_idx(0).string_value ();
+      if (key_idx.length () != 1)
+        error ("subsasgn: structure field names must be strings");
+
+      std::string key
+        = key_idx(0).xstring_value ("subsasgn: structure field names must be strings");
 
       maybe_warn_invalid_field_name (key, "subsasgn");
 
@@ -1318,6 +1343,20 @@
   return retval;
 }
 
+/*
+%!test
+%! x = struct ();
+%! idx = struct ("type", ".", "subs", {"a", "b"});
+%! x = subsasgn (x, idx, 42);
+%! assert (x.a.b, 42);
+
+%!test <*64213>
+%! x = struct ();
+%! idx = struct ("type", ".", "subs", {{"a", "b"}});
+%! fail ("x = subsasgn (x, idx, 42)", ...
+%!       "structure field names must be strings");
+*/
+
 octave_value
 octave_scalar_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
 {
