diff libinterp/corefcn/stack-frame.cc @ 26663:fad3f19de1be

don't fail if symbol in script can't be found (bug #55626) * stack-frame.h, stack-frame.cc (script_stack_frame::get_val_offsets_internal): New function. (script_stack_frame::get_val_offsets): Return flag indicating whether symbol is found instead of crashing if it is missing. If frame_offset is zero and data_offset is out of range, call get_val_offsets_internal to attempt to find symbol in parent scopes. (script_stack_frame::varval): If symbol can't be found, return undefined value. (script_stack_frame::scope_flag): If symbol can't be found, return LOCAL flag.
author John W. Eaton <jwe@octave.org>
date Fri, 01 Feb 2019 20:44:15 +0000
parents cf9e10ce3351
children 4271b53b24a6
line wrap: on
line diff
--- a/libinterp/corefcn/stack-frame.cc	Thu Jan 31 18:45:37 2019 +0000
+++ b/libinterp/corefcn/stack-frame.cc	Fri Feb 01 20:44:15 2019 +0000
@@ -758,7 +758,84 @@
     return sym;
   }
 
-  void script_stack_frame::get_val_offsets (const symbol_record& sym,
+  // Similar to set_script_offsets_internal except that we only return
+  // frame and data offsets for symbols found by name in parent scopes
+  // instead of updating the offsets stored in the script frame itself.
+
+  bool
+  script_stack_frame::get_val_offsets_internal (const symbol_record& script_sr,
+                                                size_t& frame_offset,
+                                                size_t& data_offset) const
+  {
+    bool found = false;
+
+    // This scope will be used to evaluate the script.  Find symbols
+    // here by name.
+
+    symbol_scope eval_scope = m_access_link->get_scope ();
+
+    if (eval_scope.is_nested ())
+      {
+        std::string name = script_sr.name ();
+
+        symbol_scope parent_scope = eval_scope;
+
+        size_t count = 1;
+
+        while (parent_scope)
+          {
+            const std::map<std::string, symbol_record>& parent_scope_symbols
+              = parent_scope.symbols ();
+
+            auto p = parent_scope_symbols.find (name);
+
+            if (p != parent_scope_symbols.end ())
+              {
+                found = true;
+                symbol_record parent_scope_sr = p->second;
+
+                frame_offset = parent_scope_sr.frame_offset () + 1;
+
+                data_offset = parent_scope_sr.data_offset ();
+
+                break;
+              }
+            else
+              {
+                count++;
+                parent_scope = parent_scope.parent_scope ();
+              }
+          }
+      }
+    else
+      {
+        const std::map<std::string, symbol_record>& eval_scope_symbols
+          = eval_scope.symbols ();
+
+        std::string name = script_sr.name ();
+
+        auto p = eval_scope_symbols.find (name);
+
+        symbol_record eval_scope_sr;
+
+        if (p != eval_scope_symbols.end ())
+          {
+            found = true;
+            eval_scope_sr = p->second;
+
+            // The +1 is for going from the script frame to the eval
+            // frame.  Only one access_link should need to be followed.
+
+            frame_offset = eval_scope_sr.frame_offset () + 1;
+
+            data_offset = eval_scope_sr.data_offset ();
+          }
+      }
+
+    return found;
+  }
+
+  bool script_stack_frame::get_val_offsets (const symbol_record& sym,
                                             size_t& frame_offset,
                                             size_t& data_offset) const
   {
@@ -767,11 +844,14 @@
 
     if (frame_offset == 0)
       {
-        // An out of range data_offset value here indicates an error in
-        // the implementation.
+        // An out of range data_offset value here means that we have a
+        // symbol that was not originally in the script.  But this
+        // function is called in places where we can't insert a new
+        // symbol, so we fail and it is up to the caller to decide what
+        // to do.
 
         if (data_offset >= size ())
-          panic_impossible ();
+          return get_val_offsets_internal (sym, frame_offset, data_offset);
 
         // Use frame and value offsets stored in this stack frame,
         // indexed by data_offset from the symbol_record to find the
@@ -788,6 +868,8 @@
         // that was not originally in the script.  The values should
         // have been determined by the script_stack_frame::lookup function.
       }
+
+    return true;
   }
 
   void script_stack_frame::get_val_offsets_with_insert (const symbol_record& sym,
@@ -830,7 +912,12 @@
   {
     size_t frame_offset;
     size_t data_offset;
-    get_val_offsets (sym, frame_offset, data_offset);
+
+    bool found = get_val_offsets (sym, frame_offset, data_offset);
+
+    // It can't be global or persistent, so call it local.
+    if (! found)
+      return LOCAL;
 
     // Follow frame_offset access links to stack frame that holds
     // the value.
@@ -853,7 +940,11 @@
   {
     size_t frame_offset;
     size_t data_offset;
-    get_val_offsets (sym, frame_offset, data_offset);
+
+    bool found = get_val_offsets (sym, frame_offset, data_offset);
+
+    if (! found)
+      return octave_value ();
 
     // Follow frame_offset access links to stack frame that holds
     // the value.