From bdbe2b36089f331c507dd2dee8d87078cd808636 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 18 Jan 2017 13:02:51 +0100
Subject: [PATCH] Fixed memory leaks in usage stats, JSON attribute parsing and
 ttcn2json (artf786863)

Change-Id: I1ed85b104c3cbe89c3041a6c309867d353527228
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 common/usage_stats.cc                         | 20 ++++++--------
 common/usage_stats.hh                         |  6 ++++-
 compiler2/main.cc                             | 24 +++++++++++++++--
 compiler2/ttcn3/JsonAST.cc                    |  6 ++---
 compiler2/ttcn3/JsonAST.hh                    |  6 ++---
 compiler2/ttcn3/PatternString.cc              |  4 ++-
 core/Module_list.cc                           | 26 +++++++++++++++----
 core/Module_list.hh                           | 12 ++++++++-
 core/Runtime.cc                               | 12 ++++++++-
 .../XML/XmlWorkflow/src/xmlTest_Shell.ttcn    |  5 ++++
 regression_test/profiler/Shell.ttcn           |  5 ++++
 regression_test/ttcn2json/Shell.ttcn          |  5 ++++
 12 files changed, 102 insertions(+), 29 deletions(-)

diff --git a/common/usage_stats.cc b/common/usage_stats.cc
index 4eb264a36..b268dfb15 100644
--- a/common/usage_stats.cc
+++ b/common/usage_stats.cc
@@ -194,32 +194,28 @@ UsageData::~UsageData() {
 
 }
 
-struct thread_data {
-  std::string msg;
-  Sender* sndr;
-};
 
-void UsageData::sendDataThreaded(std::string msg, Sender* sender) {
-  thread_data* data = new thread_data; // will be deleted by sendData
-  data->msg = "id="+ id + "&host=" + host + "&platform=" + platform + "&gccv=" + C_COMPILER_VERSION + "&titanv=" + PRODUCT_NUMBER + "&msg="+ msg + "\r";
-  data->sndr = sender;
+pthread_t UsageData::sendDataThreaded(std::string msg, thread_data* data) {
+  data->msg = "id="+ id + "&host=" + host + "&platform=" + platform +
+    "&gccv=" + C_COMPILER_VERSION + "&titanv=" + PRODUCT_NUMBER + "&msg="+ msg + "\r";
 
   pthread_t thread;
   pthread_create(&thread, NULL, sendData, data);
+  return thread;
 }
 
 void* UsageData::sendData(void* m) {
+  // make sure the thread is cancelable if the main thread finishes first
+  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  
   thread_data* my_data;
   my_data = (thread_data*)m;
 
   if(my_data->sndr) {
     my_data->sndr->send(my_data->msg.c_str());
-    delete my_data->sndr;
   }
   
-  // delete the data after use
-  delete my_data;
-  
   return NULL;
 }
 
diff --git a/common/usage_stats.hh b/common/usage_stats.hh
index 8c5af2ad7..b807f9ce1 100644
--- a/common/usage_stats.hh
+++ b/common/usage_stats.hh
@@ -61,6 +61,10 @@ public:
   void send(const char*);
 };
 
+struct thread_data {
+  std::string msg;
+  Sender* sndr;
+};
 
 class UsageData {
 public:
@@ -69,7 +73,7 @@ public:
     static UsageData instance; // Guaranteed to be destroyed.
     return instance; // Instantiated on first use.
   }
-  static void sendDataThreaded(std::string msg, Sender* sender);
+  static pthread_t sendDataThreaded(std::string msg, thread_data* data);
 
 private:
 
diff --git a/compiler2/main.cc b/compiler2/main.cc
index 69275ce9a..f00d8ab44 100644
--- a/compiler2/main.cc
+++ b/compiler2/main.cc
@@ -1152,6 +1152,11 @@ int main(int argc, char *argv[])
   unsigned int error_count = Error_Context::get_error_count();
   if (error_count > 0) ret_val = EXIT_FAILURE;
 
+#ifdef USAGE_STATS
+  pthread_t stats_thread = 0;
+  thread_data* stats_data = NULL;
+#endif
+  
   if (parse_only || semantic_check_only) {
     // print detailed statistics
     Error_Context::print_error_statistics();
@@ -1184,8 +1189,9 @@ int main(int argc, char *argv[])
         }
       }
 
-      HttpSender *sender = new HttpSender;
-      UsageData::getInstance().sendDataThreaded(stream.str(), sender);
+      stats_data = new thread_data;
+      stats_data->sndr = new HttpSender;
+      stats_thread = UsageData::getInstance().sendDataThreaded(stream.str(), stats_data);
 #endif
       if (ttcn2json) {
         NOTIFY("Generating JSON schema...");
@@ -1233,5 +1239,19 @@ int main(int argc, char *argv[])
 
   // dbgnew.hh already does it: check_mem_leak(argv[0]);
 
+#ifdef USAGE_STATS
+  if (stats_thread != 0) {
+    // cancel the usage stats thread if it hasn't finished yet
+    pthread_cancel(stats_thread);
+    pthread_join(stats_thread, NULL);
+  }
+  if (stats_data != NULL) {
+    if (stats_data->sndr != NULL) {
+      delete stats_data->sndr;
+    }
+    delete stats_data;
+  }
+#endif
+  
   return ret_val;
 }
diff --git a/compiler2/ttcn3/JsonAST.cc b/compiler2/ttcn3/JsonAST.cc
index d23fb3c86..add80c0f6 100644
--- a/compiler2/ttcn3/JsonAST.cc
+++ b/compiler2/ttcn3/JsonAST.cc
@@ -15,10 +15,10 @@
 #include <cstddef>
 #include <cstdio>
 
-void JsonSchemaExtension::init(const char* p_key, const char* p_value)
+void JsonSchemaExtension::init(char* p_key, char* p_value)
 {
-  key = mcopystr(p_key);
-  value = mcopystr(p_value);
+  key = p_key;
+  value = p_value;
 }
 
 JsonSchemaExtension::~JsonSchemaExtension()
diff --git a/compiler2/ttcn3/JsonAST.hh b/compiler2/ttcn3/JsonAST.hh
index e3519d499..3ac5b97ea 100644
--- a/compiler2/ttcn3/JsonAST.hh
+++ b/compiler2/ttcn3/JsonAST.hh
@@ -18,13 +18,13 @@
 
 class JsonSchemaExtension {
 private:
-  void init(const char* p_key, const char* p_value);
+  void init(char* p_key, char* p_value);
 public:
   char* key;
   char* value;
   
-  JsonSchemaExtension(const char* p_key, const char* p_value) { init(p_key, p_value); }
-  JsonSchemaExtension(const JsonSchemaExtension& x) { init(x.key, x.value); }
+  JsonSchemaExtension(char* p_key, char* p_value) { init(p_key, p_value); }
+  JsonSchemaExtension(const JsonSchemaExtension& x) { init(mcopystr(x.key), mcopystr(x.value)); }
   ~JsonSchemaExtension();
 };
 
diff --git a/compiler2/ttcn3/PatternString.cc b/compiler2/ttcn3/PatternString.cc
index db00bc1e5..1e9daddbb 100644
--- a/compiler2/ttcn3/PatternString.cc
+++ b/compiler2/ttcn3/PatternString.cc
@@ -715,7 +715,9 @@ namespace Ttcn {
       regex_str = TTCN_pattern_to_regexp(utf8str.c_str(), true);
     }
     
-    return convert_to_json_string(regex_str);
+    char* json_str = convert_to_json_string(regex_str);
+    Free(regex_str);
+    return json_str;
   }
 
 } // namespace Ttcn
diff --git a/core/Module_list.cc b/core/Module_list.cc
index 5230a50ec..84b06f435 100644
--- a/core/Module_list.cc
+++ b/core/Module_list.cc
@@ -349,8 +349,9 @@ void Module_List::print_version()
     "--------------------\n", stderr);
 }
 
-void Module_List::send_versions() {
 #ifdef USAGE_STATS
+void Module_List::send_usage_stats(pthread_t& thread, thread_data*& data)
+{
   std::set<ModuleVersion> versions;
   for (TTCN_Module *list_iter = list_head; list_iter != NULL;
       list_iter = list_iter->list_next)  {
@@ -371,11 +372,26 @@ void Module_List::send_versions() {
       }
   }
 
-  HttpSender* sender = new HttpSender;
-  UsageData::getInstance().sendDataThreaded(stream.str().c_str(), sender);
-#endif
+  data = new thread_data;
+  data->sndr = new HttpSender;
+  thread = UsageData::getInstance().sendDataThreaded(stream.str().c_str(), data);
+}
+
+void Module_List::clean_up_usage_stats(pthread_t thread, thread_data* data)
+{
+  if (thread != 0) {
+    // cancel the usage stats thread if it hasn't finished yet
+    pthread_cancel(thread);
+    pthread_join(thread, NULL);
+  }
+  if (data != NULL) {
+    if (data->sndr != NULL) {
+      delete data->sndr;
+    }
+    delete data;
+  }
 }
-            
+#endif // USAGE_STATS   
 
 void Module_List::list_testcases()
 {
diff --git a/core/Module_list.hh b/core/Module_list.hh
index 93fee1c19..66fcc43d7 100644
--- a/core/Module_list.hh
+++ b/core/Module_list.hh
@@ -23,6 +23,9 @@
 
 #include <stdio.h>
 #include "Types.h"
+#ifdef USAGE_STATS
+#include <pthread.h>
+#endif
 
 class Text_Buf;
 class TTCN_Module;
@@ -30,6 +33,9 @@ class Module_Param;
 class Module_Param_Name;
 class ModuleVersion;
 struct namespace_t;
+#ifdef USAGE_STATS
+struct thread_data;
+#endif
 
 typedef void (*genericfunc_t)(void);
 
@@ -64,7 +70,11 @@ public:
   static void execute_all_testcases(const char *module_name);
 
   static void print_version();
-  static void send_versions();
+  
+#ifdef USAGE_STATS
+  static void send_usage_stats(pthread_t& thread, thread_data*& data);
+  static void clean_up_usage_stats(pthread_t thread, thread_data* data);
+#endif
   static void list_testcases();
   static void push_version(Text_Buf& text_buf);
 
diff --git a/core/Runtime.cc b/core/Runtime.cc
index 648ed6c37..7f94a74a4 100644
--- a/core/Runtime.cc
+++ b/core/Runtime.cc
@@ -447,12 +447,18 @@ int TTCN_Runtime::hc_main(const char *local_addr, const char *MC_addr,
   TTCN_Logger::log_HC_start(get_host_name());
   TTCN_Logger::write_logger_settings();
   TTCN_Snapshot::check_fd_setsize();
+#ifdef USAGE_STATS
+  pthread_t stats_thread = 0;
+  thread_data* stats_data = NULL;
+#endif
   try {
     if (local_addr != NULL)
       TTCN_Communication::set_local_address(local_addr);
     TTCN_Communication::set_mc_address(MC_addr, MC_port);
     TTCN_Communication::connect_mc();
-    Module_List::send_versions();
+#ifdef USAGE_STATS
+    Module_List::send_usage_stats(stats_thread, stats_data);
+#endif
     executor_state = HC_IDLE;
     TTCN_Communication::send_version();
     initialize_component_process_tables();
@@ -477,6 +483,10 @@ int TTCN_Runtime::hc_main(const char *local_addr, const char *MC_addr,
     TTCN_Logger::log_executor_runtime(
       API::ExecutorRuntime_reason::host__controller__finished);
 
+#ifdef USAGE_STATS
+  Module_List::clean_up_usage_stats(stats_thread, stats_data);
+#endif
+
   return ret_val;
 }
 
diff --git a/regression_test/XML/XmlWorkflow/src/xmlTest_Shell.ttcn b/regression_test/XML/XmlWorkflow/src/xmlTest_Shell.ttcn
index cc91aeb47..2aca2d874 100644
--- a/regression_test/XML/XmlWorkflow/src/xmlTest_Shell.ttcn
+++ b/regression_test/XML/XmlWorkflow/src/xmlTest_Shell.ttcn
@@ -293,6 +293,11 @@ runs on Shell_CT
               pl_success:=false;
             }
           }//select
+          vl_pattern := "*(Memory leak at)*";
+          if (regexp(v_ASP_PResult.stderr,vl_pattern,0) != "") {
+            log("Memory leak detected during command execution.");
+            pl_success := false;
+          }
         } else {
           log("The result code(", v_ASP_PResult.code, ") is not the expected(", vl_expectedCode, ")");
           pl_success:=false;
diff --git a/regression_test/profiler/Shell.ttcn b/regression_test/profiler/Shell.ttcn
index c431eb9b4..8841e49fd 100644
--- a/regression_test/profiler/Shell.ttcn
+++ b/regression_test/profiler/Shell.ttcn
@@ -235,6 +235,11 @@ runs on Shell_CT
               pl_success:=false;
             }
           }//select
+          vl_pattern := "*(Memory leak at)*";
+          if (regexp(v_ASP_PResult.stderr,vl_pattern,0) != "") {
+            log("Memory leak detected during command execution.");
+            pl_success := false;
+          }
         } else {
           log("The result code(", v_ASP_PResult.code, ") is not the expected(", vl_expectedCode, ")");
           pl_success:=false;
diff --git a/regression_test/ttcn2json/Shell.ttcn b/regression_test/ttcn2json/Shell.ttcn
index 533beef6a..0b1899fa6 100644
--- a/regression_test/ttcn2json/Shell.ttcn
+++ b/regression_test/ttcn2json/Shell.ttcn
@@ -223,6 +223,11 @@ runs on Shell_CT
               pl_success:=false;
             }
           }//select
+          vl_pattern := "*(Memory leak at)*";
+          if (regexp(v_ASP_PResult.stderr,vl_pattern,0) != "") {
+            log("Memory leak detected during command execution.");
+            pl_success := false;
+          }
         } else {
           log("The result code(", v_ASP_PResult.code, ") is not the expected(", vl_expectedCode, ")");
           pl_success:=false;
-- 
GitLab