fix: free main command setup state

Amolith created

Use owned GLib strings for parsed options and release config, account,
password, jid, and copied mode arguments on normal and key early exits.

Amp-Thread-ID: https://ampcode.com/threads/T-019f2fe4-f392-7688-8b2f-8d40eb9fa4b8

Change summary

src/main.c | 61 +++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 43 insertions(+), 18 deletions(-)

Detailed changes

src/main.c 🔗

@@ -355,6 +355,12 @@ int main(int argc, char *argv[]) {
   char *jid = NULL;
   char *pwd = NULL;
   char *account = NULL;
+  GKeyFile *config_file = NULL;
+  GString *configfile = NULL;
+  GError *error = NULL;
+  int paramc = 0;
+  char **paramv = NULL;
+  int exit_code = EXIT_FAILURE;
 
   static struct option long_options[] = {
       /* These options set a flag. */
@@ -382,7 +388,8 @@ int main(int argc, char *argv[]) {
       switch (c) {
       case 'h':
         _show_help();
-        return EXIT_SUCCESS;
+        exit_code = EXIT_SUCCESS;
+        goto cleanup;
 
       case 'c':
         printf("option -c with value `%s'\n", optarg);
@@ -393,13 +400,13 @@ int main(int argc, char *argv[]) {
         break;
 
       case 'a':
-        account = malloc(strlen(optarg) + 1);
-        strcpy(account, optarg);
+        g_free(account);
+        account = g_strdup(optarg);
         break;
 
       case 'j':
-        jid = malloc(strlen(optarg) + 1);
-        strcpy(jid, optarg);
+        g_free(jid);
+        jid = g_strdup(optarg);
         break;
 
       case 'p':
@@ -433,9 +440,8 @@ int main(int argc, char *argv[]) {
   }
 
   // Loading config file
-  GKeyFile *config_file = g_key_file_new();
-  GError *error = NULL;
-  GString* configfile = g_string_new( g_get_home_dir());
+  config_file = g_key_file_new();
+  configfile = g_string_new( g_get_home_dir());
   g_string_append(configfile,"/.config/xmppc.conf");
   gboolean configfilefound = g_key_file_load_from_file(
     config_file,
@@ -446,12 +452,12 @@ int main(int argc, char *argv[]) {
   if (!configfilefound) {
    if(error && !g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
       logError(&xmppc, "Error loading key file: %s\n", error->message);
-      return EXIT_FAILURE;
+      goto cleanup;
     }
     if(jid == NULL && account == NULL) {
       printf("You need either --jid or --account parameter or a default account\n");
       _show_help();
-      return EXIT_FAILURE;
+      goto cleanup;
     }
   }
   g_clear_error(&error);
@@ -459,13 +465,13 @@ int main(int argc, char *argv[]) {
   if(account != NULL || (jid == NULL && pwd == NULL)) {
     logInfo(&xmppc,"Loading default account\n");
     if( account == NULL ) {
-      account = "default";
+      account = g_strdup("default");
     }
     if (jid == NULL) {
       jid = g_key_file_get_value (config_file, account, "jid" ,&error);
       if( error ) {
         logError(&xmppc, "No jid found in configuration file. %s\n", error->message);
-        return EXIT_FAILURE;
+        goto cleanup;
       }
       g_clear_error(&error);
     }
@@ -508,12 +514,11 @@ int main(int argc, char *argv[]) {
     printf("\n");
   }
 
-  int paramc = argc- optind;
-  char* paramv[paramc];
+  paramc = argc- optind;
+  paramv = g_new0(char *, paramc);
 
   for (int i = optind; i < argc; i++) {
-    char* x= malloc(strlen(argv[i])+1 *sizeof(char)  );
-    strcpy(x,argv[i]);
+    char* x= g_strdup(argv[i]);
     paramv[i-optind] = x;
   }
   xmppc_context(&xmppc, verbose_flag);
@@ -531,7 +536,10 @@ int main(int argc, char *argv[]) {
 
   if( handler == NULL ) {
     logError(&xmppc, "Unknown mode\n");
-    return -1;
+    xmpp_conn_release(xmppc.conn);
+    xmpp_ctx_free(xmppc.ctx);
+    xmpp_shutdown();
+    goto cleanup;
   } 
 
   callback_t callback = {paramc, paramv, handler, &xmppc};
@@ -552,10 +560,27 @@ int main(int argc, char *argv[]) {
   xmpp_ctx_free(xmppc.ctx);
   xmpp_shutdown();
 
+  exit_code = EXIT_SUCCESS;
+
+cleanup:
+  if (paramv) {
+    for (int i = 0; i < paramc; i++) {
+      g_free(paramv[i]);
+    }
+    g_free(paramv);
+  }
+  if (config_file) {
+    g_key_file_free(config_file);
+  }
+  if (configfile) {
+    g_string_free(configfile, TRUE);
+  }
+  g_clear_error(&error);
+  g_free(account);
   g_free(jid);
   g_free(pwd);
 
-  return EXIT_SUCCESS;
+  return exit_code;
 }
 
 static int _agent_skill_command(int argc, char *argv[]) {