From de28a6593475314c4e6f1d95e817eac78a55552a Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Thu, 4 Jun 2020 14:51:50 +0300 Subject: [PATCH] Solve Vlagrind "definitely lost" memory leaks --- daemon/aux.c | 12 +++++- daemon/main.c | 90 +++++++++++++++++++++++++++++++---------- include/aux.h | 2 + lib/auxlib.c | 50 +++++++++++++++++++---- lib/auxlib.h | 3 ++ recording-daemon/main.c | 43 ++++++++++++++++---- recording-daemon/main.h | 8 ++-- 7 files changed, 167 insertions(+), 41 deletions(-) diff --git a/daemon/aux.c b/daemon/aux.c index 1f9005924..b744adfb5 100644 --- a/daemon/aux.c +++ b/daemon/aux.c @@ -141,8 +141,10 @@ void threads_join_all(int wait) { pthread_join(*t, NULL); threads_to_join = g_list_delete_link(threads_to_join, threads_to_join); l = g_list_find_custom(threads_running, t, thread_equal); - if (l) + if (l) { + g_slice_free1(sizeof(*t), l->data); threads_running = g_list_delete_link(threads_running, l); + } else abort(); g_slice_free1(sizeof(*t), t); @@ -264,3 +266,11 @@ void free_buf(char **p) { if (*p) free(*p); } + +void free_gbuf(char **p) { + g_free(*p); +} + +void free_gvbuf(char ***p) { + g_strfreev(*p); +} diff --git a/daemon/main.c b/daemon/main.c index 018ab2de4..f59d4d48c 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -68,14 +68,12 @@ struct rtpengine_config rtpe_config = { .redis_allowed_errors = -1, .redis_disable_time = 10, .redis_connect_timeout = 1000, - .rec_method = "pcap", - .rec_format = "raw", .media_num_threads = -1, .dtls_rsa_key_size = 2048, - .dtls_ciphers = "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK", .dtls_signature = 256, }; +char **if_a_global = NULL; static void sighandler(gpointer x) { sigset_t ss; @@ -288,32 +286,32 @@ static int redis_ep_parse(endpoint_t *ep, int *db, char **auth, const char *auth static void options(int *argc, char ***argv) { char **if_a = NULL; - char **ks_a = NULL; + AUTO_CLEANUP_GVBUF(ks_a); unsigned long uint_keyspace_db; str str_keyspace_db; char **iter; - char *listenps = NULL; - char *listenudps = NULL; - char *listenngs = NULL; - char *listencli = NULL; - char *graphitep = NULL; - char *graphite_prefix_s = NULL; - char *redisps = NULL; - char *redisps_write = NULL; - char *log_facility_cdr_s = NULL; - char *log_facility_rtcp_s = NULL; - char *log_facility_dtmf_s = NULL; - char *log_format = NULL; + AUTO_CLEANUP_GBUF(listenps); + AUTO_CLEANUP_GBUF(listenudps); + AUTO_CLEANUP_GBUF(listenngs); + AUTO_CLEANUP_GBUF(listencli); + AUTO_CLEANUP_GBUF(graphitep); + AUTO_CLEANUP_GBUF(graphite_prefix_s); + AUTO_CLEANUP_GBUF(redisps); + AUTO_CLEANUP_GBUF(redisps_write); + AUTO_CLEANUP_GBUF(log_facility_cdr_s); + AUTO_CLEANUP_GBUF(log_facility_rtcp_s); + AUTO_CLEANUP_GBUF(log_facility_dtmf_s); + AUTO_CLEANUP_GBUF(log_format); int sip_source = 0; - char *homerp = NULL; - char *homerproto = NULL; + AUTO_CLEANUP_GBUF(homerp); + AUTO_CLEANUP_GBUF(homerproto); char *endptr; int codecs = 0; double max_load = 0; double max_cpu = 0; - char *dtmf_udp_ep = NULL; - char *endpoint_learning = NULL; - char *dtls_sig = NULL; + AUTO_CLEANUP_GBUF(dtmf_udp_ep); + AUTO_CLEANUP_GBUF(endpoint_learning); + AUTO_CLEANUP_GBUF(dtls_sig); GOptionEntry e[] = { { "table", 't', 0, G_OPTION_ARG_INT, &rtpe_config.kernel_table, "Kernel table to use", "INT" }, @@ -394,6 +392,16 @@ static void options(int *argc, char ***argv) { config_load(argc, argv, e, " - next-generation media proxy", "/etc/rtpengine/rtpengine.conf", "rtpengine", &rtpe_config.common); + // default values, if not configured + if (rtpe_config.rec_method == NULL) + rtpe_config.rec_method = g_strdup("pcap"); + + if (rtpe_config.rec_format == NULL) + rtpe_config.rec_format = g_strdup("raw"); + + if (rtpe_config.dtls_ciphers == NULL) + rtpe_config.dtls_ciphers = g_strdup("DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK"); + if (codecs) { codeclib_init(1); exit(0); @@ -595,6 +603,9 @@ static void options(int *argc, char ***argv) { if (rtpe_config.jb_length < 0) die("Invalid negative jitter buffer size"); + + // free local vars + if_a_global = if_a; // -> content is used; needs to be freed later } void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { @@ -670,6 +681,39 @@ void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { ini_rtpe_cfg->jb_clock_drift = rtpe_config.jb_clock_drift; } +static void unfill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { + // free g_strdup + g_free(ini_rtpe_cfg->b2b_url); + g_free(ini_rtpe_cfg->redis_auth); + g_free(ini_rtpe_cfg->redis_write_auth); + g_free(ini_rtpe_cfg->spooldir); + g_free(ini_rtpe_cfg->iptables_chain); + g_free(ini_rtpe_cfg->rec_method); + g_free(ini_rtpe_cfg->rec_format); +} + +static void options_free(void) { + // free config options + g_free(rtpe_config.b2b_url); + g_free(rtpe_config.spooldir); + g_free(rtpe_config.rec_method); + g_free(rtpe_config.rec_format); + g_free(rtpe_config.iptables_chain); + g_free(rtpe_config.scheduling); + g_free(rtpe_config.idle_scheduling); + g_free(rtpe_config.mysql_host); + g_free(rtpe_config.mysql_user); + g_free(rtpe_config.mysql_pass); + g_free(rtpe_config.mysql_query); + g_free(rtpe_config.dtls_ciphers); + + // free common config options + config_load_free(&rtpe_config.common); + + // free if_a STRING LIST + g_strfreev(if_a_global); +} + static void early_init(void) { socket_init(); // needed for socktype_udp } @@ -905,5 +949,9 @@ int main(int argc, char **argv) { ilog(LOG_INFO, "Version %s shutting down", RTPENGINE_VERSION); + unfill_initial_rtpe_cfg(&initial_rtpe_config); + + options_free(); + return 0; } diff --git a/include/aux.h b/include/aux.h index 25e19ee15..21fc3da13 100644 --- a/include/aux.h +++ b/include/aux.h @@ -232,6 +232,8 @@ INLINE int rlim(int res, rlim_t val) { } void free_buf(char **); +void free_gbuf(char **); +void free_gvbuf(char ***); diff --git a/lib/auxlib.c b/lib/auxlib.c index 54b90a4af..8fc9a98d0 100644 --- a/lib/auxlib.c +++ b/lib/auxlib.c @@ -79,7 +79,7 @@ static unsigned int options_length(const GOptionEntry *arr) { #define CONF_OPTION_GLUE(get_func, data_type, ...) \ { \ data_type *varptr = e->arg_data; \ - data_type var = g_key_file_get_ ## get_func(kf, rtpe_common_config_ptr->config_section, e->long_name, \ + data_type var = g_key_file_get_ ## get_func(kf, use_section, e->long_name, \ ##__VA_ARGS__, &er); \ if (er && g_error_matches(er, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) { \ g_error_free(er); \ @@ -92,15 +92,25 @@ static unsigned int options_length(const GOptionEntry *arr) { break; \ } +void config_load_free(struct rtpengine_common_config *cconfig) { + // free common config options + g_free(cconfig->config_file); + g_free(cconfig->config_section); + g_free(cconfig->log_facility); + g_free(cconfig->log_mark_prefix); + g_free(cconfig->log_mark_suffix); + g_free(cconfig->pidfile); +} + void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char *description, char *default_config, char *default_section, struct rtpengine_common_config *cconfig) { GOptionContext *c; GError *er = NULL; + const char *use_section; const char *use_config; int fatal = 0; - int saved_argc = *argc; char **saved_argv = g_strdupv(*argv); rtpe_common_config_ptr = cconfig; @@ -111,8 +121,8 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char #else rtpe_common_config_ptr->log_level = LOG_DEBUG; #endif - rtpe_common_config_ptr->log_mark_prefix = ""; - rtpe_common_config_ptr->log_mark_suffix = ""; + + GKeyFile *kf = g_key_file_new(); GOptionEntry shared_options[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL }, @@ -137,8 +147,9 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char memcpy(entries, shared_options, sizeof(*entries) * shared_len); memcpy(&entries[shared_len], app_entries, sizeof(*entries) * (app_len + 1)); - if (!rtpe_common_config_ptr->config_section) - rtpe_common_config_ptr->config_section = default_section; + use_section = default_section; + if (rtpe_common_config_ptr->config_section) + use_section = rtpe_common_config_ptr->config_section; c = g_option_context_new(description); g_option_context_add_main_entries(c, entries, NULL); @@ -154,7 +165,6 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char fatal = 1; } - GKeyFile *kf = g_key_file_new(); if (!g_key_file_load_from_file(kf, use_config, G_KEY_FILE_NONE, &er)) { if (!fatal && (g_error_matches(er, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) || g_error_matches(er, G_FILE_ERROR, G_FILE_ERROR_NOENT))) @@ -185,14 +195,32 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char CONF_OPTION_GLUE(string_list, char **, NULL); default: + g_option_context_free(c); + g_strfreev(saved_argv); + g_key_file_free(kf); + free(entries); + config_load_free(rtpe_common_config_ptr); + abort(); } } // process CLI arguments again so they override options from the config file - g_option_context_parse(c, &saved_argc, &saved_argv, &er); + g_option_context_parse_strv(c, &saved_argv, &er); + + // default common values, if not configured + if (rtpe_common_config_ptr->log_mark_prefix == NULL) + rtpe_common_config_ptr->log_mark_prefix = g_strdup(""); + + if (rtpe_common_config_ptr->log_mark_suffix == NULL) + rtpe_common_config_ptr->log_mark_suffix = g_strdup(""); out: + g_option_context_free(c); + g_strfreev(saved_argv); + g_key_file_free(kf); + free(entries); + if (version) { fprintf(stderr, "Version: %s\n", RTPENGINE_VERSION); exit(0); @@ -218,6 +246,12 @@ out: return; err: + g_option_context_free(c); + g_strfreev(saved_argv); + g_key_file_free(kf); + free(entries); + config_load_free(rtpe_common_config_ptr); + die("Bad command line: %s", er->message); } diff --git a/lib/auxlib.h b/lib/auxlib.h index 68ae7661e..379425e90 100644 --- a/lib/auxlib.h +++ b/lib/auxlib.h @@ -42,6 +42,7 @@ extern volatile int rtpe_shutdown; void daemonize(void); void wpidfile(void); void service_notify(const char *message); +void config_load_free(struct rtpengine_common_config *); void config_load(int *argc, char ***argv, GOptionEntry *entries, const char *description, char *default_config, char *default_section, struct rtpengine_common_config *); @@ -64,6 +65,8 @@ int uint32_eq(const void *a, const void *b); #define AUTO_CLEANUP_INIT(decl, func, val) AUTO_CLEANUP(decl, func) = val #define AUTO_CLEANUP_NULL(decl, func) AUTO_CLEANUP_INIT(decl, func, 0) #define AUTO_CLEANUP_BUF(var) AUTO_CLEANUP_NULL(char *var, free_buf) +#define AUTO_CLEANUP_GBUF(var) AUTO_CLEANUP_NULL(char *var, free_gbuf) +#define AUTO_CLEANUP_GVBUF(var) AUTO_CLEANUP_NULL(char **var, free_gvbuf) /*** STRING HELPERS ***/ diff --git a/recording-daemon/main.c b/recording-daemon/main.c index e9e31af3f..c81357bf7 100644 --- a/recording-daemon/main.c +++ b/recording-daemon/main.c @@ -32,20 +32,20 @@ int ktable = 0; int num_threads = 8; enum output_storage_enum output_storage = OUTPUT_STORAGE_FILE; -const char *spool_dir = "/var/spool/rtpengine"; -const char *output_dir = "/var/lib/rtpengine-recording"; -static const char *output_format = "wav"; +char *spool_dir = NULL; +char *output_dir = NULL; +static char *output_format = NULL; int output_mixed; int output_single; int output_enabled = 1; int decoding_enabled; -const char *c_mysql_host, +char *c_mysql_host, *c_mysql_user, *c_mysql_pass, *c_mysql_db; int c_mysql_port; -const char *forward_to = NULL; -static const char *tls_send_to = NULL; +char *forward_to = NULL; +static char *tls_send_to = NULL; endpoint_t tls_send_to_ep; int tls_resample = 8000; @@ -144,7 +144,7 @@ static void cleanup(void) { static void options(int *argc, char ***argv) { - const char *os_str = NULL; + char *os_str = NULL; GOptionEntry e[] = { { "table", 't', 0, G_OPTION_ARG_INT, &ktable, "Kernel table rtpengine uses", "INT" }, @@ -171,6 +171,16 @@ static void options(int *argc, char ***argv) { config_load(argc, argv, e, " - rtpengine recording daemon", "/etc/rtpengine/rtpengine-recording.conf", "rtpengine-recording", &rtpe_common_config); + // default config, if not configured + if (spool_dir == NULL) + spool_dir = g_strdup("/var/spool/rtpengine"); + + if (output_dir == NULL) + output_dir = g_strdup("/var/lib/rtpengine-recording"); + + if (output_format == NULL) + output_format = g_strdup("wav"); + if (tls_send_to) { if (endpoint_parse_any_getaddrinfo_full(&tls_send_to_ep, tls_send_to)) die("Failed to parse 'tls-send-to' option"); @@ -202,8 +212,25 @@ static void options(int *argc, char ***argv) { if ((output_storage & OUTPUT_STORAGE_FILE) && !strcmp(output_dir, spool_dir)) die("The spool-dir cannot be the same as the output-dir"); + + g_free(os_str); } +static void options_free(void) { + // free config options + g_free(spool_dir); + g_free(output_dir); + g_free(output_format); + g_free(c_mysql_host); + g_free(c_mysql_user); + g_free(c_mysql_pass); + g_free(c_mysql_db); + g_free(forward_to); + g_free(tls_send_to); + + // free common config options + config_load_free(&rtpe_common_config); +} int main(int argc, char **argv) { options(&argc, &argv); @@ -223,5 +250,7 @@ int main(int argc, char **argv) { wait_threads_finish(); + options_free(); + cleanup(); } diff --git a/recording-daemon/main.h b/recording-daemon/main.h index aa683b4b0..3f124e429 100644 --- a/recording-daemon/main.h +++ b/recording-daemon/main.h @@ -15,18 +15,18 @@ enum output_storage_enum { extern int ktable; extern int num_threads; extern enum output_storage_enum output_storage; -extern const char *spool_dir; -extern const char *output_dir; +extern char *spool_dir; +extern char *output_dir; extern int output_mixed; extern int output_single; extern int output_enabled; extern int decoding_enabled; -extern const char *c_mysql_host, +extern char *c_mysql_host, *c_mysql_user, *c_mysql_pass, *c_mysql_db; extern int c_mysql_port; -extern const char *forward_to; +extern char *forward_to; extern endpoint_t tls_send_to_ep; extern int tls_resample;