changeset 23631:0954bf188bed

avoid memory leak in source_file function * oct-parse.in.yy (source_file): Ensure that code returned from parse_fcn_file is deleted.
author John W. Eaton <jwe@octave.org>
date Fri, 16 Jun 2017 21:10:16 -0400
parents 8a47d4735655
children 3426a596eabd
files libinterp/parse-tree/oct-parse.in.yy
diffstat 1 files changed, 20 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/parse-tree/oct-parse.in.yy	Fri Jun 16 18:21:47 2017 -0400
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri Jun 16 21:10:16 2017 -0400
@@ -4756,7 +4756,8 @@
 
     static std::map<std::string, int> source_call_depth;
 
-    std::string file_full_name = octave::sys::file_ops::tilde_expand (file_name);
+    std::string file_full_name
+      = octave::sys::file_ops::tilde_expand (file_name);
 
     file_full_name = octave::sys::env::make_absolute (file_full_name);
 
@@ -4787,11 +4788,10 @@
       }
 
     octave_function *fcn = 0;
-    // Don't delete a function already in symbol_table
-    bool delete_fcn = false;
 
     // Find symbol name that would be in symbol_table, if it were loaded.
-    size_t dir_end = file_name.find_last_of (octave::sys::file_ops::dir_sep_chars ());
+    size_t dir_end
+      = file_name.find_last_of (octave::sys::file_ops::dir_sep_chars ());
     dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
 
     size_t extension = file_name.find_last_of ('.');
@@ -4803,28 +4803,37 @@
 
     // Check if this file is already loaded (or in the path)
     symbol_table& symtab = octave::__get_symbol_table__ ("source_file");
-    octave_value loaded_sym = symtab.find (symbol);
-    if (loaded_sym.is_function ())
+    octave_value ov_code = symtab.find (symbol);
+    if (ov_code.is_function ())
       {
-        fcn = loaded_sym.function_value ();
+        fcn = ov_code.function_value ();
+
         if (fcn)
           {
             if (octave::sys::canonicalize_file_name (fcn->fcn_file_name ())
                 != full_name)
               {
-                fcn = 0;             // wrong file, so load it below
-                delete_fcn = true;   // and delete it when done.
+                // wrong file, so load it below.
+                fcn = 0;
               }
           }
       }
 
-    // If no symbol of this name, or the symbol is for a different file, load
+    // If no symbol of this name, or the symbol is for a different
+    // file, load.
+
     if (! fcn)
       {
         try
           {
             fcn = parse_fcn_file (file_full_name, file_name, "", "",
                                   require_file, true, false, false, warn_for);
+
+            if (fcn)
+              {
+                // Ensure that FCN will be deleted.
+                ov_code = octave_value (fcn);
+              }
           }
         catch (octave::execution_exception& e)
           {
@@ -4838,11 +4847,7 @@
       return;
 
     if (! fcn->is_user_code ())
-      {
-        if (delete_fcn)
-          delete fcn;
-        error ("source: %s is not a script", full_name.c_str ());
-      }
+      error ("source: %s is not a script", full_name.c_str ());
 
     if (verbose)
       {
@@ -4856,10 +4861,6 @@
 
     if (verbose)
       std::cout << "done." << std::endl;
-
-    // Delete scripts not on the path, so they don't shadow ones that are.
-    if (delete_fcn)
-      delete fcn;
   }
 }