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