Work around unportable behavior of malloc(0) and realloc(NULL, 0).
authorTom Lane
Tue, 2 Oct 2012 21:31:49 +0000 (17:31 -0400)
committerTom Lane
Tue, 2 Oct 2012 21:31:49 +0000 (17:31 -0400)
On some platforms these functions return NULL, rather than the more common
practice of returning a pointer to a zero-sized block of memory.  Hack our
various wrapper functions to hide the difference by substituting a size
request of 1.  This is probably not so important for the callers, who
should never touch the block anyway if they asked for size 0 --- but it's
important for the wrapper functions themselves, which mistakenly treated
the NULL result as an out-of-memory failure.  This broke at least pg_dump
for the case of no user-defined aggregates, as per report from
Matthew Carrington.

Back-patch to 9.2 to fix the pg_dump issue.  Given the lack of previous
complaints, it seems likely that there is no live bug in previous releases,
even though some of these functions were in place before that.

contrib/oid2name/oid2name.c
contrib/pg_upgrade/util.c
contrib/pgbench/pgbench.c
src/backend/utils/misc/guc.c
src/bin/initdb/initdb.c
src/bin/pg_basebackup/streamutil.c
src/bin/pg_ctl/pg_ctl.c
src/bin/pg_dump/dumpmem.c
src/bin/psql/common.c
src/bin/psql/print.c
src/port/dirmod.c

index e8a389e49e796ca8d492641a08da63ae433bba41..74e60f23fba95faa1cd1467b8f5f7c5f6d3a54af 100644 (file)
@@ -49,8 +49,9 @@ struct options
 /* function prototypes */
 static void help(const char *progname);
 void       get_opts(int, char **, struct options *);
-void      *myalloc(size_t size);
-char      *mystrdup(const char *str);
+void      *pg_malloc(size_t size);
+void      *pg_realloc(void *ptr, size_t size);
+char      *pg_strdup(const char *str);
 void       add_one_elt(char *eltname, eary *eary);
 char      *get_comma_elts(eary *eary);
 PGconn    *sql_conn(struct options *);
@@ -102,7 +103,7 @@ get_opts(int argc, char **argv, struct options * my_opts)
        {
                /* specify the database */
            case 'd':
-               my_opts->dbname = mystrdup(optarg);
+               my_opts->dbname = pg_strdup(optarg);
                break;
 
                /* specify one tablename to show */
@@ -127,17 +128,17 @@ get_opts(int argc, char **argv, struct options * my_opts)
 
                /* host to connect to */
            case 'H':
-               my_opts->hostname = mystrdup(optarg);
+               my_opts->hostname = pg_strdup(optarg);
                break;
 
                /* port to connect to on remote host */
            case 'p':
-               my_opts->port = mystrdup(optarg);
+               my_opts->port = pg_strdup(optarg);
                break;
 
                /* username */
            case 'U':
-               my_opts->username = mystrdup(optarg);
+               my_opts->username = pg_strdup(optarg);
                break;
 
                /* display system tables */
@@ -199,26 +200,47 @@ help(const char *progname)
 }
 
 void *
-myalloc(size_t size)
+pg_malloc(size_t size)
 {
-   void       *ptr = malloc(size);
+   void       *ptr;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
+   ptr = malloc(size);
    if (!ptr)
    {
-       fprintf(stderr, "out of memory");
+       fprintf(stderr, "out of memory\n");
        exit(1);
    }
    return ptr;
 }
 
+void *
+pg_realloc(void *ptr, size_t size)
+{
+   void       *result;
+
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (ptr == NULL && size == 0)
+       size = 1;
+   result = realloc(ptr, size);
+   if (!result)
+   {
+       fprintf(stderr, "out of memory\n");
+       exit(1);
+   }
+   return result;
+}
+
 char *
-mystrdup(const char *str)
+pg_strdup(const char *str)
 {
    char       *result = strdup(str);
 
    if (!result)
    {
-       fprintf(stderr, "out of memory");
+       fprintf(stderr, "out of memory\n");
        exit(1);
    }
    return result;
@@ -235,22 +257,16 @@ add_one_elt(char *eltname, eary *eary)
    if (eary->alloc == 0)
    {
        eary      ->alloc = 8;
-       eary      ->array = (char **) myalloc(8 * sizeof(char *));
+       eary      ->array = (char **) pg_malloc(8 * sizeof(char *));
    }
    else if (eary->num >= eary->alloc)
    {
        eary      ->alloc *= 2;
-       eary      ->array = (char **)
-       realloc(eary->array, eary->alloc * sizeof(char *));
-
-       if (!eary->array)
-       {
-           fprintf(stderr, "out of memory");
-           exit(1);
-       }
+       eary      ->array = (char **) pg_realloc(eary->array,
+                                                eary->alloc * sizeof(char *));
    }
 
-   eary      ->array[eary->num] = mystrdup(eltname);
+   eary      ->array[eary->num] = pg_strdup(eltname);
    eary      ->num++;
 }
 
@@ -270,7 +286,7 @@ get_comma_elts(eary *eary)
                length = 0;
 
    if (eary->num == 0)
-       return mystrdup("");
+       return pg_strdup("");
 
    /*
     * PQescapeString wants 2 * length + 1 bytes of breath space.  Add two
@@ -279,7 +295,7 @@ get_comma_elts(eary *eary)
    for (i = 0; i < eary->num; i++)
        length += strlen(eary->array[i]);
 
-   ret = (char *) myalloc(length * 2 + 4 * eary->num);
+   ret = (char *) pg_malloc(length * 2 + 4 * eary->num);
    ptr = ret;
 
    for (i = 0; i < eary->num; i++)
@@ -384,7 +400,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
    nfields = PQnfields(res);
 
    /* for each field, get the needed width */
-   length = (int *) myalloc(sizeof(int) * nfields);
+   length = (int *) pg_malloc(sizeof(int) * nfields);
    for (j = 0; j < nfields; j++)
        length[j] = strlen(PQfname(res, j));
 
@@ -407,7 +423,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
            l += length[j] + 2;
        }
        fprintf(stdout, "\n");
-       pad = (char *) myalloc(l + 1);
+       pad = (char *) pg_malloc(l + 1);
        MemSet(pad, '-', l);
        pad[l] = '\0';
        fprintf(stdout, "%s\n", pad);
@@ -498,8 +514,8 @@ sql_exec_searchtables(PGconn *conn, struct options * opts)
    comma_filenodes = get_comma_elts(opts->filenodes);
 
    /* 80 extra chars for SQL expression */
-   qualifiers = (char *) myalloc(strlen(comma_oids) + strlen(comma_tables) +
-                                 strlen(comma_filenodes) + 80);
+   qualifiers = (char *) pg_malloc(strlen(comma_oids) + strlen(comma_tables) +
+                                   strlen(comma_filenodes) + 80);
    ptr = qualifiers;
 
    if (opts->oids->num > 0)
@@ -525,7 +541,7 @@ sql_exec_searchtables(PGconn *conn, struct options * opts)
    free(comma_filenodes);
 
    /* now build the query */
-   todo = (char *) myalloc(650 + strlen(qualifiers));
+   todo = (char *) pg_malloc(650 + strlen(qualifiers));
    snprintf(todo, 650 + strlen(qualifiers),
             "SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s\n"
             "FROM pg_catalog.pg_class c \n"
@@ -565,11 +581,11 @@ main(int argc, char **argv)
    struct options *my_opts;
    PGconn     *pgconn;
 
-   my_opts = (struct options *) myalloc(sizeof(struct options));
+   my_opts = (struct options *) pg_malloc(sizeof(struct options));
 
-   my_opts->oids = (eary *) myalloc(sizeof(eary));
-   my_opts->tables = (eary *) myalloc(sizeof(eary));
-   my_opts->filenodes = (eary *) myalloc(sizeof(eary));
+   my_opts->oids = (eary *) pg_malloc(sizeof(eary));
+   my_opts->tables = (eary *) pg_malloc(sizeof(eary));
+   my_opts->filenodes = (eary *) pg_malloc(sizeof(eary));
 
    my_opts->oids->num = my_opts->oids->alloc = 0;
    my_opts->tables->num = my_opts->tables->alloc = 0;
index d879e762fa24915c4686fd7557770c1fb8efb099..1d4bc89f0bf7f1ff1639bbe2e53d52f9e20322e3 100644 (file)
@@ -192,33 +192,39 @@ get_user_info(char **user_name)
 
 
 void *
-pg_malloc(size_t n)
+pg_malloc(size_t size)
 {
-   void       *p = malloc(n);
+   void       *p;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
+   p = malloc(size);
    if (p == NULL)
        pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
-
    return p;
 }
 
 void *
-pg_realloc(void *ptr, size_t n)
+pg_realloc(void *ptr, size_t size)
 {
-   void       *p = realloc(ptr, n);
+   void       *p;
 
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (ptr == NULL && size == 0)
+       size = 1;
+   p = realloc(ptr, size);
    if (p == NULL)
        pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
-
    return p;
 }
 
 
 void
-pg_free(void *p)
+pg_free(void *ptr)
 {
-   if (p != NULL)
-       free(p);
+   if (ptr != NULL)
+       free(ptr);
 }
 
 
index f2fdc6c56f67acb9f56a72eb23d08349fd301cd3..e177e16c41358c4b0ba0db166a8a8d068c503f43 100644 (file)
@@ -295,6 +295,9 @@ xmalloc(size_t size)
 {
    void       *result;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    result = malloc(size);
    if (!result)
    {
@@ -309,6 +312,9 @@ xrealloc(void *ptr, size_t size)
 {
    void       *result;
 
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (ptr == NULL && size == 0)
+       size = 1;
    result = realloc(ptr, size);
    if (!result)
    {
index 7f54d452eae9ee273ab13eb753873f714a13b617..9ab13475575ca799039701d0570940d43295e773 100644 (file)
@@ -3352,6 +3352,9 @@ guc_malloc(int elevel, size_t size)
 {
    void       *data;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    data = malloc(size);
    if (data == NULL)
        ereport(elevel,
@@ -3365,6 +3368,9 @@ guc_realloc(int elevel, void *old, size_t size)
 {
    void       *data;
 
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (old == NULL && size == 0)
+       size = 1;
    data = realloc(old, size);
    if (data == NULL)
        ereport(elevel,
index 74046b5dfea14212e499fead39321821e75b040e..a2f16a01c3c8f79b167b0e8a9e9180dfbe7e3f29 100644 (file)
@@ -285,6 +285,9 @@ pg_malloc(size_t size)
 {
    void       *result;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    result = malloc(size);
    if (!result)
    {
index c32c5acb2b9db58a7e0fa14dea0d42017e12058d..e5fd6fd76554a172555484d632b14d210f121d86 100644 (file)
@@ -54,6 +54,9 @@ xmalloc0(int size)
 {
    void       *result;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    result = malloc(size);
    if (!result)
    {
index 72fc4c1abf6ae80b92aafea727c9f07d36d9efb3..b288e9a8a633da427804717e1f550b1749b52310 100644 (file)
@@ -233,6 +233,9 @@ pg_malloc(size_t size)
 {
    void       *result;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    result = malloc(size);
    if (!result)
    {
index 3ef10307bc5c499c848541863d575a119e7fe47e..cadc89d4447a0593f01583c70b3b778be9567c04 100644 (file)
@@ -42,6 +42,9 @@ pg_malloc(size_t size)
 {
    void       *tmp;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    tmp = malloc(size);
    if (!tmp)
        exit_horribly(NULL, "out of memory\n");
@@ -64,6 +67,9 @@ pg_realloc(void *ptr, size_t size)
 {
    void       *tmp;
 
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (ptr == NULL && size == 0)
+       size = 1;
    tmp = realloc(ptr, size);
    if (!tmp)
        exit_horribly(NULL, "out of memory\n");
index 330d5ce12cfa793407013923f258bba965fb89db..c804148cd575623c64caa85a15345f1eb5a4c032 100644 (file)
@@ -60,6 +60,9 @@ pg_malloc(size_t size)
 {
    void       *tmp;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    tmp = malloc(size);
    if (!tmp)
    {
index 8fa5e371284e67c3236d54a8d3329ec83019e06e..6da3ba053e0ecbf484e40755fdb6744f1b2589d6 100644 (file)
@@ -136,6 +136,9 @@ pg_local_malloc(size_t size)
 {
    void       *tmp;
 
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
    tmp = malloc(size);
    if (!tmp)
    {
index 22f5c591b07302748bbb89e37bcb6dca1e8b3f32..514424f82e635dd721b184e009dccce1a4d52bf7 100644 (file)
@@ -70,7 +70,11 @@ fe_palloc(Size size)
 {
    void       *res;
 
-   if ((res = malloc(size)) == NULL)
+   /* Avoid unportable behavior of malloc(0) */
+   if (size == 0)
+       size = 1;
+   res = malloc(size);
+   if (res == NULL)
    {
        fprintf(stderr, _("out of memory\n"));
        exit(1);
@@ -96,7 +100,11 @@ fe_repalloc(void *pointer, Size size)
 {
    void       *res;
 
-   if ((res = realloc(pointer, size)) == NULL)
+   /* Avoid unportable behavior of realloc(NULL, 0) */
+   if (pointer == NULL && size == 0)
+       size = 1;
+   res = realloc(pointer, size);
+   if (res == NULL)
    {
        fprintf(stderr, _("out of memory\n"));
        exit(1);