changeset 21417:7ce76114b321

catch exceptions in PKG_ADD files at startup (bug #47346) * load-path.h, load-path.cc (execute_pkg_add, execute_pkg_del): Make static functions in load_path class. Change uses. (load_path::get_add_hook, load_path::get_add_hook): New functions. * octave.cc (execute_pkg_add, initialize_load_path): New static functions. (safe_source_file): Improve error messages. (gripe_safe_source_exception): Delete. (octave_initialize_interpreter): Call initialize_load_path instead of load_path::initialize.
author John W. Eaton <jwe@octave.org>
date Tue, 08 Mar 2016 12:59:25 -0500
parents fdeb0d731512
children ca8450b9ef5b
files libinterp/corefcn/load-path.cc libinterp/corefcn/load-path.h libinterp/octave.cc
diffstat 3 files changed, 70 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/load-path.cc	Tue Mar 08 12:14:15 2016 -0500
+++ b/libinterp/corefcn/load-path.cc	Tue Mar 08 12:59:25 2016 -0500
@@ -46,8 +46,8 @@
 #include "utils.h"
 
 load_path *load_path::instance = 0;
-load_path::hook_fcn_ptr load_path::add_hook = execute_pkg_add;
-load_path::hook_fcn_ptr load_path::remove_hook = execute_pkg_del;
+load_path::hook_fcn_ptr load_path::add_hook = load_path::execute_pkg_add;
+load_path::hook_fcn_ptr load_path::remove_hook = load_path::execute_pkg_del;
 std::string load_path::command_line_path;
 std::string load_path::sys_path;
 load_path::abs_dir_cache_type load_path::abs_dir_cache;
@@ -2220,13 +2220,13 @@
 }
 
 void
-execute_pkg_add (const std::string& dir)
+load_path::execute_pkg_add (const std::string& dir)
 {
   execute_pkg_add_or_del (dir, "PKG_ADD");
 }
 
 void
-execute_pkg_del (const std::string& dir)
+load_path::execute_pkg_del (const std::string& dir)
 {
   execute_pkg_add_or_del (dir, "PKG_DEL");
 }
--- a/libinterp/corefcn/load-path.h	Tue Mar 08 12:14:15 2016 -0500
+++ b/libinterp/corefcn/load-path.h	Tue Mar 08 12:59:25 2016 -0500
@@ -259,10 +259,15 @@
       instance->do_display (os);
   }
 
-  static void set_add_hook (hook_fcn_ptr f) { add_hook = f; }
+  static hook_fcn_ptr get_add_hook (void) { return add_hook; }
+  static hook_fcn_ptr get_remove_hook (void) { return remove_hook; }
 
+  static void set_add_hook (hook_fcn_ptr f) { add_hook = f; }
   static void set_remove_hook (hook_fcn_ptr f) { remove_hook = f; }
 
+  static void execute_pkg_add (const std::string& dir);
+  static void execute_pkg_del (const std::string& dir);
+
   static void set_command_line_path (const std::string& p)
   {
     if (command_line_path.empty ())
@@ -733,7 +738,4 @@
 extern std::string
 genpath (const std::string& dir, const string_vector& skip = "private");
 
-extern void execute_pkg_add (const std::string& dir);
-extern void execute_pkg_del (const std::string& dir);
-
 #endif
--- a/libinterp/octave.cc	Tue Mar 08 12:14:15 2016 -0500
+++ b/libinterp/octave.cc	Tue Mar 08 12:59:25 2016 -0500
@@ -200,6 +200,57 @@
     }
 }
 
+static void
+execute_pkg_add (const std::string& dir)
+{
+  std::string file_name = file_ops::concat (dir, "PKG_ADD");
+
+  try
+    {
+      load_path::execute_pkg_add (dir);
+    }
+  catch (const index_exception& e)
+    {
+      recover_from_exception ();
+
+      std::cerr << "error: index exception in " << file_name << ": "
+                << e.message () << std::endl;
+    }
+  catch (const octave_interrupt_exception&)
+    {
+      recover_from_exception ();
+
+      if (quitting_gracefully)
+        clean_up_and_exit (exit_status);
+    }
+  catch (const octave_execution_exception&)
+    {
+      recover_from_exception ();
+
+      std::cerr << "error: execution exception in " << file_name << std::endl;
+    }
+}
+
+static void
+initialize_load_path (void)
+{
+  // Temporarily set the execute_pkg_add function to one that catches
+  // exceptions.  This is better than wrapping load_path::initialize in
+  // a try-catch block because it will not stop executing PKG_ADD files
+  // at the first exception.  It's also better than changing the default
+  // execute_pkg_add function to use safe_source file because that will
+  // normally be evaluated from the normal intepreter loop where
+  // exceptions are already handled.
+
+  unwind_protect frame;
+
+  frame.add_fcn (load_path::set_add_hook, load_path::get_add_hook ());
+
+  load_path::set_add_hook (execute_pkg_add);
+
+  load_path::initialize (set_initial_path);
+}
+
 DEFUN (__version_info__, args, ,
        "-*- texinfo -*-\n\
 @deftypefn {} {retval =} __version_info__ (@var{name}, @var{version}, @var{release}, @var{date})\n\
@@ -257,15 +308,6 @@
   F__version_info__ (args, 0);
 }
 
-static void
-gripe_safe_source_exception (const std::string& file, const std::string& msg)
-{
-  std::cerr << "error: " << msg << "\n"
-            << "error: execution of " << file << " failed\n"
-            << "error: trying to make my way to a command prompt"
-            << std::endl;
-}
-
 // Execute commands from a file and catch potential exceptions in a consistent
 // way.  This function should be called anywhere we might parse and execute
 // commands from a file before before we have entered the main loop in
@@ -281,6 +323,13 @@
     {
       source_file (file_name, context, verbose, require_file, warn_for);
     }
+  catch (const index_exception& e)
+    {
+      recover_from_exception ();
+
+      std::cerr << "error: index exception in " << file_name << ": "
+                << e.message () << std::endl;
+    }
   catch (const octave_interrupt_exception&)
     {
       recover_from_exception ();
@@ -292,7 +341,7 @@
     {
       recover_from_exception ();
 
-      gripe_safe_source_exception (file_name, "unhandled execution exception");
+      std::cerr << "error: execution exception in " << file_name << std::endl;
     }
 }
 
@@ -840,7 +889,7 @@
 
   intern_argv (argc, argv);
 
-  load_path::initialize (set_initial_path);
+  initialize_load_path ();
 
   initialize_history (read_history_file);
 }