Fix assorted memory leaks in pg_hba.conf parsing. Over a sufficiently
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 3 Oct 2009 20:04:39 +0000 (20:04 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 3 Oct 2009 20:04:39 +0000 (20:04 +0000)
large number of SIGHUP cycles, these would have run the postmaster out
of memory.  Noted while testing memory-leak scenario in postgresql.conf
configuration-change-printing patch.

src/backend/libpq/hba.c

index 43b5e04b46f152d519c6ec87252a2655b74c289b..a51ea53082b423606dfd15297a223b0bcdc7acf4 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.191 2009/10/01 01:58:57 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.192 2009/10/03 20:04:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -804,16 +804,12 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                                token, gai_strerror(ret)),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
-               if (cidr_slash)
-                   *cidr_slash = '/';
                if (gai_result)
                    pg_freeaddrinfo_all(hints.ai_family, gai_result);
+               pfree(token);
                return false;
            }
 
-           if (cidr_slash)
-               *cidr_slash = '/';
-
            memcpy(&parsedline->addr, gai_result->ai_addr,
                   gai_result->ai_addrlen);
            pg_freeaddrinfo_all(hints.ai_family, gai_result);
@@ -824,18 +820,22 @@ parse_hba_line(List *line, int line_num, HbaLine *parsedline)
                if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
                                          parsedline->addr.ss_family) < 0)
                {
+                   *cidr_slash = '/';      /* restore token for message */
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("invalid CIDR mask in address \"%s\"",
                                    token),
                             errcontext("line %d of configuration file \"%s\"",
                                        line_num, HbaFileName)));
+                   pfree(token);
                    return false;
                }
+               pfree(token);
            }
            else
            {
                /* Read the mask field. */
+               pfree(token);
                line_item = lnext(line_item);
                if (!line_item)
                {
@@ -1266,7 +1266,7 @@ check_hba(hbaPort *port)
 }
 
 /*
- * Free the contents of a hba record
+ * Free an HbaLine structure
  */
 static void
 free_hba_record(HbaLine *record)
@@ -1275,6 +1275,8 @@ free_hba_record(HbaLine *record)
        pfree(record->database);
    if (record->role)
        pfree(record->role);
+   if (record->usermap)
+       pfree(record->usermap);
    if (record->pamservice)
        pfree(record->pamservice);
    if (record->ldapserver)
@@ -1287,6 +1289,7 @@ free_hba_record(HbaLine *record)
        pfree(record->krb_server_hostname);
    if (record->krb_realm)
        pfree(record->krb_realm);
+   pfree(record);
 }
 
 /*
@@ -1355,20 +1358,22 @@ load_hba(void)
        {
            /* Parse error in the file, so indicate there's a problem */
            free_hba_record(newline);
-           pfree(newline);
+           ok = false;
 
            /*
             * Keep parsing the rest of the file so we can report errors on
             * more than the first row. Error has already been reported in the
             * parsing function, so no need to log it here.
             */
-           ok = false;
            continue;
        }
 
        new_parsed_lines = lappend(new_parsed_lines, newline);
    }
 
+   /* Free the temporary lists */
+   free_lines(&hba_lines, &hba_line_nums);
+
    if (!ok)
    {
        /* Parsing failed at one or more rows, so bail out */
@@ -1380,9 +1385,6 @@ load_hba(void)
    clean_hba_list(parsed_hba_lines);
    parsed_hba_lines = new_parsed_lines;
 
-   /* Free the temporary lists */
-   free_lines(&hba_lines, &hba_line_nums);
-
    return true;
 }