Skip to content

Commit 689d993

Browse files
committed
Work around unportable behavior of malloc(0) and realloc(NULL, 0).
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.
1 parent 87b6a39 commit 689d993

File tree

11 files changed

+106
-43
lines changed

11 files changed

+106
-43
lines changed

contrib/oid2name/oid2name.c

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ struct options
4949
/* function prototypes */
5050
static void help(const char *progname);
5151
void get_opts(int, char **, struct options *);
52-
void *myalloc(size_t size);
53-
char *mystrdup(const char *str);
52+
void *pg_malloc(size_t size);
53+
void *pg_realloc(void *ptr, size_t size);
54+
char *pg_strdup(const char *str);
5455
void add_one_elt(char *eltname, eary *eary);
5556
char *get_comma_elts(eary *eary);
5657
PGconn *sql_conn(struct options *);
@@ -102,7 +103,7 @@ get_opts(int argc, char **argv, struct options * my_opts)
102103
{
103104
/* specify the database */
104105
case 'd':
105-
my_opts->dbname = mystrdup(optarg);
106+
my_opts->dbname = pg_strdup(optarg);
106107
break;
107108

108109
/* specify one tablename to show */
@@ -127,17 +128,17 @@ get_opts(int argc, char **argv, struct options * my_opts)
127128

128129
/* host to connect to */
129130
case 'H':
130-
my_opts->hostname = mystrdup(optarg);
131+
my_opts->hostname = pg_strdup(optarg);
131132
break;
132133

133134
/* port to connect to on remote host */
134135
case 'p':
135-
my_opts->port = mystrdup(optarg);
136+
my_opts->port = pg_strdup(optarg);
136137
break;
137138

138139
/* username */
139140
case 'U':
140-
my_opts->username = mystrdup(optarg);
141+
my_opts->username = pg_strdup(optarg);
141142
break;
142143

143144
/* display system tables */
@@ -199,26 +200,47 @@ help(const char *progname)
199200
}
200201

201202
void *
202-
myalloc(size_t size)
203+
pg_malloc(size_t size)
203204
{
204-
void *ptr = malloc(size);
205+
void *ptr;
205206

207+
/* Avoid unportable behavior of malloc(0) */
208+
if (size == 0)
209+
size = 1;
210+
ptr = malloc(size);
206211
if (!ptr)
207212
{
208-
fprintf(stderr, "out of memory");
213+
fprintf(stderr, "out of memory\n");
209214
exit(1);
210215
}
211216
return ptr;
212217
}
213218

219+
void *
220+
pg_realloc(void *ptr, size_t size)
221+
{
222+
void *result;
223+
224+
/* Avoid unportable behavior of realloc(NULL, 0) */
225+
if (ptr == NULL && size == 0)
226+
size = 1;
227+
result = realloc(ptr, size);
228+
if (!result)
229+
{
230+
fprintf(stderr, "out of memory\n");
231+
exit(1);
232+
}
233+
return result;
234+
}
235+
214236
char *
215-
mystrdup(const char *str)
237+
pg_strdup(const char *str)
216238
{
217239
char *result = strdup(str);
218240

219241
if (!result)
220242
{
221-
fprintf(stderr, "out of memory");
243+
fprintf(stderr, "out of memory\n");
222244
exit(1);
223245
}
224246
return result;
@@ -235,22 +257,16 @@ add_one_elt(char *eltname, eary *eary)
235257
if (eary->alloc == 0)
236258
{
237259
eary ->alloc = 8;
238-
eary ->array = (char **) myalloc(8 * sizeof(char *));
260+
eary ->array = (char **) pg_malloc(8 * sizeof(char *));
239261
}
240262
else if (eary->num >= eary->alloc)
241263
{
242264
eary ->alloc *= 2;
243-
eary ->array = (char **)
244-
realloc(eary->array, eary->alloc * sizeof(char *));
245-
246-
if (!eary->array)
247-
{
248-
fprintf(stderr, "out of memory");
249-
exit(1);
250-
}
265+
eary ->array = (char **) pg_realloc(eary->array,
266+
eary->alloc * sizeof(char *));
251267
}
252268

253-
eary ->array[eary->num] = mystrdup(eltname);
269+
eary ->array[eary->num] = pg_strdup(eltname);
254270
eary ->num++;
255271
}
256272

@@ -270,7 +286,7 @@ get_comma_elts(eary *eary)
270286
length = 0;
271287

272288
if (eary->num == 0)
273-
return mystrdup("");
289+
return pg_strdup("");
274290

275291
/*
276292
* PQescapeString wants 2 * length + 1 bytes of breath space. Add two
@@ -279,7 +295,7 @@ get_comma_elts(eary *eary)
279295
for (i = 0; i < eary->num; i++)
280296
length += strlen(eary->array[i]);
281297

282-
ret = (char *) myalloc(length * 2 + 4 * eary->num);
298+
ret = (char *) pg_malloc(length * 2 + 4 * eary->num);
283299
ptr = ret;
284300

285301
for (i = 0; i < eary->num; i++)
@@ -384,7 +400,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
384400
nfields = PQnfields(res);
385401

386402
/* for each field, get the needed width */
387-
length = (int *) myalloc(sizeof(int) * nfields);
403+
length = (int *) pg_malloc(sizeof(int) * nfields);
388404
for (j = 0; j < nfields; j++)
389405
length[j] = strlen(PQfname(res, j));
390406

@@ -407,7 +423,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
407423
l += length[j] + 2;
408424
}
409425
fprintf(stdout, "\n");
410-
pad = (char *) myalloc(l + 1);
426+
pad = (char *) pg_malloc(l + 1);
411427
MemSet(pad, '-', l);
412428
pad[l] = '\0';
413429
fprintf(stdout, "%s\n", pad);
@@ -498,8 +514,8 @@ sql_exec_searchtables(PGconn *conn, struct options * opts)
498514
comma_filenodes = get_comma_elts(opts->filenodes);
499515

500516
/* 80 extra chars for SQL expression */
501-
qualifiers = (char *) myalloc(strlen(comma_oids) + strlen(comma_tables) +
502-
strlen(comma_filenodes) + 80);
517+
qualifiers = (char *) pg_malloc(strlen(comma_oids) + strlen(comma_tables) +
518+
strlen(comma_filenodes) + 80);
503519
ptr = qualifiers;
504520

505521
if (opts->oids->num > 0)
@@ -525,7 +541,7 @@ sql_exec_searchtables(PGconn *conn, struct options * opts)
525541
free(comma_filenodes);
526542

527543
/* now build the query */
528-
todo = (char *) myalloc(650 + strlen(qualifiers));
544+
todo = (char *) pg_malloc(650 + strlen(qualifiers));
529545
snprintf(todo, 650 + strlen(qualifiers),
530546
"SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s\n"
531547
"FROM pg_catalog.pg_class c \n"
@@ -565,11 +581,11 @@ main(int argc, char **argv)
565581
struct options *my_opts;
566582
PGconn *pgconn;
567583

568-
my_opts = (struct options *) myalloc(sizeof(struct options));
584+
my_opts = (struct options *) pg_malloc(sizeof(struct options));
569585

570-
my_opts->oids = (eary *) myalloc(sizeof(eary));
571-
my_opts->tables = (eary *) myalloc(sizeof(eary));
572-
my_opts->filenodes = (eary *) myalloc(sizeof(eary));
586+
my_opts->oids = (eary *) pg_malloc(sizeof(eary));
587+
my_opts->tables = (eary *) pg_malloc(sizeof(eary));
588+
my_opts->filenodes = (eary *) pg_malloc(sizeof(eary));
573589

574590
my_opts->oids->num = my_opts->oids->alloc = 0;
575591
my_opts->tables->num = my_opts->tables->alloc = 0;

contrib/pg_upgrade/util.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,33 +192,39 @@ get_user_info(char **user_name)
192192

193193

194194
void *
195-
pg_malloc(size_t n)
195+
pg_malloc(size_t size)
196196
{
197-
void *p = malloc(n);
197+
void *p;
198198

199+
/* Avoid unportable behavior of malloc(0) */
200+
if (size == 0)
201+
size = 1;
202+
p = malloc(size);
199203
if (p == NULL)
200204
pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
201-
202205
return p;
203206
}
204207

205208
void *
206-
pg_realloc(void *ptr, size_t n)
209+
pg_realloc(void *ptr, size_t size)
207210
{
208-
void *p = realloc(ptr, n);
211+
void *p;
209212

213+
/* Avoid unportable behavior of realloc(NULL, 0) */
214+
if (ptr == NULL && size == 0)
215+
size = 1;
216+
p = realloc(ptr, size);
210217
if (p == NULL)
211218
pg_log(PG_FATAL, "%s: out of memory\n", os_info.progname);
212-
213219
return p;
214220
}
215221

216222

217223
void
218-
pg_free(void *p)
224+
pg_free(void *ptr)
219225
{
220-
if (p != NULL)
221-
free(p);
226+
if (ptr != NULL)
227+
free(ptr);
222228
}
223229

224230

contrib/pgbench/pgbench.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ xmalloc(size_t size)
295295
{
296296
void *result;
297297

298+
/* Avoid unportable behavior of malloc(0) */
299+
if (size == 0)
300+
size = 1;
298301
result = malloc(size);
299302
if (!result)
300303
{
@@ -309,6 +312,9 @@ xrealloc(void *ptr, size_t size)
309312
{
310313
void *result;
311314

315+
/* Avoid unportable behavior of realloc(NULL, 0) */
316+
if (ptr == NULL && size == 0)
317+
size = 1;
312318
result = realloc(ptr, size);
313319
if (!result)
314320
{

src/backend/utils/misc/guc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3352,6 +3352,9 @@ guc_malloc(int elevel, size_t size)
33523352
{
33533353
void *data;
33543354

3355+
/* Avoid unportable behavior of malloc(0) */
3356+
if (size == 0)
3357+
size = 1;
33553358
data = malloc(size);
33563359
if (data == NULL)
33573360
ereport(elevel,
@@ -3365,6 +3368,9 @@ guc_realloc(int elevel, void *old, size_t size)
33653368
{
33663369
void *data;
33673370

3371+
/* Avoid unportable behavior of realloc(NULL, 0) */
3372+
if (old == NULL && size == 0)
3373+
size = 1;
33683374
data = realloc(old, size);
33693375
if (data == NULL)
33703376
ereport(elevel,

src/bin/initdb/initdb.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ pg_malloc(size_t size)
285285
{
286286
void *result;
287287

288+
/* Avoid unportable behavior of malloc(0) */
289+
if (size == 0)
290+
size = 1;
288291
result = malloc(size);
289292
if (!result)
290293
{

src/bin/pg_basebackup/streamutil.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ xmalloc0(int size)
5454
{
5555
void *result;
5656

57+
/* Avoid unportable behavior of malloc(0) */
58+
if (size == 0)
59+
size = 1;
5760
result = malloc(size);
5861
if (!result)
5962
{

src/bin/pg_ctl/pg_ctl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ pg_malloc(size_t size)
233233
{
234234
void *result;
235235

236+
/* Avoid unportable behavior of malloc(0) */
237+
if (size == 0)
238+
size = 1;
236239
result = malloc(size);
237240
if (!result)
238241
{

src/bin/pg_dump/dumpmem.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ pg_malloc(size_t size)
4242
{
4343
void *tmp;
4444

45+
/* Avoid unportable behavior of malloc(0) */
46+
if (size == 0)
47+
size = 1;
4548
tmp = malloc(size);
4649
if (!tmp)
4750
exit_horribly(NULL, "out of memory\n");
@@ -64,6 +67,9 @@ pg_realloc(void *ptr, size_t size)
6467
{
6568
void *tmp;
6669

70+
/* Avoid unportable behavior of realloc(NULL, 0) */
71+
if (ptr == NULL && size == 0)
72+
size = 1;
6773
tmp = realloc(ptr, size);
6874
if (!tmp)
6975
exit_horribly(NULL, "out of memory\n");

src/bin/psql/common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pg_malloc(size_t size)
6060
{
6161
void *tmp;
6262

63+
/* Avoid unportable behavior of malloc(0) */
64+
if (size == 0)
65+
size = 1;
6366
tmp = malloc(size);
6467
if (!tmp)
6568
{

src/bin/psql/print.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ pg_local_malloc(size_t size)
136136
{
137137
void *tmp;
138138

139+
/* Avoid unportable behavior of malloc(0) */
140+
if (size == 0)
141+
size = 1;
139142
tmp = malloc(size);
140143
if (!tmp)
141144
{

src/port/dirmod.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ fe_palloc(Size size)
7070
{
7171
void *res;
7272

73-
if ((res = malloc(size)) == NULL)
73+
/* Avoid unportable behavior of malloc(0) */
74+
if (size == 0)
75+
size = 1;
76+
res = malloc(size);
77+
if (res == NULL)
7478
{
7579
fprintf(stderr, _("out of memory\n"));
7680
exit(1);
@@ -96,7 +100,11 @@ fe_repalloc(void *pointer, Size size)
96100
{
97101
void *res;
98102

99-
if ((res = realloc(pointer, size)) == NULL)
103+
/* Avoid unportable behavior of realloc(NULL, 0) */
104+
if (pointer == NULL && size == 0)
105+
size = 1;
106+
res = realloc(pointer, size);
107+
if (res == NULL)
100108
{
101109
fprintf(stderr, _("out of memory\n"));
102110
exit(1);

0 commit comments

Comments
 (0)