On 2020-08-03 19:39, Tom Lane wrote:
That's easy to fix, but it's perhaps wondering briefly why it needs to
be zero-padded.  hashname() doesn't care, heap_form_tuple() doesn't
care.  Does anything care?

We do have an expectation that there are no undefined bytes in values to
be stored on-disk.  There's even some code in coerce_type() that will
complain about this:

Okay, here is a new patch with improved implementations of namecpy() and namestrcpy(). I didn't see any other places that relied on the zero-filling behavior of strncpy().

While we're here, shouldn't namestrcpy() do some pg_mbcliplen() stuff
like namein()?

Excellent point --- probably so, unless the callers are all truncating
in advance, which I doubt.

I will look into that separately.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 740866001613e9d6aa29f759085ea284c0d41c94 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Tue, 4 Aug 2020 15:16:37 +0200
Subject: [PATCH v2] Replace remaining StrNCpy() by strlcpy()

They are equivalent, and strlcpy() has become the preferred spelling.
Convert over the remaining cases.  Remove StrNCpy() as it is now
unused.
---
 contrib/pgcrypto/crypt-des.c                  |  2 +-
 src/backend/access/transam/slru.c             |  2 +-
 src/backend/access/transam/xlogarchive.c      |  2 +-
 src/backend/catalog/pg_constraint.c           |  2 +-
 src/backend/commands/indexcmds.c              |  2 +-
 src/backend/commands/statscmds.c              |  2 +-
 src/backend/commands/tablecmds.c              |  2 +-
 src/backend/postmaster/pgstat.c               |  2 +-
 src/backend/replication/logical/logical.c     |  3 +-
 src/backend/replication/slot.c                |  2 +-
 src/backend/utils/adt/formatting.c            |  8 ++---
 src/backend/utils/adt/name.c                  |  6 ++--
 src/backend/utils/adt/pg_locale.c             |  9 ------
 src/backend/utils/adt/ruleutils.c             |  2 +-
 src/common/exec.c                             |  4 +--
 src/include/c.h                               | 29 -------------------
 src/interfaces/ecpg/pgtypeslib/dt_common.c    |  4 +--
 src/interfaces/ecpg/test/pg_regress_ecpg.c    |  2 +-
 .../ssl_passphrase_func.c                     |  2 +-
 19 files changed, 26 insertions(+), 61 deletions(-)

diff --git a/contrib/pgcrypto/crypt-des.c b/contrib/pgcrypto/crypt-des.c
index 6efaa609c9..98c30ea122 100644
--- a/contrib/pgcrypto/crypt-des.c
+++ b/contrib/pgcrypto/crypt-des.c
@@ -720,7 +720,7 @@ px_crypt_des(const char *key, const char *setting)
                        if (des_setkey((char *) keybuf))
                                return NULL;
                }
-               StrNCpy(output, setting, 10);
+               strlcpy(output, setting, 10);
 
                /*
                 * Double check that we weren't given a short setting. If we 
were, the
diff --git a/src/backend/access/transam/slru.c 
b/src/backend/access/transam/slru.c
index 9e145f1c36..d1dbb43e09 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -252,7 +252,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, 
int nlsns,
         */
        ctl->shared = shared;
        ctl->do_fsync = true;           /* default behavior */
-       StrNCpy(ctl->Dir, subdir, sizeof(ctl->Dir));
+       strlcpy(ctl->Dir, subdir, sizeof(ctl->Dir));
 }
 
 /*
diff --git a/src/backend/access/transam/xlogarchive.c 
b/src/backend/access/transam/xlogarchive.c
index cdd586fcfb..8f8734dc1d 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -323,7 +323,7 @@ ExecuteRecoveryCommand(const char *command, const char 
*commandName, bool failOn
                                case 'r':
                                        /* %r: filename of last restartpoint */
                                        sp++;
-                                       StrNCpy(dp, lastRestartPointFname, endp 
- dp);
+                                       strlcpy(dp, lastRestartPointFname, endp 
- dp);
                                        dp += strlen(dp);
                                        break;
                                case '%':
diff --git a/src/backend/catalog/pg_constraint.c 
b/src/backend/catalog/pg_constraint.c
index fdc63e7dea..6a6b2cb8c0 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -484,7 +484,7 @@ ChooseConstraintName(const char *name1, const char *name2,
        conDesc = table_open(ConstraintRelationId, AccessShareLock);
 
        /* try the unmodified label first */
-       StrNCpy(modlabel, label, sizeof(modlabel));
+       strlcpy(modlabel, label, sizeof(modlabel));
 
        for (;;)
        {
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2baca12c5f..7819266a63 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2246,7 +2246,7 @@ ChooseRelationName(const char *name1, const char *name2,
        char            modlabel[NAMEDATALEN];
 
        /* try the unmodified label first */
-       StrNCpy(modlabel, label, sizeof(modlabel));
+       strlcpy(modlabel, label, sizeof(modlabel));
 
        for (;;)
        {
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 974828545c..3057d89d50 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -681,7 +681,7 @@ ChooseExtendedStatisticName(const char *name1, const char 
*name2,
        char            modlabel[NAMEDATALEN];
 
        /* try the unmodified label first */
-       StrNCpy(modlabel, label, sizeof(modlabel));
+       strlcpy(modlabel, label, sizeof(modlabel));
 
        for (;;)
        {
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ac53f79ada..cd989c95e5 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -606,7 +606,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
         * Truncate relname to appropriate length (probably a waste of time, as
         * parser should have done this already).
         */
-       StrNCpy(relname, stmt->relation->relname, NAMEDATALEN);
+       strlcpy(relname, stmt->relation->relname, NAMEDATALEN);
 
        /*
         * Check consistency of arguments
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 15f92b66c6..73ce944fb1 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -4367,7 +4367,7 @@ pgstat_send_archiver(const char *xlog, bool failed)
         */
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ARCHIVER);
        msg.m_failed = failed;
-       StrNCpy(msg.m_xlog, xlog, sizeof(msg.m_xlog));
+       strlcpy(msg.m_xlog, xlog, sizeof(msg.m_xlog));
        msg.m_timestamp = GetCurrentTimestamp();
        pgstat_send(&msg, sizeof(msg));
 }
diff --git a/src/backend/replication/logical/logical.c 
b/src/backend/replication/logical/logical.c
index 05d24b93da..ebc0b7080e 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -39,6 +39,7 @@
 #include "replication/snapbuild.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
+#include "utils/builtins.h"
 #include "utils/memutils.h"
 
 /* data for errcontext callback */
@@ -321,7 +322,7 @@ CreateInitDecodingContext(char *plugin,
 
        /* register output plugin name with slot */
        SpinLockAcquire(&slot->mutex);
-       StrNCpy(NameStr(slot->data.plugin), plugin, NAMEDATALEN);
+       namestrcpy(&slot->data.plugin, plugin);
        SpinLockRelease(&slot->mutex);
 
        if (XLogRecPtrIsInvalid(restart_lsn))
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 57bbb6288c..3dc01b6df2 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -275,7 +275,7 @@ ReplicationSlotCreate(const char *name, bool db_specific,
 
        /* first initialize persistent data */
        memset(&slot->data, 0, sizeof(ReplicationSlotPersistentData));
-       StrNCpy(NameStr(slot->data.name), name, NAMEDATALEN);
+       namestrcpy(&slot->data.name, name);
        slot->data.database = db_specific ? MyDatabaseId : InvalidOid;
        slot->data.persistency = persistency;
 
diff --git a/src/backend/utils/adt/formatting.c 
b/src/backend/utils/adt/formatting.c
index 6626438136..9de63686ec 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -3890,7 +3890,7 @@ DCH_cache_getnew(const char *str, bool std)
                elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, 
old->age);
 #endif
                old->valid = false;
-               StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
+               strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
                old->age = (++DCHCounter);
                /* caller is expected to fill format, then set valid */
                return old;
@@ -3904,7 +3904,7 @@ DCH_cache_getnew(const char *str, bool std)
                DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
                        MemoryContextAllocZero(TopMemoryContext, 
sizeof(DCHCacheEntry));
                ent->valid = false;
-               StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
+               strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
                ent->std = std;
                ent->age = (++DCHCounter);
                /* caller is expected to fill format, then set valid */
@@ -4799,7 +4799,7 @@ NUM_cache_getnew(const char *str)
                elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, 
old->age);
 #endif
                old->valid = false;
-               StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
+               strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
                old->age = (++NUMCounter);
                /* caller is expected to fill format and Num, then set valid */
                return old;
@@ -4813,7 +4813,7 @@ NUM_cache_getnew(const char *str)
                NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
                        MemoryContextAllocZero(TopMemoryContext, 
sizeof(NUMCacheEntry));
                ent->valid = false;
-               StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
+               strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
                ent->age = (++NUMCounter);
                /* caller is expected to fill format and Num, then set valid */
                ++n_NUMCache;
diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c
index 64877f67e0..895def56c2 100644
--- a/src/backend/utils/adt/name.c
+++ b/src/backend/utils/adt/name.c
@@ -234,7 +234,7 @@ namecpy(Name n1, const NameData *n2)
 {
        if (!n1 || !n2)
                return -1;
-       StrNCpy(NameStr(*n1), NameStr(*n2), NAMEDATALEN);
+       memcpy(n1, n2, NAMEDATALEN);
        return 0;
 }
 
@@ -251,7 +251,9 @@ namestrcpy(Name name, const char *str)
 {
        if (!name || !str)
                return -1;
-       StrNCpy(NameStr(*name), str, NAMEDATALEN);
+       /* NB: We need to zero-pad the destination. */
+       strncpy(NameStr(*name), str, NAMEDATALEN);
+       NameStr(*name)[NAMEDATALEN-1] = '\0';
        return 0;
 }
 
diff --git a/src/backend/utils/adt/pg_locale.c 
b/src/backend/utils/adt/pg_locale.c
index 11d05c73ac..07299dbc09 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -75,16 +75,7 @@
 #endif
 
 #ifdef WIN32
-/*
- * This Windows file defines StrNCpy. We don't need it here, so we undefine
- * it to keep the compiler quiet, and undefine it again after the file is
- * included, so we don't accidentally use theirs.
- */
-#undef StrNCpy
 #include <shlwapi.h>
-#ifdef StrNCpy
-#undef StrNCpy
-#endif
 #endif
 
 #define                MAX_L10N_DATA           80
diff --git a/src/backend/utils/adt/ruleutils.c 
b/src/backend/utils/adt/ruleutils.c
index 2cbcb4b85e..f507e5cd76 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2489,7 +2489,7 @@ pg_get_userbyid(PG_FUNCTION_ARGS)
        if (HeapTupleIsValid(roletup))
        {
                role_rec = (Form_pg_authid) GETSTRUCT(roletup);
-               StrNCpy(NameStr(*result), NameStr(role_rec->rolname), 
NAMEDATALEN);
+               namecpy(result, &role_rec->rolname);
                ReleaseSysCache(roletup);
        }
        else
diff --git a/src/common/exec.c b/src/common/exec.c
index f39b0a294b..78bb486f99 100644
--- a/src/common/exec.c
+++ b/src/common/exec.c
@@ -144,7 +144,7 @@ find_my_exec(const char *argv0, char *retpath)
        if (first_dir_separator(argv0) != NULL)
        {
                if (is_absolute_path(argv0))
-                       StrNCpy(retpath, argv0, MAXPGPATH);
+                       strlcpy(retpath, argv0, MAXPGPATH);
                else
                        join_path_components(retpath, cwd, argv0);
                canonicalize_path(retpath);
@@ -184,7 +184,7 @@ find_my_exec(const char *argv0, char *retpath)
                        if (!endp)
                                endp = startp + strlen(startp); /* point to end 
*/
 
-                       StrNCpy(test_path, startp, Min(endp - startp + 1, 
MAXPGPATH));
+                       strlcpy(test_path, startp, Min(endp - startp + 1, 
MAXPGPATH));
 
                        if (is_absolute_path(test_path))
                                join_path_components(retpath, test_path, argv0);
diff --git a/src/include/c.h b/src/include/c.h
index f242e32edb..2c61ca8aa8 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -932,35 +932,6 @@ extern void ExceptionalCondition(const char *conditionName,
  */
 #define Abs(x)                 ((x) >= 0 ? (x) : -(x))
 
-/*
- * StrNCpy
- *     Like standard library function strncpy(), except that result string
- *     is guaranteed to be null-terminated --- that is, at most N-1 bytes
- *     of the source string will be kept.
- *     Also, the macro returns no result (too hard to do that without
- *     evaluating the arguments multiple times, which seems worse).
- *
- *     BTW: when you need to copy a non-null-terminated string (like a text
- *     datum) and add a null, do not do it with StrNCpy(..., len+1).  That
- *     might seem to work, but it fetches one byte more than there is in the
- *     text object.  One fine day you'll have a SIGSEGV because there isn't
- *     another byte before the end of memory.  Don't laugh, we've had real
- *     live bug reports from real live users over exactly this mistake.
- *     Do it honestly with "memcpy(dst,src,len); dst[len] = '\0';", instead.
- */
-#define StrNCpy(dst,src,len) \
-       do \
-       { \
-               char * _dst = (dst); \
-               Size _len = (len); \
-\
-               if (_len > 0) \
-               { \
-                       strncpy(_dst, (src), _len); \
-                       _dst[_len-1] = '\0'; \
-               } \
-       } while (0)
-
 
 /* Get a bit mask of the bits set in non-long aligned addresses */
 #define LONG_ALIGN_MASK (sizeof(long) - 1)
diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c 
b/src/interfaces/ecpg/pgtypeslib/dt_common.c
index 14cdf2d428..e8a8a0f0ed 100644
--- a/src/interfaces/ecpg/pgtypeslib/dt_common.c
+++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c
@@ -1015,7 +1015,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, 
char **tzn)
                         * Copy no more than MAXTZLEN bytes of timezone to tzn, 
in case it
                         * contains an error message, which doesn't fit in the 
buffer
                         */
-                       StrNCpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
+                       strlcpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
                        if (strlen(tm->tm_zone) > MAXTZLEN)
                                tm->tm_isdst = -1;
                }
@@ -1033,7 +1033,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, 
char **tzn)
                         * Copy no more than MAXTZLEN bytes of timezone to tzn, 
in case it
                         * contains an error message, which doesn't fit in the 
buffer
                         */
-                       StrNCpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 
1);
+                       strlcpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 
1);
                        if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
                                tm->tm_isdst = -1;
                }
diff --git a/src/interfaces/ecpg/test/pg_regress_ecpg.c 
b/src/interfaces/ecpg/test/pg_regress_ecpg.c
index 956a599fcb..46b9e78fe5 100644
--- a/src/interfaces/ecpg/test/pg_regress_ecpg.c
+++ b/src/interfaces/ecpg/test/pg_regress_ecpg.c
@@ -63,7 +63,7 @@ ecpg_filter(const char *sourcefile, const char *outfile)
                        if (plen > 1)
                        {
                                n = (char *) malloc(plen);
-                               StrNCpy(n, p + 1, plen);
+                               strlcpy(n, p + 1, plen);
                                replace_string(linebuf, n, "");
                        }
                }
diff --git a/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c 
b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c
index 563ff144cc..6b0a3db104 100644
--- a/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c
+++ b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c
@@ -74,7 +74,7 @@ rot13_passphrase(char *buf, int size, int rwflag, void 
*userdata)
 {
 
        Assert(ssl_passphrase != NULL);
-       StrNCpy(buf, ssl_passphrase, size);
+       strlcpy(buf, ssl_passphrase, size);
        for (char *p = buf; *p; p++)
        {
                char            c = *p;
-- 
2.28.0

Reply via email to