From 6ab9111048ec9a09ea4809c4ec57ad97fe208ce5 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 25 Jan 2017 16:00:24 +0100
Subject: [PATCH] Fixed memory leaks in TPD processing (artf786863)

Change-Id: I2ba03f8e7ea122e60be0ff1bb39a12679ea1f95a
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/makefile.c | 30 +++++++++++++++----
 compiler2/xpather.cc | 71 +++++++++++++++++++++++++++++++++-----------
 compiler2/xpather.h  |  2 +-
 3 files changed, 78 insertions(+), 25 deletions(-)

diff --git a/compiler2/makefile.c b/compiler2/makefile.c
index 64efcf9a9..cb188c212 100644
--- a/compiler2/makefile.c
+++ b/compiler2/makefile.c
@@ -4995,6 +4995,8 @@ int main(int argc, char *argv[])
   
   if (error_flag) {
     usage();
+    Free(other_files);
+    Free(search_paths);
     return EXIT_FAILURE;
   }
 
@@ -5007,6 +5009,8 @@ int main(int argc, char *argv[])
 #ifdef LICENSE
     print_license_info();
 #endif
+    Free(other_files);
+    Free(search_paths);
     return EXIT_SUCCESS;
   }
 
@@ -5017,16 +5021,21 @@ int main(int argc, char *argv[])
   free_openssl();
   if (!valid_license) {
     free_license(&lstr);
+    Free(other_files);
+    Free(search_paths);
     exit(EXIT_FAILURE);
   }
   if (!check_feature(&lstr, FEATURE_TPGEN)) {
     ERROR("The license key does not allow the generation of "
           "Makefile skeletons.");
+    Free(other_files);
+    Free(search_paths);
     return EXIT_FAILURE;
   }
   free_license(&lstr);
 #endif
 
+  boolean free_argv = FALSE;
   if (tflag) {
     char* abs_work_dir = NULL;
     FILE* prj_graph_fp = NULL;
@@ -5104,7 +5113,7 @@ int main(int argc, char *argv[])
     boolean temp_wflag = FALSE;
 
     tpd_processed = process_tpd(tpd_file_name, tpd_build_config, file_list_path,
-      &argc, &argv, &optind, &ets_name, &project_name,
+      &argc, &argv, &free_argv, &optind, &ets_name, &project_name,
       &gflag, &sflag, &cflag, &aflag, &pflag,
       &Rflag, &lflag, &mflag, &Pflag, &Lflag, rflag, Fflag, Tflag, output_file, &abs_work_dir, sub_project_dirs, program_name, prj_graph_fp,
       create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines, prep_includes, prep_defines, prep_undefines, &csflag,
@@ -5118,14 +5127,17 @@ int main(int argc, char *argv[])
       wflag = temp_wflag;
     }
 
-    Free(abs_work_dir);
     if (prj_graph_fp) {
       fprintf(prj_graph_fp, "</project_hierarchy_graph>\n");
       fclose(prj_graph_fp);
     }
     if (tpd_processed == TPD_FAILED) {
       ERROR("Failed to process %s", tpd_file_name);
-      goto end;
+      // process_tpd has already cleaned everything up
+      return EXIT_FAILURE;
+    }
+    else {
+      Free(abs_work_dir);
     }
     if (zflag) {
       WARNING("Compiler option '-z' and its argument will be overwritten by "
@@ -5160,8 +5172,12 @@ int main(int argc, char *argv[])
       executeMakefileScript(makefileScript, output_file);
     }
   }
+  else {
+    free_string2_list(run_command_list);
+    free_string2_list(create_symlink_list);
+    Free(project_name);
+  }
 
-end:
   free_string_list(sub_project_dirs);
   free_string_list(ttcn3_prep_includes);
   free_string_list(ttcn3_prep_defines);
@@ -5185,10 +5201,9 @@ end:
   free_string2_list(target_placement_list);
   free_string2_list(required_configs);
   Free(makefileScript);
-
+  
   Free(other_files);
   if (tpd_processed == TPD_SUCCESS) {
-    int E;
     if (!(eflag && ets_name))
       Free(ets_name);
     if (cxxcompiler)
@@ -5200,6 +5215,9 @@ end:
     if (ttcn3prep)
       Free(ttcn3prep);
   /* Free(output_file); */
+  }
+  if (free_argv) {
+    int E;
     for (E = 0; E < argc; ++E) Free(argv[E]);
     Free(argv);
   }
diff --git a/compiler2/xpather.cc b/compiler2/xpather.cc
index bddf069ce..488c787c0 100644
--- a/compiler2/xpather.cc
+++ b/compiler2/xpather.cc
@@ -1253,7 +1253,7 @@ static tpd_result config_struct_get_required_configs(struct config_struct* const
 }
 
 static tpd_result process_tpd_internal(const char *p_tpd_name, char* tpdName, const char *actcfg,
-  const char *file_list_path, int *p_argc, char ***p_argv,
+  const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
   int *p_optind, char **p_ets_name, char **p_project_name,
   boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
   boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
@@ -1273,7 +1273,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char* tpdName, co
   const char **search_paths, size_t n_search_paths, char** makefileScript, struct config_struct * const all_configs);
 
 extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
-  const char *file_list_path, int *p_argc, char ***p_argv,
+  const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
   int *p_optind, char **p_ets_name, char **p_project_name,
   boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
   boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
@@ -1304,7 +1304,7 @@ extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
   // The first round only collects the configurations about the tpd-s into the
   // all_configs variable. It does not do anything else.
   tpd_result success = process_tpd_internal(p_tpd_name, tpdName,
-      actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, p_project_name,
+      actcfg, file_list_path, p_argc, p_argv, p_free_argv, p_optind, p_ets_name, p_project_name,
       p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
       p_Rflag, p_lflag, p_mflag, p_Pflag,
       p_Lflag, recursive, force_overwrite, gen_only_top_level,
@@ -1332,7 +1332,7 @@ extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
     // optimal case. In the not optimal case errors are produced.
     // This round does get the information from the tpd to generate the makefile.
     success = process_tpd_internal(p_tpd_name, tpdName,
-      actcfg, file_list_path, p_argc, p_argv, p_optind, p_ets_name, p_project_name,
+      actcfg, file_list_path, p_argc, p_argv, p_free_argv, p_optind, p_ets_name, p_project_name,
       p_gflag, p_sflag, p_cflag, p_aflag, preprocess,
       p_Rflag, p_lflag, p_mflag, p_Pflag,
       p_Lflag, recursive, force_overwrite, gen_only_top_level,
@@ -1371,7 +1371,7 @@ extern "C" tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
   }
   seen_tpd_files.clear();
 
-  return success;
+  return TPD_SUCCESS;
   
 failure:
   /* free everything before exiting */
@@ -1394,20 +1394,33 @@ failure:
 
   Free(search_paths);
   Free(*generatorCommandOutput);
+  free_string2_list(run_command_list);
   free_string2_list(create_symlink_list);
   free_string2_list(target_placement_list);
   free_string2_list(required_configs);
   Free(*makefileScript);
   Free(*p_project_name);
+  Free(*abs_work_dir_p);
 
   Free(*p_ets_name);
   Free(*cxxcompiler);
   Free(*optlevel);
   Free(*optflags);
   Free(*ttcn3prep);
-  for (int E = 0; E < *p_argc; ++E) Free((*p_argv)[E]);
-  Free(*p_argv);
-  exit(EXIT_FAILURE);
+  if (*p_free_argv) {
+    for (int E = 0; E < *p_argc; ++E) Free((*p_argv)[E]);
+    Free(*p_argv);
+  }
+  
+  for (size_t i = 0, num = seen_tpd_files.size(); i < num; ++i) {
+    const cstring& key = seen_tpd_files.get_nth_key(i);
+    int *elem = seen_tpd_files.get_nth_elem(i);
+    key.destroy();
+    delete elem;
+  }
+  seen_tpd_files.clear();
+  
+  return TPD_FAILED;
 }
 
 // optind is the index of the next element of argv to be processed.
@@ -1421,7 +1434,7 @@ failure:
 // If process_tpd() preserves the content of such a string (e.g. ets_name),
 // it must nevertheless make a copy on the heap via mcopystr().
 static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, const char *actcfg,
-  const char *file_list_path, int *p_argc, char ***p_argv,
+  const char *file_list_path, int *p_argc, char ***p_argv, boolean* p_free_argv,
   int *p_optind, char **p_ets_name, char **p_project_name,
   boolean *p_gflag, boolean *p_sflag, boolean *p_cflag, boolean *p_aflag, boolean *preprocess,
   boolean *p_Rflag, boolean *p_lflag, boolean *p_mflag, boolean *p_Pflag,
@@ -1582,6 +1595,9 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
     XPathObject projectNameObj(run_xpath(xpathCtx, projectNameXpath));
     Free(projectNameXpath);
     if (projectNameObj->nodesetval && projectNameObj->nodesetval->nodeNr > 0) {
+      if (*p_project_name != NULL) {
+        Free(*p_project_name);
+      }
       *p_project_name = mcopystr((const char*)projectNameObj->nodesetval->nodeTab[0]->content);
       projGenHelper.addTarget(*p_project_name);
       projGenHelper.setToplevelProjectName(*p_project_name);
@@ -2885,6 +2901,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
         int my_argc = 0;
         char *my_args[] = { NULL };
         char **my_argv = my_args + 0;
+        boolean my_free_argv = FALSE;
         int my_optind = 0;
         boolean my_gflag = *p_gflag, my_aflag = *p_aflag, my_cflag = *p_cflag, // pass down
           my_Rflag = *p_Rflag, my_Pflag = *p_Pflag, my_Zflag = *p_Zflag, my_Hflag = *p_Hflag,
@@ -2936,7 +2953,7 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
         }
       
         tpd_result success = process_tpd_internal((const char*)abs_projectLocationURI, tpdName_loc,
-          my_actcfg, file_list_path, &my_argc, &my_argv, &my_optind, &my_ets, &my_proj_name,
+          my_actcfg, file_list_path, &my_argc, &my_argv, &my_free_argv, &my_optind, &my_ets, &my_proj_name,
           &my_gflag, &my_sflag, &my_cflag, &my_aflag, preprocess, &my_Rflag, &my_lflag,
           &my_mflag, &my_Pflag, &my_Lflag, recursive, force_overwrite, gen_only_top_level, NULL, &sub_proj_abs_work_dir,
           sub_project_dirs, program_name, prj_graph_fp, create_symlink_list, ttcn3_prep_includes, ttcn3_prep_defines, ttcn3_prep_undefines, 
@@ -3017,21 +3034,31 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
               const cstring tmp(my_argv[z]);
               if (!files.has_key(tmp)){
                 files.add(tmp, my_argv[z]);
-              } else {
+              } else if (my_free_argv) {
                 Free(my_argv[z]);
               }
             }
           }
 
-          Free(my_argv); // free the array; we keep the pointers
+          if (my_free_argv) {
+            Free(my_argv); // free the array; we keep the pointers
+          }
           Free(my_ets);
-          Free(my_proj_name);
         }
-        else if (success == TPD_FAILED) {
-          ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
-          result = TPD_FAILED;
+        else {
+          if (my_free_argv) {
+            for (int z = 0; z < my_argc; ++z) {
+              Free(my_argv[z]);
+            }
+            Free(my_argv);
+          }
+          if (success == TPD_FAILED) {
+            ERROR("Failed to process %s", (const char*)abs_projectLocationURI);
+            result = TPD_FAILED;
+          }
+          // else TPD_SKIPPED, keep quiet
         }
-        // else TPD_SKIPPED, keep quiet
+        Free(my_proj_name);
         Free(tpdName_loc);
         name = projectLocationURI = tpdName_loc = NULL; // forget all
       }
@@ -3165,6 +3192,15 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
   }
   // replace argv only if not config mode
   if (!get_config_mode) {
+    if (*p_free_argv) {
+      for (int i = 0; i < *p_argc; ++i) {
+        Free((*p_argv)[i]);
+      }
+      Free(*p_argv);
+    }
+    else {
+      *p_free_argv = TRUE;
+    }
     *p_argv = new_argv;
     *p_argc = new_argc;
     *p_optind = 0;
@@ -3173,7 +3209,6 @@ static tpd_result process_tpd_internal(const char *p_tpd_name, char *tpdName, co
       Free(new_argv[i]);
     }
     Free(new_argv);
-    Free(*p_project_name);
   }
 
   // finally...
diff --git a/compiler2/xpather.h b/compiler2/xpather.h
index e93420d13..c4565b7c5 100644
--- a/compiler2/xpather.h
+++ b/compiler2/xpather.h
@@ -272,7 +272,7 @@ enum
 #endif
 tpd_result process_tpd(const char *p_tpd_name, const char *actcfg,
   const char *file_list_path,
-  int *argc, char ***argv,
+  int *argc, char ***argv, boolean* p_free_argv,
   int *optind, char **ets_name, char **project_name,
   boolean *gnu_make, boolean *single_mode,
   boolean *central_storage, boolean *absolute_paths,
-- 
GitLab