After many years of trying, it seems the -fsanitize=undefined checking
in gcc is now working somewhat reliably.  Attached is a patch that fixes
all errors of the kind

runtime error: null pointer passed as argument N, which is declared to
never be null

Most of the cases are calls to memcpy(), memcmp(), etc. with a length of
zero, so one appears to get away with passing a null pointer.

Note that these are runtime errors, not static analysis, so the code in
question is actually reached.

To reproduce, configure normally and then set

COPT=-fsanitize=undefined -fno-sanitize=alignment -fno-sanitize-recover=all

and build and run make check-world.  Unpatched, this will core dump in
various places.

(-fno-sanitize=alignment should also be fixed but I took it out here to
deal with it separately.)

See https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html for
further documentation.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 4b657d1af4a8518218be207024b123cfa6d799d8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Mon, 3 Jun 2019 20:55:35 +0200
Subject: [PATCH] Fix runtime errors from -fsanitize-undefined

These are of the form

runtime error: null pointer passed as argument N, which is declared to never be 
null
---
 contrib/pgcrypto/px.c                       |  2 +-
 src/backend/access/heap/heapam.c            |  2 +-
 src/backend/access/heap/heapam_visibility.c |  2 ++
 src/backend/access/transam/clog.c           |  1 +
 src/backend/access/transam/xact.c           |  5 +++--
 src/backend/commands/indexcmds.c            |  3 ++-
 src/backend/utils/cache/relcache.c          |  8 ++++++--
 src/backend/utils/misc/guc.c                |  2 +-
 src/backend/utils/time/snapmgr.c            | 10 ++++++----
 src/fe_utils/print.c                        |  3 ++-
 10 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c
index 0f02fb56c4..ec9cf99086 100644
--- a/contrib/pgcrypto/px.c
+++ b/contrib/pgcrypto/px.c
@@ -200,7 +200,7 @@ combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
                memset(ivbuf, 0, ivs);
                if (ivlen > ivs)
                        memcpy(ivbuf, iv, ivs);
-               else
+               else if (ivlen > 0)
                        memcpy(ivbuf, iv, ivlen);
        }
 
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 419da8784a..52e3782282 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -307,7 +307,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool 
keep_startblock)
        /*
         * copy the scan key, if appropriate
         */
-       if (key != NULL)
+       if (key != NULL && scan->rs_base.rs_nkeys)
                memcpy(scan->rs_base.rs_key, key, scan->rs_base.rs_nkeys * 
sizeof(ScanKeyData));
 
        /*
diff --git a/src/backend/access/heap/heapam_visibility.c 
b/src/backend/access/heap/heapam_visibility.c
index 537e681b23..9c291cd1ab 100644
--- a/src/backend/access/heap/heapam_visibility.c
+++ b/src/backend/access/heap/heapam_visibility.c
@@ -1520,6 +1520,8 @@ HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
 static bool
 TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
 {
+       if (!xip)
+               return false;
        return bsearch(&xid, xip, num,
                                   sizeof(TransactionId), xidComparator) != 
NULL;
 }
diff --git a/src/backend/access/transam/clog.c 
b/src/backend/access/transam/clog.c
index 47db7a8a88..4324229a61 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -294,6 +294,7 @@ TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
         * on the same page.  Check those conditions, too.
         */
        if (all_xact_same_page && xid == MyPgXact->xid &&
+               nsubxids > 0 &&
                nsubxids <= THRESHOLD_SUBTRANS_CLOG_OPT &&
                nsubxids == MyPgXact->nxids &&
                memcmp(subxids, MyProc->subxids.xids,
diff --git a/src/backend/access/transam/xact.c 
b/src/backend/access/transam/xact.c
index f1108ccc8b..976ab5a950 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -5201,8 +5201,9 @@ SerializeTransactionState(Size maxsize, char 
*start_address)
        {
                if (FullTransactionIdIsValid(s->fullTransactionId))
                        workspace[i++] = 
XidFromFullTransactionId(s->fullTransactionId);
-               memcpy(&workspace[i], s->childXids,
-                          s->nChildXids * sizeof(TransactionId));
+               if (s->nChildXids > 0)
+                       memcpy(&workspace[i], s->childXids,
+                                  s->nChildXids * sizeof(TransactionId));
                i += s->nChildXids;
        }
        Assert(i == nxids);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 40ea629ffe..af45e44a00 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1051,7 +1051,8 @@ DefineIndex(Oid relationId,
                        
pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_TOTAL,
                                                                                
 nparts);
 
-                       memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
+                       if (nparts > 0)
+                               memcpy(part_oids, partdesc->oids, sizeof(Oid) * 
nparts);
 
                        parentDesc = CreateTupleDescCopy(RelationGetDescr(rel));
                        opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
diff --git a/src/backend/utils/cache/relcache.c 
b/src/backend/utils/cache/relcache.c
index 2b992d7832..a56f2a4145 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -5900,10 +5900,14 @@ write_relcache_init_file(bool shared)
 static void
 write_item(const void *data, Size len, FILE *fp)
 {
+       Assert(data || len == 0);
        if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
                elog(FATAL, "could not write init file");
-       if (fwrite(data, 1, len, fp) != len)
-               elog(FATAL, "could not write init file");
+       if (data)
+       {
+               if (fwrite(data, 1, len, fp) != len)
+                       elog(FATAL, "could not write init file");
+       }
 }
 
 /*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1208eb9a68..29b15fa2bd 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -9066,7 +9066,7 @@ GetConfigOptionByNum(int varnum, const char **values, 
bool *noshow)
        values[4] = _(conf->short_desc);
 
        /* extra_desc */
-       values[5] = _(conf->long_desc);
+       values[5] = conf->long_desc ? _(conf->long_desc) : NULL;
 
        /* context */
        values[6] = GucContext_Names[conf->context];
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index ef9fc15ac3..b9df5e8ae6 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -594,12 +594,14 @@ SetTransactionSnapshot(Snapshot sourcesnap, 
VirtualTransactionId *sourcevxid,
        CurrentSnapshot->xmax = sourcesnap->xmax;
        CurrentSnapshot->xcnt = sourcesnap->xcnt;
        Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
-       memcpy(CurrentSnapshot->xip, sourcesnap->xip,
-                  sourcesnap->xcnt * sizeof(TransactionId));
+       if (sourcesnap->xcnt > 0)
+               memcpy(CurrentSnapshot->xip, sourcesnap->xip,
+                          sourcesnap->xcnt * sizeof(TransactionId));
        CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
        Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
-       memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
-                  sourcesnap->subxcnt * sizeof(TransactionId));
+       if (sourcesnap->subxcnt > 0)
+               memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
+                          sourcesnap->subxcnt * sizeof(TransactionId));
        CurrentSnapshot->suboverflowed = sourcesnap->suboverflowed;
        CurrentSnapshot->takenDuringRecovery = sourcesnap->takenDuringRecovery;
        /* NB: curcid should NOT be copied, it's a local matter */
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index e41f42ea98..c7c101aa13 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -913,7 +913,8 @@ print_aligned_text(const printTableContent *cont, FILE 
*fout, bool is_pager)
 
                        more_col_wrapping = col_count;
                        curr_nl_line = 0;
-                       memset(header_done, false, col_count * sizeof(bool));
+                       if (header_done)
+                               memset(header_done, false, col_count * 
sizeof(bool));
                        while (more_col_wrapping)
                        {
                                if (opt_border == 2)
-- 
2.21.0

Reply via email to