Subject: Use pg_malloc macros in src/fe_utils

From: Henrik TJ <[email-masked]>
Date: Wed, 18 Feb 2026 16:05:09 +0100 (CET)

Hi

Inspired by [1], I took a stab at converting src/fe_utils to the new 
pg_malloc macros.

Some mostly useless metrics: 31/34 converted, 7 casts removed.

meson test looks good for me.

1. https://www.postgresql.org/message-id/flat/CAHut%2BPvpGPDLhkHAoxw_g3jdrYxA1m16a8uagbgH3TGWSKtXNQ%40mail.gmail.com

   best regards, Henrik

From 6ad0e5be35029a1aa32452cfeba5fe0ec55b1f5d Mon Sep 17 00:00:00 2001
From: Henrik TJ <[email-masked]>
Date: Fri, 13 Feb 2026 15:51:47 +0100
Subject: [PATCH] fe_utils: Use pg_malloc_object() and pg_malloc_array()

Use more high-level allocation routines in src/fe_utils.

Similar to 31d3847a37be and 6736dea14af
---
 src/fe_utils/conditional.c |  4 ++--
 src/fe_utils/print.c       | 48 +++++++++++++++++++-------------------
 src/fe_utils/psqlscan.l    |  8 +++----
 src/fe_utils/simple_list.c |  4 ++--
 4 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/src/fe_utils/conditional.c b/src/fe_utils/conditional.c
index deba61e0d81..537c76ed3cd 100644
--- a/src/fe_utils/conditional.c
+++ b/src/fe_utils/conditional.c
@@ -17,7 +17,7 @@
 ConditionalStack
 conditional_stack_create(void)
 {
-	ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
+	ConditionalStack cstack = pg_malloc_object(ConditionalStackData);
 
 	cstack->head = NULL;
 	return cstack;
@@ -52,7 +52,7 @@ conditional_stack_destroy(ConditionalStack cstack)
 void
 conditional_stack_push(ConditionalStack cstack, ifState new_state)
 {
-	IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
+	IfStackElem *p = pg_malloc_object(IfStackElem);
 
 	p->if_state = new_state;
 	p->query_len = -1;
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index ef52cdee9b7..12d969e8666 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -344,7 +344,7 @@ format_numeric_locale(const char *my_str)
 		return pg_strdup(my_str);
 
 	new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
-	new_str = pg_malloc(new_len + 1);
+	new_str = pg_malloc_array(char, (new_len + 1));
 	new_str_pos = 0;
 	int_len = integer_digits(my_str);
 
@@ -692,18 +692,18 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
 	if (cont->ncolumns > 0)
 	{
 		col_count = cont->ncolumns;
-		width_header = pg_malloc0(col_count * sizeof(*width_header));
-		width_average = pg_malloc0(col_count * sizeof(*width_average));
-		max_width = pg_malloc0(col_count * sizeof(*max_width));
-		width_wrap = pg_malloc0(col_count * sizeof(*width_wrap));
-		max_nl_lines = pg_malloc0(col_count * sizeof(*max_nl_lines));
-		curr_nl_line = pg_malloc0(col_count * sizeof(*curr_nl_line));
-		col_lineptrs = pg_malloc0(col_count * sizeof(*col_lineptrs));
-		max_bytes = pg_malloc0(col_count * sizeof(*max_bytes));
-		format_buf = pg_malloc0(col_count * sizeof(*format_buf));
-		header_done = pg_malloc0(col_count * sizeof(*header_done));
-		bytes_output = pg_malloc0(col_count * sizeof(*bytes_output));
-		wrap = pg_malloc0(col_count * sizeof(*wrap));
+		width_header = pg_malloc0_array(unsigned int, col_count);
+		width_average = pg_malloc0_array(unsigned int, col_count);
+		max_width = pg_malloc0_array(unsigned int, col_count);
+		width_wrap = pg_malloc0_array(unsigned int, col_count);
+		max_nl_lines = pg_malloc0_array(unsigned int, col_count);
+		curr_nl_line = pg_malloc0_array(unsigned int, col_count);
+		col_lineptrs = pg_malloc0_array(struct lineptr *, col_count);
+		max_bytes = pg_malloc0_array(unsigned int, col_count);
+		format_buf = pg_malloc0_array(unsigned char *, col_count);
+		header_done = pg_malloc0_array(bool, col_count);
+		bytes_output = pg_malloc0_array(int, col_count);
+		wrap = pg_malloc0_array(printTextLineWrap, col_count);
 	}
 	else
 	{
@@ -798,10 +798,10 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
 	for (i = 0; i < col_count; i++)
 	{
 		/* Add entry for ptr == NULL array termination */
-		col_lineptrs[i] = pg_malloc0((max_nl_lines[i] + 1) *
-									 sizeof(**col_lineptrs));
+		col_lineptrs[i] = pg_malloc0_array(struct lineptr,
+										   (max_nl_lines[i] + 1));
 
-		format_buf[i] = pg_malloc(max_bytes[i] + 1);
+		format_buf[i] = pg_malloc_array(unsigned char, (max_bytes[i] + 1));
 
 		col_lineptrs[i]->ptr = format_buf[i];
 	}
@@ -1409,8 +1409,8 @@ print_aligned_vertical(const printTableContent *cont,
 	 * We now have all the information we need to setup the formatting
 	 * structures
 	 */
-	dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
-	hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
+	dlineptr = pg_malloc_array(struct lineptr, (dheight + 1));
+	hlineptr = pg_malloc_array(struct lineptr, (hheight + 1));
 
 	dlineptr->ptr = pg_malloc(dformatsize);
 	hlineptr->ptr = pg_malloc(hformatsize);
@@ -3198,7 +3198,7 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
 	content->ncolumns = ncolumns;
 	content->nrows = nrows;
 
-	content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
+	content->headers = pg_malloc0_array(const char *, (ncolumns + 1));
 
 	total_cells = (uint64) ncolumns * nrows;
 	/* Catch possible overflow.  Using >= here allows adding 1 below */
@@ -3209,12 +3209,12 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
 				SIZE_MAX / sizeof(*content->cells));
 		exit(EXIT_FAILURE);
 	}
-	content->cells = pg_malloc0((total_cells + 1) * sizeof(*content->cells));
+	content->cells = pg_malloc0_array(const char *, (total_cells + 1));
 
 	content->cellmustfree = NULL;
 	content->footers = NULL;
 
-	content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
+	content->aligns = pg_malloc0_array(char, (ncolumns + 1));
 
 	content->header = content->headers;
 	content->cell = content->cells;
@@ -3305,7 +3305,7 @@ printTableAddCell(printTableContent *const content, char *cell,
 	{
 		if (content->cellmustfree == NULL)
 			content->cellmustfree =
-				pg_malloc0((total_cells + 1) * sizeof(bool));
+				pg_malloc0_array(bool, (total_cells + 1));
 
 		content->cellmustfree[content->cellsadded] = true;
 	}
@@ -3330,7 +3330,7 @@ printTableAddFooter(printTableContent *const content, const char *footer)
 {
 	printTableFooter *f;
 
-	f = pg_malloc0(sizeof(*f));
+	f = pg_malloc0_object(printTableFooter);
 	f->data = pg_strdup(footer);
 
 	if (content->footers == NULL)
@@ -3477,7 +3477,7 @@ count_table_lines(const printTableContent *cont,
 	 * Scan all column headers and determine their heights.  Cache the values
 	 * since vertical mode repeats the headers for every record.
 	 */
-	header_height = (int *) pg_malloc(cont->ncolumns * sizeof(int));
+	header_height = pg_malloc_array(int, cont->ncolumns);
 	for (i = 0; i < cont->ncolumns; i++)
 	{
 		pg_wcssize((const unsigned char *) cont->headers[i],
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 5d74714ffc6..e78952d448d 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -1002,7 +1002,7 @@ psql_scan_create(const PsqlScanCallbacks *callbacks)
 {
 	PsqlScanState state;
 
-	state = (PsqlScanStateData *) pg_malloc0(sizeof(PsqlScanStateData));
+	state = pg_malloc0_object(PsqlScanStateData);
 
 	state->callbacks = callbacks;
 
@@ -1376,7 +1376,7 @@ psqlscan_push_new_buffer(PsqlScanState state, const char *newstr,
 {
 	StackElem  *stackelem;
 
-	stackelem = (StackElem *) pg_malloc(sizeof(StackElem));
+	stackelem = pg_malloc_object(StackElem);
 
 	/*
 	 * In current usage, the passed varname points at the current flex input
@@ -1479,7 +1479,7 @@ psqlscan_prepare_buffer(PsqlScanState state, const char *txt, int len,
 	char	   *newtxt;
 
 	/* Flex wants two \0 characters after the actual data */
-	newtxt = pg_malloc(len + 2);
+	newtxt = pg_malloc_array(char, (len + 2));
 	*txtcopy = newtxt;
 	newtxt[len] = newtxt[len + 1] = YY_END_OF_BUFFER_CHAR;
 
@@ -1548,7 +1548,7 @@ psqlscan_emit(PsqlScanState state, const char *txt, int len)
 char *
 psqlscan_extract_substring(PsqlScanState state, const char *txt, int len)
 {
-	char	   *result = (char *) pg_malloc(len + 1);
+	char	   *result = pg_malloc_array(char, (len + 1));
 
 	if (state->safe_encoding)
 		memcpy(result, txt, len);
diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c
index ec698fc6728..03c11bae7c8 100644
--- a/src/fe_utils/simple_list.c
+++ b/src/fe_utils/simple_list.c
@@ -27,7 +27,7 @@ simple_oid_list_append(SimpleOidList *list, Oid val)
 {
 	SimpleOidListCell *cell;
 
-	cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+	cell = pg_malloc_object(SimpleOidListCell);
 	cell->next = NULL;
 	cell->val = val;
 
@@ -163,7 +163,7 @@ simple_ptr_list_append(SimplePtrList *list, void *ptr)
 {
 	SimplePtrListCell *cell;
 
-	cell = (SimplePtrListCell *) pg_malloc(sizeof(SimplePtrListCell));
+	cell = pg_malloc_object(SimplePtrListCell);
 	cell->next = NULL;
 	cell->ptr = ptr;
 
-- 
2.53.0

---

From: Andreas Karlsson <[email-masked]>
Date: Mon, 23 Feb 2026 03:17:52 +0100

> Inspired by [1], I took a stab at converting src/fe_utils to the new 
Thanks for the patch!

Looks like a nice change but why not just fix all instances of it in one 
swoop? It cannot be that many as there are 166 calls to pg_malloc() and 
62 calls to pg_malloc0() after your patch that need to be looked at.

-- 
Andreas Karlsson
Percona

---

From: Michael Paquier <[email-masked]>
Date: Tue, 24 Feb 2026 12:36:50 +0900

On Mon, Feb 23, 2026 at 03:17:52AM +0100, Andreas Karlsson wrote:
> swoop? It cannot be that many as there are 166 calls to pg_malloc() and 62
> calls to pg_malloc0() after your patch that need to be looked at.

FWIW, I don't really mind if these changes are proposed gradually, and
this looked fine enough on its own.  So applied.
--
Michael

---

From: Andreas Karlsson <[email-masked]>
Date: Fri, 27 Feb 2026 02:15:46 +0100

> this looked fine enough on its own.  So applied.

Fair, here is a patch which should handle all uses in the frontend code 
so we follow this pattern consistently to encourage new code to use 
these macros.

When doing this I found two things which I am ot sure what the cleanest 
way to handle would be so I broke them out into separate patches.

1. What should we do about when we allocate a an array of characters? 
Would it make sense to use pg_array_alloc() or would that jsut be silly? 
For example:

-pad = (char *) pg_malloc(l + 1);
+pad = pg_malloc_array(char, l + 1);

2. I found a small and harmless thinko. The buffer in verify_tar_file() 
is actually a char * but for some reason the code did the following:

buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));

What should we do about it? Just skip the "sizof(uint8)"?

Andreas
From 0c62229ff9a8f1a5175393b9c1d51bb379ac31ea Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email-masked]>
Date: Fri, 27 Feb 2026 02:03:46 +0100
Subject: [PATCH v1 1/3] Use pg_malloc_object() and pg_alloc_array() variants
 in frontend code

Where possible use the pg_*_object() and pg_*_array() macros in our frontend
code to encourage newly added code to use the macros.
---
 contrib/oid2name/oid2name.c                   | 16 +++---
 src/bin/initdb/initdb.c                       |  6 +--
 src/bin/pg_amcheck/pg_amcheck.c               |  8 +--
 src/bin/pg_basebackup/pg_basebackup.c         |  4 +-
 src/bin/pg_basebackup/pg_recvlogical.c        |  2 +-
 src/bin/pg_basebackup/streamutil.c            |  8 +--
 src/bin/pg_basebackup/walmethods.c            | 12 ++---
 src/bin/pg_combinebackup/load_manifest.c      |  4 +-
 src/bin/pg_combinebackup/pg_combinebackup.c   |  6 +--
 src/bin/pg_combinebackup/reconstruct.c        | 10 ++--
 src/bin/pg_combinebackup/write_manifest.c     |  2 +-
 src/bin/pg_ctl/pg_ctl.c                       |  4 +-
 src/bin/pg_rewind/datapagemap.c               |  2 +-
 src/bin/pg_rewind/libpq_source.c              |  2 +-
 src/bin/pg_rewind/local_source.c              |  2 +-
 src/bin/pg_rewind/pg_rewind.c                 |  2 +-
 src/bin/pg_rewind/timeline.c                  |  6 +--
 src/bin/pg_upgrade/check.c                    |  4 +-
 src/bin/pg_upgrade/function.c                 |  4 +-
 src/bin/pg_upgrade/info.c                     | 11 ++--
 src/bin/pg_upgrade/parallel.c                 | 12 ++---
 src/bin/pg_upgrade/slru_io.c                  |  2 +-
 src/bin/pg_upgrade/tablespace.c               |  4 +-
 src/bin/pg_upgrade/task.c                     |  8 +--
 src/bin/pg_verifybackup/astreamer_verify.c    |  2 +-
 src/bin/pg_verifybackup/pg_verifybackup.c     |  6 +--
 src/bin/pgbench/exprparse.y                   | 16 +++---
 src/bin/pgbench/pgbench.c                     | 22 ++++----
 src/bin/psql/command.c                        |  6 +--
 src/bin/psql/copy.c                           |  2 +-
 src/bin/psql/crosstabview.c                   | 15 +++---
 src/bin/psql/describe.c                       |  4 +-
 src/bin/psql/tab-complete.in.c                |  7 ++-
 src/bin/psql/variables.c                      |  6 +--
 src/bin/scripts/reindexdb.c                   |  6 +--
 src/test/isolation/isolationtester.c          | 12 ++---
 src/test/isolation/specparse.y                | 50 +++++++++----------
 .../modules/libpq_pipeline/libpq_pipeline.c   |  8 +--
 src/test/regress/pg_regress.c                 |  6 +--
 39 files changed, 152 insertions(+), 157 deletions(-)

diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index 63e6ce2dae8..1e9efcd3953 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -237,13 +237,13 @@ add_one_elt(char *eltname, eary *eary)
 	if (eary->alloc == 0)
 	{
 		eary	  ->alloc = 8;
-		eary	  ->array = (char **) pg_malloc(8 * sizeof(char *));
+		eary	  ->array = pg_malloc_array(char *, 8);
 	}
 	else if (eary->num >= eary->alloc)
 	{
 		eary	  ->alloc *= 2;
-		eary	  ->array = (char **) pg_realloc(eary->array,
-												 eary->alloc * sizeof(char *));
+		eary	  ->array = pg_realloc_array(eary->array, char *,
+											 eary->alloc);
 	}
 
 	eary	  ->array[eary->num] = pg_strdup(eltname);
@@ -400,7 +400,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
 	nfields = PQnfields(res);
 
 	/* for each field, get the needed width */
-	length = (int *) pg_malloc(sizeof(int) * nfields);
+	length = pg_malloc_array(int, nfields);
 	for (j = 0; j < nfields; j++)
 		length[j] = strlen(PQfname(res, j));
 
@@ -585,11 +585,11 @@ main(int argc, char **argv)
 	struct options *my_opts;
 	PGconn	   *pgconn;
 
-	my_opts = (struct options *) pg_malloc(sizeof(struct options));
+	my_opts = pg_malloc_object(struct options);
 
-	my_opts->oids = (eary *) pg_malloc(sizeof(eary));
-	my_opts->tables = (eary *) pg_malloc(sizeof(eary));
-	my_opts->filenumbers = (eary *) pg_malloc(sizeof(eary));
+	my_opts->oids = pg_malloc_object(eary);
+	my_opts->tables = pg_malloc_object(eary);
+	my_opts->filenumbers = pg_malloc_object(eary);
 
 	my_opts->oids->num = my_opts->oids->alloc = 0;
 	my_opts->tables->num = my_opts->tables->alloc = 0;
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 7c49dd433a7..53ec1544ff3 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -444,7 +444,7 @@ escape_quotes_bki(const char *src)
 static void
 add_stringlist_item(_stringlist **listhead, const char *str)
 {
-	_stringlist *newentry = pg_malloc(sizeof(_stringlist));
+	_stringlist *newentry = pg_malloc_object(_stringlist);
 	_stringlist *oldentry;
 
 	newentry->str = pg_strdup(str);
@@ -687,7 +687,7 @@ readfile(const char *path)
 	initStringInfo(&line);
 
 	maxlines = 1024;
-	result = (char **) pg_malloc(maxlines * sizeof(char *));
+	result = pg_malloc_array(char *, maxlines);
 
 	n = 0;
 	while (pg_get_line_buf(infile, &line))
@@ -696,7 +696,7 @@ readfile(const char *path)
 		if (n >= maxlines - 1)
 		{
 			maxlines *= 2;
-			result = (char **) pg_realloc(result, maxlines * sizeof(char *));
+			result = pg_realloc_array(result, char *, maxlines);
 		}
 
 		result[n++] = pg_strdup(line.data);
diff --git a/src/bin/pg_amcheck/pg_amcheck.c b/src/bin/pg_amcheck/pg_amcheck.c
index 03e24a2577c..09ba0596400 100644
--- a/src/bin/pg_amcheck/pg_amcheck.c
+++ b/src/bin/pg_amcheck/pg_amcheck.c
@@ -1338,7 +1338,7 @@ extend_pattern_info_array(PatternInfoArray *pia)
 	PatternInfo *result;
 
 	pia->len++;
-	pia->data = (PatternInfo *) pg_realloc(pia->data, pia->len * sizeof(PatternInfo));
+	pia->data = pg_realloc_array(pia->data, PatternInfo, pia->len);
 	result = &pia->data[pia->len - 1];
 	memset(result, 0, sizeof(*result));
 
@@ -1593,7 +1593,7 @@ compile_database_list(PGconn *conn, SimplePtrList *databases,
 
 	if (initial_dbname)
 	{
-		DatabaseInfo *dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo));
+		DatabaseInfo *dat = pg_malloc0_object(DatabaseInfo);
 
 		/* This database is included.  Add to list */
 		if (opts.verbose)
@@ -1738,7 +1738,7 @@ compile_database_list(PGconn *conn, SimplePtrList *databases,
 			if (opts.verbose)
 				pg_log_info("including database \"%s\"", datname);
 
-			dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo));
+			dat = pg_malloc0_object(DatabaseInfo);
 			dat->datname = pstrdup(datname);
 			simple_ptr_list_append(databases, dat);
 		}
@@ -2202,7 +2202,7 @@ compile_relation_list_one_db(PGconn *conn, SimplePtrList *relations,
 		{
 			/* Current record pertains to a relation */
 
-			RelationInfo *rel = (RelationInfo *) pg_malloc0(sizeof(RelationInfo));
+			RelationInfo *rel = pg_malloc0_object(RelationInfo);
 
 			Assert(OidIsValid(oid));
 			Assert((is_heap && !is_btree) || (is_btree && !is_heap));
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 1e3a8203f77..fa169a8d642 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -320,7 +320,7 @@ kill_bgchild_atexit(void)
 static void
 tablespace_list_append(const char *arg)
 {
-	TablespaceListCell *cell = (TablespaceListCell *) pg_malloc0(sizeof(TablespaceListCell));
+	TablespaceListCell *cell = pg_malloc0_object(TablespaceListCell);
 	char	   *dst;
 	char	   *dst_ptr;
 	const char *arg_ptr;
@@ -623,7 +623,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier,
 				lo;
 	char		statusdir[MAXPGPATH];
 
-	param = pg_malloc0(sizeof(logstreamer_param));
+	param = pg_malloc0_object(logstreamer_param);
 	param->timeline = timeline;
 	param->sysidentifier = sysidentifier;
 	param->wal_compress_algorithm = wal_compress_algorithm;
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index abc6cd85a6d..be71783b370 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -820,7 +820,7 @@ main(int argc, char **argv)
 					}
 
 					noptions += 1;
-					options = pg_realloc(options, sizeof(char *) * noptions * 2);
+					options = pg_realloc_array(options, char *, noptions * 2);
 
 					options[(noptions - 1) * 2] = data;
 					options[(noptions - 1) * 2 + 1] = val;
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 1d404e778a0..76abdfa2ae6 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -94,8 +94,8 @@ GetConnection(void)
 				argcount++;
 		}
 
-		keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
-		values = pg_malloc0((argcount + 1) * sizeof(*values));
+		keywords = pg_malloc0_array(const char *, argcount + 1);
+		values = pg_malloc0_array(const char *, argcount + 1);
 
 		/*
 		 * Set dbname here already, so it can be overridden by a dbname in the
@@ -117,8 +117,8 @@ GetConnection(void)
 	}
 	else
 	{
-		keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
-		values = pg_malloc0((argcount + 1) * sizeof(*values));
+		keywords = pg_malloc0_array(const char *, argcount + 1);
+		values = pg_malloc0_array(const char *, argcount + 1);
 		keywords[i] = "dbname";
 		values[i] = (dbname == NULL) ? "replication" : dbname;
 		i++;
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 17d22c79f68..476673cf729 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -275,7 +275,7 @@ dir_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
 		}
 	}
 
-	f = pg_malloc0(sizeof(DirectoryMethodFile));
+	f = pg_malloc0_object(DirectoryMethodFile);
 #ifdef HAVE_LIBZ
 	if (wwmethod->compression_algorithm == PG_COMPRESSION_GZIP)
 		f->gzfp = gzfp;
@@ -643,7 +643,7 @@ CreateWalDirectoryMethod(const char *basedir,
 {
 	DirectoryMethodData *wwmethod;
 
-	wwmethod = pg_malloc0(sizeof(DirectoryMethodData));
+	wwmethod = pg_malloc0_object(DirectoryMethodData);
 	*((const WalWriteMethodOps **) &wwmethod->base.ops) =
 		&WalDirectoryMethodOps;
 	wwmethod->base.compression_algorithm = compression_algorithm;
@@ -825,7 +825,7 @@ static char *
 tar_get_file_name(WalWriteMethod *wwmethod, const char *pathname,
 				  const char *temp_suffix)
 {
-	char	   *filename = pg_malloc0(MAXPGPATH * sizeof(char));
+	char	   *filename = pg_malloc0_array(char, MAXPGPATH);
 
 	snprintf(filename, MAXPGPATH, "%s%s",
 			 pathname, temp_suffix ? temp_suffix : "");
@@ -859,7 +859,7 @@ tar_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
 #ifdef HAVE_LIBZ
 		if (wwmethod->compression_algorithm == PG_COMPRESSION_GZIP)
 		{
-			tar_data->zp = (z_streamp) pg_malloc(sizeof(z_stream));
+			tar_data->zp = pg_malloc_object(z_stream);
 			tar_data->zp->zalloc = Z_NULL;
 			tar_data->zp->zfree = Z_NULL;
 			tar_data->zp->opaque = Z_NULL;
@@ -893,7 +893,7 @@ tar_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
 		return NULL;
 	}
 
-	tar_data->currentfile = pg_malloc0(sizeof(TarMethodFile));
+	tar_data->currentfile = pg_malloc0_object(TarMethodFile);
 	tar_data->currentfile->base.wwmethod = wwmethod;
 
 	tmppath = tar_get_file_name(wwmethod, pathname, temp_suffix);
@@ -1360,7 +1360,7 @@ CreateWalTarMethod(const char *tarbase,
 	const char *suffix = (compression_algorithm == PG_COMPRESSION_GZIP) ?
 		".tar.gz" : ".tar";
 
-	wwmethod = pg_malloc0(sizeof(TarMethodData));
+	wwmethod = pg_malloc0_object(TarMethodData);
 	*((const WalWriteMethodOps **) &wwmethod->base.ops) =
 		&WalTarMethodOps;
 	wwmethod->base.compression_algorithm = compression_algorithm;
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c
index c363ac6187e..2e50b7af4d2 100644
--- a/src/bin/pg_combinebackup/load_manifest.c
+++ b/src/bin/pg_combinebackup/load_manifest.c
@@ -85,7 +85,7 @@ load_backup_manifests(int n_backups, char **backup_directories)
 	manifest_data **result;
 	int			i;
 
-	result = pg_malloc(sizeof(manifest_data *) * n_backups);
+	result = pg_malloc_array(manifest_data *, n_backups);
 	for (i = 0; i < n_backups; ++i)
 		result[i] = load_backup_manifest(backup_directories[i]);
 
@@ -139,7 +139,7 @@ load_backup_manifest(char *backup_directory)
 	/* Create the hash table. */
 	ht = manifest_files_create(initial_size, NULL);
 
-	result = pg_malloc0(sizeof(manifest_data));
+	result = pg_malloc0_object(manifest_data);
 	result->files = ht;
 	context.private_data = result;
 	context.version_cb = combinebackup_version_cb;
diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c
index b9f26ce782e..ac7eb0940d5 100644
--- a/src/bin/pg_combinebackup/pg_combinebackup.c
+++ b/src/bin/pg_combinebackup/pg_combinebackup.c
@@ -455,7 +455,7 @@ main(int argc, char *argv[])
 static void
 add_tablespace_mapping(cb_options *opt, char *arg)
 {
-	cb_tablespace_mapping *tsmap = pg_malloc0(sizeof(cb_tablespace_mapping));
+	cb_tablespace_mapping *tsmap = pg_malloc0_object(cb_tablespace_mapping);
 	char	   *dst;
 	char	   *dst_ptr;
 	char	   *arg_ptr;
@@ -1171,7 +1171,7 @@ process_directory_recursively(Oid tsoid,
 static void
 remember_to_cleanup_directory(char *target_path, bool rmtopdir)
 {
-	cb_cleanup_dir *dir = pg_malloc(sizeof(cb_cleanup_dir));
+	cb_cleanup_dir *dir = pg_malloc_object(cb_cleanup_dir);
 
 	dir->target_path = target_path;
 	dir->rmtopdir = rmtopdir;
@@ -1259,7 +1259,7 @@ scan_for_existing_tablespaces(char *pathname, cb_options *opt)
 		}
 
 		/* Create a new tablespace object. */
-		ts = pg_malloc0(sizeof(cb_tablespace));
+		ts = pg_malloc0_object(cb_tablespace);
 		ts->oid = oid;
 
 		/*
diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c
index da60f7d0297..3349aa2441d 100644
--- a/src/bin/pg_combinebackup/reconstruct.c
+++ b/src/bin/pg_combinebackup/reconstruct.c
@@ -120,7 +120,7 @@ reconstruct_from_incremental_file(char *input_filename,
 	 * Every block must come either from the latest version of the file or
 	 * from one of the prior backups.
 	 */
-	source = pg_malloc0(sizeof(rfile *) * (1 + n_prior_backups));
+	source = pg_malloc0_array(rfile *, 1 + n_prior_backups);
 
 	/*
 	 * Use the information from the latest incremental file to figure out how
@@ -135,8 +135,8 @@ reconstruct_from_incremental_file(char *input_filename,
 	 * need to obtain it and at what offset in that file it's stored.
 	 * sourcemap gives us the first of these things, and offsetmap the latter.
 	 */
-	sourcemap = pg_malloc0(sizeof(rfile *) * block_length);
-	offsetmap = pg_malloc0(sizeof(off_t) * block_length);
+	sourcemap = pg_malloc0_array(rfile *, block_length);
+	offsetmap = pg_malloc0_array(off_t, block_length);
 
 	/*
 	 * Every block that is present in the newest incremental file should be
@@ -483,7 +483,7 @@ make_incremental_rfile(char *filename)
 	if (rf->num_blocks > 0)
 	{
 		rf->relative_block_numbers =
-			pg_malloc0(sizeof(BlockNumber) * rf->num_blocks);
+			pg_malloc0_array(BlockNumber, rf->num_blocks);
 		read_bytes(rf, rf->relative_block_numbers,
 				   sizeof(BlockNumber) * rf->num_blocks);
 	}
@@ -512,7 +512,7 @@ make_rfile(char *filename, bool missing_ok)
 {
 	rfile	   *rf;
 
-	rf = pg_malloc0(sizeof(rfile));
+	rf = pg_malloc0_object(rfile);
 	rf->filename = pstrdup(filename);
 	if ((rf->fd = open(filename, O_RDONLY | PG_BINARY, 0)) < 0)
 	{
diff --git a/src/bin/pg_combinebackup/write_manifest.c b/src/bin/pg_combinebackup/write_manifest.c
index 4f3ed2c173c..715286043b5 100644
--- a/src/bin/pg_combinebackup/write_manifest.c
+++ b/src/bin/pg_combinebackup/write_manifest.c
@@ -47,7 +47,7 @@ static size_t hex_encode(const uint8 *src, size_t len, char *dst);
 manifest_writer *
 create_manifest_writer(char *directory, uint64 system_identifier)
 {
-	manifest_writer *mwriter = pg_malloc(sizeof(manifest_writer));
+	manifest_writer *mwriter = pg_malloc_object(manifest_writer);
 
 	snprintf(mwriter->pathname, MAXPGPATH, "%s/backup_manifest", directory);
 	mwriter->fd = -1;
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 122856b599e..3cc61455dcb 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -346,7 +346,7 @@ readfile(const char *path, int *numlines)
 	{
 		/* empty file */
 		close(fd);
-		result = (char **) pg_malloc(sizeof(char *));
+		result = pg_malloc_object(char *);
 		*result = NULL;
 		return result;
 	}
@@ -374,7 +374,7 @@ readfile(const char *path, int *numlines)
 	}
 
 	/* set up the result buffer */
-	result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
+	result = pg_malloc_array(char *, nlines + 1);
 	*numlines = nlines;
 
 	/* now split the buffer into lines */
diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c
index 94bac43fb92..8e8cdda5005 100644
--- a/src/bin/pg_rewind/datapagemap.c
+++ b/src/bin/pg_rewind/datapagemap.c
@@ -76,7 +76,7 @@ datapagemap_iterate(datapagemap_t *map)
 {
 	datapagemap_iterator_t *iter;
 
-	iter = pg_malloc(sizeof(datapagemap_iterator_t));
+	iter = pg_malloc0_object(datapagemap_iterator_t);
 	iter->map = map;
 	iter->nextblkno = 0;
 
diff --git a/src/bin/pg_rewind/libpq_source.c b/src/bin/pg_rewind/libpq_source.c
index 15a05d9a8d0..6955bc575ea 100644
--- a/src/bin/pg_rewind/libpq_source.c
+++ b/src/bin/pg_rewind/libpq_source.c
@@ -84,7 +84,7 @@ init_libpq_source(PGconn *conn)
 
 	init_libpq_conn(conn);
 
-	src = pg_malloc0(sizeof(libpq_source));
+	src = pg_malloc0_object(libpq_source);
 
 	src->common.traverse_files = libpq_traverse_files;
 	src->common.fetch_file = libpq_fetch_file;
diff --git a/src/bin/pg_rewind/local_source.c b/src/bin/pg_rewind/local_source.c
index 97d6f65009b..4841cf01fb7 100644
--- a/src/bin/pg_rewind/local_source.c
+++ b/src/bin/pg_rewind/local_source.c
@@ -39,7 +39,7 @@ init_local_source(const char *datadir)
 {
 	local_source *src;
 
-	src = pg_malloc0(sizeof(local_source));
+	src = pg_malloc0_object(local_source);
 
 	src->common.traverse_files = local_traverse_files;
 	src->common.fetch_file = local_fetch_file;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index d0aafd7e7a6..9d745d4b25b 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -874,7 +874,7 @@ getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
 	 */
 	if (tli == 1)
 	{
-		history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
+		history = pg_malloc_object(TimeLineHistoryEntry);
 		history->tli = tli;
 		history->begin = history->end = InvalidXLogRecPtr;
 		*nentries = 1;
diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c
index 69f589f67c9..dda06eaa0bc 100644
--- a/src/bin/pg_rewind/timeline.c
+++ b/src/bin/pg_rewind/timeline.c
@@ -91,7 +91,7 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
 		lasttli = tli;
 
 		nlines++;
-		entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+		entries = pg_realloc_array(entries, TimeLineHistoryEntry, nlines);
 
 		entry = &entries[nlines - 1];
 		entry->tli = tli;
@@ -115,9 +115,9 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
 	 */
 	nlines++;
 	if (entries)
-		entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+		entries = pg_realloc_array(entries, TimeLineHistoryEntry, nlines);
 	else
-		entries = pg_malloc(1 * sizeof(TimeLineHistoryEntry));
+		entries = pg_malloc_array(TimeLineHistoryEntry, 1);
 
 	entry = &entries[nlines - 1];
 	entry->tli = targetTLI;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 5afa65db98e..eb35c68d450 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -482,8 +482,8 @@ check_for_data_types_usage(ClusterInfo *cluster)
 	}
 
 	/* Allocate memory for queries and for task states */
-	queries = pg_malloc0(sizeof(char *) * n_data_types_usage_checks);
-	states = pg_malloc0(sizeof(struct data_type_check_state) * n_data_types_usage_checks);
+	queries = pg_malloc0_array(char *, n_data_types_usage_checks);
+	states = pg_malloc0_array(struct data_type_check_state, n_data_types_usage_checks);
 
 	for (int i = 0; i < n_data_types_usage_checks; i++)
 	{
diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c
index 850c9238c11..a3184f95665 100644
--- a/src/bin/pg_upgrade/function.c
+++ b/src/bin/pg_upgrade/function.c
@@ -83,7 +83,7 @@ get_loadable_libraries(void)
 	struct loadable_libraries_state state;
 	char	   *query;
 
-	state.ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
+	state.ress = pg_malloc_array(PGresult *, old_cluster.dbarr.ndbs);
 	state.totaltups = 0;
 
 	query = psprintf("SELECT DISTINCT probin "
@@ -105,7 +105,7 @@ get_loadable_libraries(void)
 	 * plugins.
 	 */
 	n_libinfos = state.totaltups + count_old_cluster_logical_slots();
-	os_info.libraries = (LibraryInfo *) pg_malloc(sizeof(LibraryInfo) * n_libinfos);
+	os_info.libraries = pg_malloc_array(LibraryInfo, n_libinfos);
 	totaltups = 0;
 
 	for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index ad4b1530e6d..8c5679b8097 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -53,8 +53,7 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
 	bool		all_matched = true;
 
 	/* There will certainly not be more mappings than there are old rels */
-	maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
-									 old_db->rel_arr.nrels);
+	maps = pg_malloc_array(FileNameMap, old_db->rel_arr.nrels);
 
 	/*
 	 * Each of the RelInfo arrays should be sorted by OID.  Scan through them
@@ -364,7 +363,7 @@ get_template0_info(ClusterInfo *cluster)
 	if (PQntuples(dbres) != 1)
 		pg_fatal("template0 not found");
 
-	locale = pg_malloc(sizeof(DbLocaleInfo));
+	locale = pg_malloc_object(DbLocaleInfo);
 
 	i_datencoding = PQfnumber(dbres, "encoding");
 	i_datlocprovider = PQfnumber(dbres, "datlocprovider");
@@ -433,7 +432,7 @@ get_db_infos(ClusterInfo *cluster)
 	i_spclocation = PQfnumber(res, "spclocation");
 
 	ntups = PQntuples(res);
-	dbinfos = (DbInfo *) pg_malloc0(sizeof(DbInfo) * ntups);
+	dbinfos = pg_malloc0_array(DbInfo, ntups);
 
 	for (tupnum = 0; tupnum < ntups; tupnum++)
 	{
@@ -579,7 +578,7 @@ static void
 process_rel_infos(DbInfo *dbinfo, PGresult *res, void *arg)
 {
 	int			ntups = PQntuples(res);
-	RelInfo    *relinfos = (RelInfo *) pg_malloc(sizeof(RelInfo) * ntups);
+	RelInfo    *relinfos = pg_malloc_array(RelInfo, ntups);
 	int			i_reloid = PQfnumber(res, "reloid");
 	int			i_indtable = PQfnumber(res, "indtable");
 	int			i_toastheap = PQfnumber(res, "toastheap");
@@ -785,7 +784,7 @@ process_old_cluster_logical_slot_infos(DbInfo *dbinfo, PGresult *res, void *arg)
 		int			i_caught_up;
 		int			i_invalid;
 
-		slotinfos = (LogicalSlotInfo *) pg_malloc(sizeof(LogicalSlotInfo) * num_slots);
+		slotinfos = pg_malloc_array(LogicalSlotInfo, num_slots);
 
 		i_slotname = PQfnumber(res, "slot_name");
 		i_plugin = PQfnumber(res, "plugin");
diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c
index 6945f71fcf1..f0406de84ee 100644
--- a/src/bin/pg_upgrade/parallel.c
+++ b/src/bin/pg_upgrade/parallel.c
@@ -85,13 +85,13 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
 		/* parallel */
 #ifdef WIN32
 		if (thread_handles == NULL)
-			thread_handles = pg_malloc(user_opts.jobs * sizeof(HANDLE));
+			thread_handles = pg_malloc_array(HANDLE, user_opts.jobs);
 
 		if (exec_thread_args == NULL)
 		{
 			int			i;
 
-			exec_thread_args = pg_malloc(user_opts.jobs * sizeof(exec_thread_arg *));
+			exec_thread_args = pg_malloc_array(exec_thread_arg *, user_opts.jobs);
 
 			/*
 			 * For safety and performance, we keep the args allocated during
@@ -99,7 +99,7 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
 			 * thread different from the one that allocated it.
 			 */
 			for (i = 0; i < user_opts.jobs; i++)
-				exec_thread_args[i] = pg_malloc0(sizeof(exec_thread_arg));
+				exec_thread_args[i] = pg_malloc0_object(exec_thread_arg);
 		}
 
 		cur_thread_args = (void **) exec_thread_args;
@@ -188,13 +188,13 @@ parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
 		/* parallel */
 #ifdef WIN32
 		if (thread_handles == NULL)
-			thread_handles = pg_malloc(user_opts.jobs * sizeof(HANDLE));
+			thread_handles = pg_malloc_array(HANDLE, user_opts.jobs);
 
 		if (transfer_thread_args == NULL)
 		{
 			int			i;
 
-			transfer_thread_args = pg_malloc(user_opts.jobs * sizeof(transfer_thread_arg *));
+			transfer_thread_args = pg_malloc_array(transfer_thread_arg *, user_opts.jobs);
 
 			/*
 			 * For safety and performance, we keep the args allocated during
@@ -202,7 +202,7 @@ parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
 			 * thread different from the one that allocated it.
 			 */
 			for (i = 0; i < user_opts.jobs; i++)
-				transfer_thread_args[i] = pg_malloc0(sizeof(transfer_thread_arg));
+				transfer_thread_args[i] = pg_malloc0_object(transfer_thread_arg);
 		}
 
 		cur_thread_args = (void **) transfer_thread_args;
diff --git a/src/bin/pg_upgrade/slru_io.c b/src/bin/pg_upgrade/slru_io.c
index ae3e224d7b1..2188a287850 100644
--- a/src/bin/pg_upgrade/slru_io.c
+++ b/src/bin/pg_upgrade/slru_io.c
@@ -26,7 +26,7 @@ static void SlruFlush(SlruSegState *state);
 static SlruSegState *
 AllocSlruSegState(const char *dir)
 {
-	SlruSegState *state = pg_malloc(sizeof(*state));
+	SlruSegState *state = pg_malloc_object(SlruSegState);
 
 	state->dir = pstrdup(dir);
 	state->fn = NULL;
diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c
index 0ec5644a639..95ea7819457 100644
--- a/src/bin/pg_upgrade/tablespace.c
+++ b/src/bin/pg_upgrade/tablespace.c
@@ -69,9 +69,9 @@ get_tablespace_paths(void)
 	if (PQntuples(res) != 0)
 	{
 		old_cluster.tablespaces =
-			(char **) pg_malloc(old_cluster.num_tablespaces * sizeof(char *));
+			pg_malloc_array(char *, old_cluster.num_tablespaces);
 		new_cluster.tablespaces =
-			(char **) pg_malloc(new_cluster.num_tablespaces * sizeof(char *));
+			pg_malloc_array(char *, new_cluster.num_tablespaces);
 	}
 	else
 	{
diff --git a/src/bin/pg_upgrade/task.c b/src/bin/pg_upgrade/task.c
index 3d958527528..b6eb29e1f3a 100644
--- a/src/bin/pg_upgrade/task.c
+++ b/src/bin/pg_upgrade/task.c
@@ -116,7 +116,7 @@ typedef struct UpgradeTaskSlot
 UpgradeTask *
 upgrade_task_create(void)
 {
-	UpgradeTask *task = pg_malloc0(sizeof(UpgradeTask));
+	UpgradeTask *task = pg_malloc0_object(UpgradeTask);
 
 	task->queries = createPQExpBuffer();
 
@@ -154,8 +154,8 @@ upgrade_task_add_step(UpgradeTask *task, const char *query,
 {
 	UpgradeTaskStep *new_step;
 
-	task->steps = pg_realloc(task->steps,
-							 ++task->num_steps * sizeof(UpgradeTaskStep));
+	task->steps = pg_realloc_array(task->steps, UpgradeTaskStep,
+								   ++task->num_steps);
 
 	new_step = &task->steps[task->num_steps - 1];
 	new_step->process_cb = process_cb;
@@ -421,7 +421,7 @@ void
 upgrade_task_run(const UpgradeTask *task, const ClusterInfo *cluster)
 {
 	int			jobs = Max(1, user_opts.jobs);
-	UpgradeTaskSlot *slots = pg_malloc0(sizeof(UpgradeTaskSlot) * jobs);
+	UpgradeTaskSlot *slots = pg_malloc0_array(UpgradeTaskSlot, jobs);
 
 	dbs_complete = 0;
 	dbs_processing = 0;
diff --git a/src/bin/pg_verifybackup/astreamer_verify.c b/src/bin/pg_verifybackup/astreamer_verify.c
index 0edc8123b43..26c98186530 100644
--- a/src/bin/pg_verifybackup/astreamer_verify.c
+++ b/src/bin/pg_verifybackup/astreamer_verify.c
@@ -79,7 +79,7 @@ astreamer_verify_content_new(astreamer *next, verifier_context *context,
 	streamer->tblspc_oid = tblspc_oid;
 
 	if (!context->skip_checksums)
-		streamer->checksum_ctx = pg_malloc(sizeof(pg_checksum_context));
+		streamer->checksum_ctx = pg_malloc_object(pg_checksum_context);
 
 	return &streamer->base;
 }
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index f9f2d457f2f..cbc9447384f 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -418,7 +418,7 @@ parse_manifest_file(char *manifest_path)
 	/* Create the hash table. */
 	ht = manifest_files_create(initial_size, NULL);
 
-	result = pg_malloc0(sizeof(manifest_data));
+	result = pg_malloc0_object(manifest_data);
 	result->files = ht;
 	context.private_data = result;
 	context.version_cb = verifybackup_version_cb;
@@ -970,7 +970,7 @@ precheck_tar_backup_file(verifier_context *context, char *relpath,
 	 * Append the information to the list for complete verification at a later
 	 * stage.
 	 */
-	tar = pg_malloc(sizeof(tar_file));
+	tar = pg_malloc_object(tar_file);
 	tar->relpath = pstrdup(relpath);
 	tar->tblspc_oid = tblspc_oid;
 	tar->compress_algorithm = compress_algorithm;
@@ -1065,7 +1065,7 @@ verify_backup_checksums(verifier_context *context)
 
 	progress_report(false);
 
-	buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));
+	buffer = pg_malloc_array(uint8, READ_CHUNK_SIZE);
 
 	manifest_files_start_iterate(manifest->files, &it);
 	while ((m = manifest_files_iterate(manifest->files, &it)) != NULL)
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index 8dd6c8811f2..6dd809950fd 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -167,7 +167,7 @@ function: FUNCTION			{ $$ = find_func(yyscanner, $1); pg_free($1); }
 static PgBenchExpr *
 make_null_constant(void)
 {
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	expr->etype = ENODE_CONSTANT;
 	expr->u.constant.type = PGBT_NULL;
@@ -178,7 +178,7 @@ make_null_constant(void)
 static PgBenchExpr *
 make_integer_constant(int64 ival)
 {
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	expr->etype = ENODE_CONSTANT;
 	expr->u.constant.type = PGBT_INT;
@@ -189,7 +189,7 @@ make_integer_constant(int64 ival)
 static PgBenchExpr *
 make_double_constant(double dval)
 {
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	expr->etype = ENODE_CONSTANT;
 	expr->u.constant.type = PGBT_DOUBLE;
@@ -200,7 +200,7 @@ make_double_constant(double dval)
 static PgBenchExpr *
 make_boolean_constant(bool bval)
 {
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	expr->etype = ENODE_CONSTANT;
 	expr->u.constant.type = PGBT_BOOLEAN;
@@ -211,7 +211,7 @@ make_boolean_constant(bool bval)
 static PgBenchExpr *
 make_variable(char *varname)
 {
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	expr->etype = ENODE_VARIABLE;
 	expr->u.variable.varname = varname;
@@ -415,12 +415,12 @@ make_elist(PgBenchExpr *expr, PgBenchExprList *list)
 
 	if (list == NULL)
 	{
-		list = pg_malloc(sizeof(PgBenchExprList));
+		list = pg_malloc_object(PgBenchExprList);
 		list->head = NULL;
 		list->tail = NULL;
 	}
 
-	cons = pg_malloc(sizeof(PgBenchExprLink));
+	cons = pg_malloc_object(PgBenchExprLink);
 	cons->expr = expr;
 	cons->next = NULL;
 
@@ -453,7 +453,7 @@ make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
 {
 	int			len = elist_length(args);
 
-	PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+	PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
 
 	Assert(fnumber >= 0);
 
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index cb4e986092e..1dae918cc09 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -1774,7 +1774,7 @@ enlargeVariables(Variables *variables, int needed)
 	{
 		variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
 		variables->vars = (Variable *)
-			pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
+			pg_realloc_array(variables->vars, Variable, variables->max_vars);
 	}
 }
 
@@ -3067,7 +3067,7 @@ allocCStatePrepared(CState *st)
 {
 	Assert(st->prepared == NULL);
 
-	st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
+	st->prepared = pg_malloc_array(bool *, num_scripts);
 	for (int i = 0; i < num_scripts; i++)
 	{
 		ParsedScript *script = &sql_script[i];
@@ -3075,7 +3075,7 @@ allocCStatePrepared(CState *st)
 
 		for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
 			;
-		st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
+		st->prepared[i] = pg_malloc0_array(bool, numcmds);
 	}
 }
 
@@ -5659,7 +5659,7 @@ create_sql_command(PQExpBuffer buf)
 		return NULL;
 
 	/* Allocate and initialize Command structure */
-	my_command = (Command *) pg_malloc(sizeof(Command));
+	my_command = pg_malloc0_object(Command);
 	initPQExpBuffer(&my_command->lines);
 	appendPQExpBufferStr(&my_command->lines, p);
 	my_command->first_line = NULL;	/* this is set later */
@@ -5755,7 +5755,7 @@ process_backslash_command(PsqlScanState sstate, const char *source,
 	}
 
 	/* Allocate and initialize Command structure */
-	my_command = (Command *) pg_malloc0(sizeof(Command));
+	my_command = pg_malloc0_object(Command);
 	my_command->type = META_COMMAND;
 	my_command->argc = 0;
 	initSimpleStats(&my_command->stats);
@@ -6011,7 +6011,7 @@ ParseScript(const char *script, const char *desc, int weight)
 	/* Initialize all fields of ps */
 	ps.desc = desc;
 	ps.weight = weight;
-	ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
+	ps.commands = pg_malloc_array(Command *, alloc_num);
 	initStats(&ps.stats, 0);
 
 	/* Prepare to parse script */
@@ -6114,7 +6114,7 @@ ParseScript(const char *script, const char *desc, int weight)
 		{
 			alloc_num += COMMANDS_ALLOC_NUM;
 			ps.commands = (Command **)
-				pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
+				pg_realloc_array(ps.commands, Command *, alloc_num);
 		}
 
 		/* Done if we reached EOF */
@@ -6844,7 +6844,7 @@ main(int argc, char **argv)
 		}
 	}
 
-	state = (CState *) pg_malloc0(sizeof(CState));
+	state = pg_malloc0_object(CState);
 
 	/* set random seed early, because it may be used while parsing scripts. */
 	if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
@@ -7298,7 +7298,7 @@ main(int argc, char **argv)
 
 	if (nclients > 1)
 	{
-		state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
+		state = pg_realloc_array(state, CState, nclients);
 		memset(state + 1, 0, sizeof(CState) * (nclients - 1));
 
 		/* copy any -D switch values to all clients */
@@ -7412,7 +7412,7 @@ main(int argc, char **argv)
 	PQfinish(con);
 
 	/* set up thread data structures */
-	threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
+	threads = pg_malloc_array(TState, nthreads);
 	nclients_dealt = 0;
 
 	for (i = 0; i < nthreads; i++)
@@ -7993,7 +7993,7 @@ socket_has_input(socket_set *sa, int fd, int idx)
 static socket_set *
 alloc_socket_set(int count)
 {
-	return (socket_set *) pg_malloc0(sizeof(socket_set));
+	return pg_malloc0_object(socket_set);
 }
 
 static void
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 213d48500de..637f2703db2 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4168,8 +4168,8 @@ do_connect(enum trivalue reuse_previous_specification,
 	/* Loop till we have a connection or fail, which we might've already */
 	while (success)
 	{
-		const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
-		const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
+		const char **keywords = pg_malloc_array(const char *, nconnopts + 1);
+		const char **values = pg_malloc_array(const char *, nconnopts + 1);
 		int			paramnum = 0;
 		PQconninfoOption *ci;
 
@@ -5665,7 +5665,7 @@ savePsetInfo(const printQueryOpt *popt)
 {
 	printQueryOpt *save;
 
-	save = (printQueryOpt *) pg_malloc(sizeof(printQueryOpt));
+	save = pg_malloc_object(printQueryOpt);
 
 	/* Flat-copy all the scalar fields, then duplicate sub-structures. */
 	memcpy(save, popt, sizeof(printQueryOpt));
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 892c28894ed..6a8a9792e7d 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -99,7 +99,7 @@ parse_slash_copy(const char *args)
 		return NULL;
 	}
 
-	result = pg_malloc0(sizeof(struct copy_options));
+	result = pg_malloc0_object(struct copy_options);
 
 	result->before_tofrom = pg_strdup("");	/* initialize for appending */
 
diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c
index 3b268e41641..111e8823bdb 100644
--- a/src/bin/psql/crosstabview.c
+++ b/src/bin/psql/crosstabview.c
@@ -245,11 +245,9 @@ PrintResultInCrosstab(const PGresult *res)
 	num_columns = piv_columns.count;
 	num_rows = piv_rows.count;
 
-	array_columns = (pivot_field *)
-		pg_malloc(sizeof(pivot_field) * num_columns);
+	array_columns = pg_malloc_array(pivot_field, num_columns);
 
-	array_rows = (pivot_field *)
-		pg_malloc(sizeof(pivot_field) * num_rows);
+	array_rows = pg_malloc_array(pivot_field, num_rows);
 
 	avlCollectFields(&piv_columns, piv_columns.root, array_columns, 0);
 	avlCollectFields(&piv_rows, piv_rows.root, array_rows, 0);
@@ -312,7 +310,7 @@ printCrosstab(const PGresult *result,
 	 * map associating each piv_columns[].rank to its index in piv_columns.
 	 * This avoids an O(N^2) loop later.
 	 */
-	horiz_map = (int *) pg_malloc(sizeof(int) * num_columns);
+	horiz_map = pg_malloc_array(int, num_columns);
 	for (i = 0; i < num_columns; i++)
 		horiz_map[piv_columns[i].rank] = i;
 
@@ -437,7 +435,7 @@ error:
 static void
 avlInit(avl_tree *tree)
 {
-	tree->end = (avl_node *) pg_malloc0(sizeof(avl_node));
+	tree->end = pg_malloc0_object(avl_node);
 	tree->end->children[0] = tree->end->children[1] = tree->end;
 	tree->count = 0;
 	tree->root = tree->end;
@@ -532,8 +530,7 @@ avlInsertNode(avl_tree *tree, avl_node **node, pivot_field field)
 
 	if (current == tree->end)
 	{
-		avl_node   *new_node = (avl_node *)
-			pg_malloc(sizeof(avl_node));
+		avl_node   *new_node = pg_malloc_object(avl_node);
 
 		new_node->height = 1;
 		new_node->field = field;
@@ -591,7 +588,7 @@ rankSort(int num_columns, pivot_field *piv_columns)
 								 * every header entry] */
 	int			i;
 
-	hmap = (int *) pg_malloc(sizeof(int) * num_columns * 2);
+	hmap = pg_malloc_array(int, num_columns * 2);
 	for (i = 0; i < num_columns; i++)
 	{
 		char	   *val = piv_columns[i].sort_value;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 571a6a003d5..4352991e541 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3797,7 +3797,7 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 		return false;
 
 	nrows = PQntuples(res);
-	attr = pg_malloc0((nrows + 1) * sizeof(*attr));
+	attr = pg_malloc0_array(char *, nrows + 1);
 
 	printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
 
@@ -5306,7 +5306,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
 			 * storing "Publications:" string) + publication schema mapping
 			 * count +  1 (for storing NULL).
 			 */
-			footers = (char **) pg_malloc((1 + pub_schema_tuples + 1) * sizeof(char *));
+			footers = pg_malloc_array(char *, 1 + pub_schema_tuples + 1);
 			footers[0] = pg_strdup(_("Publications:"));
 
 			/* Might be an empty set - that's ok */
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 8b91bc00062..b2dba6d10ab 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -6324,8 +6324,7 @@ append_variable_names(char ***varnames, int *nvars,
 	if (*nvars >= *maxvars)
 	{
 		*maxvars *= 2;
-		*varnames = (char **) pg_realloc(*varnames,
-										 ((*maxvars) + 1) * sizeof(char *));
+		*varnames = pg_realloc_array(*varnames, char *, (*maxvars) + 1);
 	}
 
 	(*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix);
@@ -6350,7 +6349,7 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix
 	int			i;
 	struct _variable *ptr;
 
-	varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
+	varnames = pg_malloc_array(char *, maxvars + 1);
 
 	for (ptr = pset.vars->next; ptr; ptr = ptr->next)
 	{
@@ -6928,7 +6927,7 @@ get_previous_words(int point, char **buffer, int *nwords)
 	 * This is usually much more space than we need, but it's cheaper than
 	 * doing a separate malloc() for each word.
 	 */
-	previous_words = (char **) pg_malloc(point * sizeof(char *));
+	previous_words = pg_malloc_array(char *, point);
 	*buffer = outptr = (char *) pg_malloc(point * 2);
 
 	/*
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 1cd082db157..f2a28bc9820 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -54,7 +54,7 @@ CreateVariableSpace(void)
 {
 	struct _variable *ptr;
 
-	ptr = pg_malloc(sizeof *ptr);
+	ptr = pg_malloc_object(struct _variable);
 	ptr->name = NULL;
 	ptr->value = NULL;
 	ptr->substitute_hook = NULL;
@@ -353,7 +353,7 @@ SetVariable(VariableSpace space, const char *name, const char *value)
 	/* not present, make new entry ... unless we were asked to delete */
 	if (value)
 	{
-		current = pg_malloc(sizeof *current);
+		current = pg_malloc_object(struct _variable);
 		current->name = pg_strdup(name);
 		current->value = pg_strdup(value);
 		current->substitute_hook = NULL;
@@ -416,7 +416,7 @@ SetVariableHooks(VariableSpace space, const char *name,
 	}
 
 	/* not present, make new entry */
-	current = pg_malloc(sizeof *current);
+	current = pg_malloc_object(struct _variable);
 	current->name = pg_strdup(name);
 	current->value = NULL;
 	current->substitute_hook = shook;
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index 8bab74b5917..d7fb16d3c85 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -322,7 +322,7 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
 				 * database itself, so build a list with a single entry.
 				 */
 				Assert(user_list == NULL);
-				process_list = pg_malloc0(sizeof(SimpleStringList));
+				process_list = pg_malloc0_object(SimpleStringList);
 				simple_string_list_append(process_list, PQdb(conn));
 				break;
 
@@ -713,7 +713,7 @@ get_parallel_tables_list(PGconn *conn, ReindexType type,
 		return NULL;
 	}
 
-	tables = pg_malloc0(sizeof(SimpleStringList));
+	tables = pg_malloc0_object(SimpleStringList);
 
 	/* Build qualified identifiers for each table */
 	for (int i = 0; i < ntups; i++)
@@ -809,7 +809,7 @@ get_parallel_tabidx_list(PGconn *conn,
 		return;
 	}
 
-	*table_list = pg_malloc0(sizeof(SimpleOidList));
+	*table_list = pg_malloc0_object(SimpleOidList);
 
 	/*
 	 * Build two lists, one with table OIDs and the other with fully-qualified
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index a0aec04d994..440c875b8ac 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -147,7 +147,7 @@ main(int argc, char **argv)
 	 * extra for lock wait detection and global work.
 	 */
 	nconns = 1 + testspec->nsessions;
-	conns = (IsoConnInfo *) pg_malloc0(nconns * sizeof(IsoConnInfo));
+	conns = pg_malloc0_array(IsoConnInfo, nconns);
 	atexit(disconnect_atexit);
 
 	for (i = 0; i < nconns; i++)
@@ -262,7 +262,7 @@ check_testspec(TestSpec *testspec)
 	for (i = 0; i < testspec->nsessions; i++)
 		nallsteps += testspec->sessions[i]->nsteps;
 
-	allsteps = pg_malloc(nallsteps * sizeof(Step *));
+	allsteps = pg_malloc_array(Step *, nallsteps);
 
 	k = 0;
 	for (i = 0; i < testspec->nsessions; i++)
@@ -417,8 +417,8 @@ run_all_permutations(TestSpec *testspec)
 		nsteps += testspec->sessions[i]->nsteps;
 
 	/* Create PermutationStep workspace array */
-	steps = (PermutationStep *) pg_malloc0(sizeof(PermutationStep) * nsteps);
-	stepptrs = (PermutationStep **) pg_malloc(sizeof(PermutationStep *) * nsteps);
+	steps = pg_malloc0_array(PermutationStep, nsteps);
+	stepptrs = pg_malloc_array(PermutationStep *, nsteps);
 	for (i = 0; i < nsteps; i++)
 		stepptrs[i] = steps + i;
 
@@ -431,7 +431,7 @@ run_all_permutations(TestSpec *testspec)
 	 * A pile is actually just an integer which tells how many steps we've
 	 * already picked from this pile.
 	 */
-	piles = pg_malloc(sizeof(int) * testspec->nsessions);
+	piles = pg_malloc_array(int, testspec->nsessions);
 	for (i = 0; i < testspec->nsessions; i++)
 		piles[i] = 0;
 
@@ -524,7 +524,7 @@ run_permutation(TestSpec *testspec, int nsteps, PermutationStep **steps)
 	int			nwaiting = 0;
 	PermutationStep **waiting;
 
-	waiting = pg_malloc(sizeof(PermutationStep *) * testspec->nsessions);
+	waiting = pg_malloc_array(PermutationStep *, testspec->nsessions);
 
 	printf("\nstarting permutation:");
 	for (i = 0; i < nsteps; i++)
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index b61d789d8f0..f6b9058e557 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -83,8 +83,8 @@ setup_list:
 			}
 			| setup_list setup
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $2;
 				$$.nelements = $1.nelements + 1;
 			}
@@ -107,15 +107,15 @@ opt_teardown:
 session_list:
 			session_list session
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $2;
 				$$.nelements = $1.nelements + 1;
 			}
 			| session
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
+				$$.elements = pg_malloc_object(void *);
 				$$.elements[0] = $1;
 			}
 		;
@@ -123,7 +123,7 @@ session_list:
 session:
 			SESSION identifier opt_setup step_list opt_teardown
 			{
-				$$ = pg_malloc(sizeof(Session));
+				$$ = pg_malloc_object(Session);
 				$$->name = $2;
 				$$->setupsql = $3;
 				$$->steps = (Step **) $4.elements;
@@ -135,15 +135,15 @@ session:
 step_list:
 			step_list step
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $2;
 				$$.nelements = $1.nelements + 1;
 			}
 			| step
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
+				$$.elements = pg_malloc_object(void *);
 				$$.elements[0] = $1;
 			}
 		;
@@ -152,7 +152,7 @@ step_list:
 step:
 			STEP identifier sqlblock
 			{
-				$$ = pg_malloc(sizeof(Step));
+				$$ = pg_malloc_object(Step);
 				$$->name = $2;
 				$$->sql = $3;
 				$$->session = -1; /* until filled */
@@ -175,15 +175,15 @@ opt_permutation_list:
 permutation_list:
 			permutation_list permutation
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $2;
 				$$.nelements = $1.nelements + 1;
 			}
 			| permutation
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
+				$$.elements = pg_malloc_object(void *);
 				$$.elements[0] = $1;
 			}
 		;
@@ -192,7 +192,7 @@ permutation_list:
 permutation:
 			PERMUTATION permutation_step_list
 			{
-				$$ = pg_malloc(sizeof(Permutation));
+				$$ = pg_malloc_object(Permutation);
 				$$->nsteps = $2.nelements;
 				$$->steps = (PermutationStep **) $2.elements;
 			}
@@ -201,15 +201,15 @@ permutation:
 permutation_step_list:
 			permutation_step_list permutation_step
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $2;
 				$$.nelements = $1.nelements + 1;
 			}
 			| permutation_step
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
+				$$.elements = pg_malloc_object(void *);
 				$$.elements[0] = $1;
 			}
 		;
@@ -217,7 +217,7 @@ permutation_step_list:
 permutation_step:
 			identifier
 			{
-				$$ = pg_malloc(sizeof(PermutationStep));
+				$$ = pg_malloc_object(PermutationStep);
 				$$->name = $1;
 				$$->blockers = NULL;
 				$$->nblockers = 0;
@@ -225,7 +225,7 @@ permutation_step:
 			}
 			| identifier '(' blocker_list ')'
 			{
-				$$ = pg_malloc(sizeof(PermutationStep));
+				$$ = pg_malloc_object(PermutationStep);
 				$$->name = $1;
 				$$->blockers = (PermutationStepBlocker **) $3.elements;
 				$$->nblockers = $3.nelements;
@@ -236,15 +236,15 @@ permutation_step:
 blocker_list:
 			blocker_list ',' blocker
 			{
-				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
+				$$.elements = pg_realloc_array($1.elements, void *,
+											   $1.nelements + 1);
 				$$.elements[$1.nelements] = $3;
 				$$.nelements = $1.nelements + 1;
 			}
 			| blocker
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
+				$$.elements = pg_malloc_object(void *);
 				$$.elements[0] = $1;
 			}
 		;
@@ -252,7 +252,7 @@ blocker_list:
 blocker:
 			identifier
 			{
-				$$ = pg_malloc(sizeof(PermutationStepBlocker));
+				$$ = pg_malloc_object(PermutationStepBlocker);
 				$$->stepname = $1;
 				$$->blocktype = PSB_OTHER_STEP;
 				$$->num_notices = -1;
@@ -261,7 +261,7 @@ blocker:
 			}
 			| identifier NOTICES INTEGER
 			{
-				$$ = pg_malloc(sizeof(PermutationStepBlocker));
+				$$ = pg_malloc_object(PermutationStepBlocker);
 				$$->stepname = $1;
 				$$->blocktype = PSB_NUM_NOTICES;
 				$$->num_notices = $3;
@@ -270,7 +270,7 @@ blocker:
 			}
 			| '*'
 			{
-				$$ = pg_malloc(sizeof(PermutationStepBlocker));
+				$$ = pg_malloc_object(PermutationStepBlocker);
 				$$->stepname = NULL;
 				$$->blocktype = PSB_ONCE;
 				$$->num_notices = -1;
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 409b3a7fa45..aa0a6bbe762 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -260,8 +260,8 @@ copy_connection(PGconn *conn)
 		nopts++;
 	nopts++;					/* for the NULL terminator */
 
-	keywords = pg_malloc(sizeof(char *) * nopts);
-	vals = pg_malloc(sizeof(char *) * nopts);
+	keywords = pg_malloc_array(const char *, nopts);
+	vals = pg_malloc_array(const char *, nopts);
 
 	i = 0;
 	for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
@@ -1337,8 +1337,8 @@ test_protocol_version(PGconn *conn)
 		nopts++;
 	nopts++;					/* NULL terminator */
 
-	keywords = pg_malloc0(sizeof(char *) * nopts);
-	vals = pg_malloc0(sizeof(char *) * nopts);
+	keywords = pg_malloc0_array(const char *, nopts);
+	vals = pg_malloc0_array(const char *, nopts);
 
 	i = 0;
 	for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index b5c0cb647a8..b8b6a911987 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -196,7 +196,7 @@ unlimit_core_size(void)
 void
 add_stringlist_item(_stringlist **listhead, const char *str)
 {
-	_stringlist *newentry = pg_malloc(sizeof(_stringlist));
+	_stringlist *newentry = pg_malloc_object(_stringlist);
 	_stringlist *oldentry;
 
 	newentry->str = pg_strdup(str);
@@ -674,7 +674,7 @@ load_resultmap(void)
 		 */
 		if (string_matches_pattern(host_platform, platform))
 		{
-			_resultmap *entry = pg_malloc(sizeof(_resultmap));
+			_resultmap *entry = pg_malloc_object(_resultmap);
 
 			entry->test = pg_strdup(buf);
 			entry->type = pg_strdup(file_type);
@@ -1557,7 +1557,7 @@ wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
 	int			i;
 
 #ifdef WIN32
-	PID_TYPE   *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
+	PID_TYPE   *active_pids = pg_malloc_array(PID_TYPE, num_tests);
 
 	memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
 #endif
-- 
2.47.3

From 1e6fcfa51df10912e665cc9bd583e49eb03f6f13 Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email-masked]>
Date: Fri, 27 Feb 2026 02:11:17 +0100
Subject: [PATCH v1 2/3] TODO: What to do about when we allocate an array of
 char?

---
 contrib/oid2name/oid2name.c        | 8 ++++----
 src/bin/initdb/initdb.c            | 4 ++--
 src/bin/pg_basebackup/walmethods.c | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index 1e9efcd3953..cfa342a2926 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -275,7 +275,7 @@ get_comma_elts(eary *eary)
 	for (i = 0; i < eary->num; i++)
 		length += strlen(eary->array[i]);
 
-	ret = (char *) pg_malloc(length * 2 + 4 * eary->num);
+	ret = pg_malloc_array(char, length * 2 + 4 * eary->num);
 	ptr = ret;
 
 	for (i = 0; i < eary->num; i++)
@@ -423,7 +423,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
 			l += length[j] + 2;
 		}
 		fprintf(stdout, "\n");
-		pad = (char *) pg_malloc(l + 1);
+		pad = pg_malloc_array(char, l + 1);
 		memset(pad, '-', l);
 		pad[l] = '\0';
 		fprintf(stdout, "%s\n", pad);
@@ -515,8 +515,8 @@ sql_exec_searchtables(PGconn *conn, struct options *opts)
 	comma_filenumbers = get_comma_elts(opts->filenumbers);
 
 	/* 80 extra chars for SQL expression */
-	qualifiers = (char *) pg_malloc(strlen(comma_oids) + strlen(comma_tables) +
-									strlen(comma_filenumbers) + 80);
+	qualifiers = pg_malloc_array(char, strlen(comma_oids) + strlen(comma_tables) +
+								 strlen(comma_filenumbers) + 80);
 	ptr = qualifiers;
 
 	if (opts->oids->num > 0)
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 53ec1544ff3..b6916bad201 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -426,7 +426,7 @@ escape_quotes_bki(const char *src)
 	char	   *resultp;
 	char	   *datap;
 
-	result = (char *) pg_malloc(strlen(data) + 3);
+	result = pg_malloc_array(char, strlen(data) + 3);
 	resultp = result;
 	*resultp++ = '\'';
 	for (datap = data; *datap; datap++)
@@ -492,7 +492,7 @@ replace_token(char **lines, const char *token, const char *replacement)
 
 		/* if we get here a change is needed - set up new line */
 
-		newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
+		newline = pg_malloc_array(char, strlen(lines[i]) + diff + 1);
 
 		pre = where - lines[i];
 
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 476673cf729..3a6b3b5f45b 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -102,7 +102,7 @@ static char *
 dir_get_file_name(WalWriteMethod *wwmethod,
 				  const char *pathname, const char *temp_suffix)
 {
-	char	   *filename = pg_malloc0(MAXPGPATH * sizeof(char));
+	char	   *filename = pg_malloc0_array(char, MAXPGPATH);
 
 	snprintf(filename, MAXPGPATH, "%s%s%s",
 			 pathname,
-- 
2.47.3

From 2056a1f6c1422e0f2a56b4a832ddf92ecf8256ff Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email-masked]>
Date: Fri, 27 Feb 2026 02:11:30 +0100
Subject: [PATCH v1 3/3] TODO: uint8 vs char confusion

---
 src/bin/pg_verifybackup/pg_verifybackup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index cbc9447384f..562e9212e30 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -1007,7 +1007,7 @@ verify_tar_file(verifier_context *context, char *relpath, char *fullpath,
 		return;
 	}
 
-	buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));
+	buffer = pg_malloc_array(char, READ_CHUNK_SIZE);
 
 	/* Perform the reads */
 	while ((rc = read(fd, buffer, READ_CHUNK_SIZE)) > 0)
-- 
2.47.3