From c92f7e258ee579abd0f95183598edf250d351b2c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 27 Sep 2006 18:40:10 +0000 Subject: [PATCH] Replace strncpy with strlcpy in selected places that seem possibly relevant to performance. (A wholesale effort to get rid of strncpy should be undertaken sometime, but not during beta.) This commit also fixes dynahash.c to correctly truncate overlength string keys for hashtables, so that its callers don't have to anymore. --- src/backend/commands/prepare.c | 22 ++++------------------ src/backend/nodes/read.c | 4 ++-- src/backend/storage/ipc/shmem.c | 15 ++++++--------- src/backend/utils/error/elog.c | 18 +++++++++++------- src/backend/utils/fmgr/dfmgr.c | 8 ++------ src/backend/utils/hash/dynahash.c | 28 +++++++++++++++++++++------- src/backend/utils/hash/hashfn.c | 12 ++++++++++-- src/backend/utils/misc/ps_status.c | 4 ++-- src/backend/utils/mmgr/portalmem.c | 20 +++++++------------- src/port/path.c | 10 +++++----- src/port/thread.c | 4 ++-- 11 files changed, 72 insertions(+), 73 deletions(-) diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index eccce9d10d..46824a48e5 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.64 2006/09/07 22:52:00 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.65 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -314,7 +314,6 @@ StorePreparedStatement(const char *stmt_name, MemoryContext oldcxt, entrycxt; char *qstring; - char key[NAMEDATALEN]; bool found; /* Initialize the hash table, if necessary */ @@ -322,10 +321,7 @@ StorePreparedStatement(const char *stmt_name, InitQueryHashTable(); /* Check for pre-existing entry of same name */ - /* See notes in FetchPreparedStatement */ - StrNCpy(key, stmt_name, sizeof(key)); - - hash_search(prepared_queries, key, HASH_FIND, &found); + hash_search(prepared_queries, stmt_name, HASH_FIND, &found); if (found) ereport(ERROR, @@ -355,7 +351,7 @@ StorePreparedStatement(const char *stmt_name, /* Now we can add entry to hash table */ entry = (PreparedStatement *) hash_search(prepared_queries, - key, + stmt_name, HASH_ENTER, &found); @@ -384,7 +380,6 @@ StorePreparedStatement(const char *stmt_name, PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError) { - char key[NAMEDATALEN]; PreparedStatement *entry; /* @@ -392,19 +387,10 @@ FetchPreparedStatement(const char *stmt_name, bool throwError) * anything, therefore it couldn't possibly store our plan. */ if (prepared_queries) - { - /* - * We can't just use the statement name as supplied by the user: the - * hash package is picky enough that it needs to be NUL-padded out to - * the appropriate length to work correctly. - */ - StrNCpy(key, stmt_name, sizeof(key)); - entry = (PreparedStatement *) hash_search(prepared_queries, - key, + stmt_name, HASH_FIND, NULL); - } else entry = NULL; diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c index 14ccb88942..4563478899 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.48 2006/03/05 15:58:28 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/read.c,v 1.49 2006/09/27 18:40:09 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -408,7 +408,7 @@ nodeRead(char *token, int tok_len) char *val = palloc(tok_len); /* skip leading 'b' */ - strncpy(val, token + 1, tok_len - 1); + memcpy(val, token + 1, tok_len - 1); val[tok_len - 1] = '\0'; result = (Node *) makeBitString(val); break; diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 3c48173f2f..4cff4c19f3 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.95 2006/08/01 19:03:11 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.96 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -456,13 +456,9 @@ ShmemInitHash(const char *name, /* table string name for shmem index */ void * ShmemInitStruct(const char *name, Size size, bool *foundPtr) { - ShmemIndexEnt *result, - item; + ShmemIndexEnt *result; void *structPtr; - strncpy(item.key, name, SHMEM_INDEX_KEYSIZE); - item.location = BAD_LOCATION; - LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE); if (!ShmemIndex) @@ -498,7 +494,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) /* look it up in the shmem index */ result = (ShmemIndexEnt *) - hash_search(ShmemIndex, (void *) &item, HASH_ENTER_NULL, foundPtr); + hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr); if (!result) { @@ -533,12 +529,13 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) { /* out of memory */ Assert(ShmemIndex); - hash_search(ShmemIndex, (void *) &item, HASH_REMOVE, NULL); + hash_search(ShmemIndex, name, HASH_REMOVE, NULL); LWLockRelease(ShmemIndexLock); ereport(WARNING, (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("could not allocate shared memory segment \"%s\"", name))); + errmsg("could not allocate shared memory segment \"%s\"", + name))); *foundPtr = FALSE; return NULL; } diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index e46d16fa55..2aff7f790a 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -42,7 +42,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.173 2006/07/14 14:52:25 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.174 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1225,6 +1225,7 @@ write_syslog(int level, const char *line) while (len > 0) { char buf[PG_SYSLOG_LIMIT + 1]; + const char *nlpos; int buflen; int i; @@ -1236,12 +1237,15 @@ write_syslog(int level, const char *line) continue; } - strncpy(buf, line, PG_SYSLOG_LIMIT); - buf[PG_SYSLOG_LIMIT] = '\0'; - if (strchr(buf, '\n') != NULL) - *strchr(buf, '\n') = '\0'; - - buflen = strlen(buf); + /* copy one line, or as much as will fit, to buf */ + nlpos = strchr(line, '\n'); + if (nlpos != NULL) + buflen = nlpos - line; + else + buflen = len; + buflen = Min(buflen, PG_SYSLOG_LIMIT); + memcpy(buf, line, buflen); + buf[buflen] = '\0'; /* trim to multibyte letter boundary */ buflen = pg_mbcliplen(buf, buflen, buflen); diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index b95180d17e..b12674026e 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.89 2006/08/16 04:32:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.90 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -594,7 +594,6 @@ find_rendezvous_variable(const char *varName) { static HTAB *rendezvousHash = NULL; - char key[NAMEDATALEN]; rendezvousHashEntry *hentry; bool found; @@ -612,12 +611,9 @@ find_rendezvous_variable(const char *varName) HASH_ELEM); } - /* Turn the varName into a fixed-size string */ - StrNCpy(key, varName, sizeof(key)); - /* Find or create the hashtable entry for this varName */ hentry = (rendezvousHashEntry *) hash_search(rendezvousHash, - key, + varName, HASH_ENTER, &found); diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index b2974da999..aa0a6b11f2 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/hash/dynahash.c,v 1.71 2006/08/14 12:39:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/hash/dynahash.c,v 1.72 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -209,6 +209,20 @@ DynaHashAlloc(Size size) } +/* + * HashCompareFunc for string keys + * + * Because we copy keys with strlcpy(), they will be truncated at keysize-1 + * bytes, so we can only compare that many ... hence strncmp is almost but + * not quite the right thing. + */ +static int +string_compare(const char *key1, const char *key2, Size keysize) +{ + return strncmp(key1, key2, keysize - 1); +} + + /************************** CREATE ROUTINES **********************/ /* @@ -273,24 +287,24 @@ hash_create(const char *tabname, long nelem, HASHCTL *info, int flags) hashp->hash = string_hash; /* default hash function */ /* - * If you don't specify a match function, it defaults to strncmp() if you - * used string_hash (either explicitly or by default) and to memcmp() - * otherwise. (Prior to PostgreSQL 7.4, memcmp() was always used.) + * If you don't specify a match function, it defaults to string_compare + * if you used string_hash (either explicitly or by default) and to memcmp + * otherwise. (Prior to PostgreSQL 7.4, memcmp was always used.) */ if (flags & HASH_COMPARE) hashp->match = info->match; else if (hashp->hash == string_hash) - hashp->match = (HashCompareFunc) strncmp; + hashp->match = (HashCompareFunc) string_compare; else hashp->match = memcmp; /* - * Similarly, the key-copying function defaults to strncpy() or memcpy(). + * Similarly, the key-copying function defaults to strlcpy or memcpy. */ if (flags & HASH_KEYCOPY) hashp->keycopy = info->keycopy; else if (hashp->hash == string_hash) - hashp->keycopy = (HashCopyFunc) strncpy; + hashp->keycopy = (HashCopyFunc) strlcpy; else hashp->keycopy = memcpy; diff --git a/src/backend/utils/hash/hashfn.c b/src/backend/utils/hash/hashfn.c index ed0826e8e5..af528881ef 100644 --- a/src/backend/utils/hash/hashfn.c +++ b/src/backend/utils/hash/hashfn.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/hash/hashfn.c,v 1.27 2006/07/14 14:52:25 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/hash/hashfn.c,v 1.28 2006/09/27 18:40:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,8 +27,16 @@ uint32 string_hash(const void *key, Size keysize) { + /* + * If the string exceeds keysize-1 bytes, we want to hash only that many, + * because when it is copied into the hash table it will be truncated at + * that length. + */ + Size s_len = strlen((const char *) key); + + s_len = Min(s_len, keysize-1); return DatumGetUInt32(hash_any((const unsigned char *) key, - (int) strlen((const char *) key))); + (int) s_len)); } /* diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c index d23aa563f7..f6c4c588b2 100644 --- a/src/backend/utils/misc/ps_status.c +++ b/src/backend/utils/misc/ps_status.c @@ -5,7 +5,7 @@ * to contain some useful information. Mechanism differs wildly across * platforms. * - * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.31 2006/06/27 22:16:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.32 2006/09/27 18:40:10 tgl Exp $ * * Copyright (c) 2000-2006, PostgreSQL Global Development Group * various details abducted from various places @@ -300,7 +300,7 @@ set_ps_display(const char *activity, bool force) #endif /* Update ps_buffer to contain both fixed part and activity */ - StrNCpy(ps_buffer + ps_buffer_fixed_size, activity, + strlcpy(ps_buffer + ps_buffer_fixed_size, activity, ps_buffer_size - ps_buffer_fixed_size); /* Transmit new setting to kernel, if necessary */ diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index e29ffb53c9..883f075eec 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -12,7 +12,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.94 2006/09/07 22:52:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.95 2006/09/27 18:40:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,12 +54,10 @@ static HTAB *PortalHashTable = NULL; #define PortalHashTableLookup(NAME, PORTAL) \ do { \ - PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \ + PortalHashEnt *hentry; \ \ - MemSet(key, 0, MAX_PORTALNAME_LEN); \ - StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ - key, HASH_FIND, NULL); \ + (NAME), HASH_FIND, NULL); \ if (hentry) \ PORTAL = hentry->portal; \ else \ @@ -68,12 +66,10 @@ do { \ #define PortalHashTableInsert(PORTAL, NAME) \ do { \ - PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \ + PortalHashEnt *hentry; bool found; \ \ - MemSet(key, 0, MAX_PORTALNAME_LEN); \ - StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ - key, HASH_ENTER, &found); \ + (NAME), HASH_ENTER, &found); \ if (found) \ elog(ERROR, "duplicate portal name"); \ hentry->portal = PORTAL; \ @@ -83,12 +79,10 @@ do { \ #define PortalHashTableDelete(PORTAL) \ do { \ - PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \ + PortalHashEnt *hentry; \ \ - MemSet(key, 0, MAX_PORTALNAME_LEN); \ - StrNCpy(key, PORTAL->name, MAX_PORTALNAME_LEN); \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ - key, HASH_REMOVE, NULL); \ + PORTAL->name, HASH_REMOVE, NULL); \ if (hentry == NULL) \ elog(WARNING, "trying to delete portal name that does not exist"); \ } while(0) diff --git a/src/port/path.c b/src/port/path.c index 4acb8046bf..a7d5ec7c45 100644 --- a/src/port/path.c +++ b/src/port/path.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/path.c,v 1.68 2006/09/22 21:39:58 tgl Exp $ + * $PostgreSQL: pgsql/src/port/path.c,v 1.69 2006/09/27 18:40:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -174,7 +174,7 @@ join_path_components(char *ret_path, const char *head, const char *tail) { if (ret_path != head) - StrNCpy(ret_path, head, MAXPGPATH); + strlcpy(ret_path, head, MAXPGPATH); /* * Remove any leading "." and ".." in the tail component, adjusting head @@ -493,7 +493,7 @@ make_relative_path(char *ret_path, const char *target_path, * Set up my_exec_path without the actual executable name, and * canonicalize to simplify comparison to bin_path. */ - StrNCpy(ret_path, my_exec_path, MAXPGPATH); + strlcpy(ret_path, my_exec_path, MAXPGPATH); trim_directory(ret_path); /* remove my executable name */ canonicalize_path(ret_path); @@ -513,7 +513,7 @@ make_relative_path(char *ret_path, const char *target_path, } no_match: - StrNCpy(ret_path, target_path, MAXPGPATH); + strlcpy(ret_path, target_path, MAXPGPATH); canonicalize_path(ret_path); } @@ -625,7 +625,7 @@ get_home_path(char *ret_path) if (pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) != 0) return false; - StrNCpy(ret_path, pwd->pw_dir, MAXPGPATH); + strlcpy(ret_path, pwd->pw_dir, MAXPGPATH); return true; #else char tmppath[MAX_PATH]; diff --git a/src/port/thread.c b/src/port/thread.c index 04f42f55b2..74e6508c36 100644 --- a/src/port/thread.c +++ b/src/port/thread.c @@ -7,7 +7,7 @@ * * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/port/thread.c,v 1.34 2006/07/06 02:12:32 momjian Exp $ + * $PostgreSQL: pgsql/src/port/thread.c,v 1.35 2006/09/27 18:40:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -81,7 +81,7 @@ pqStrerror(int errnum, char *strerrbuf, size_t buflen) #endif #else /* no strerror_r() available, just use strerror */ - StrNCpy(strerrbuf, strerror(errnum), buflen); + strlcpy(strerrbuf, strerror(errnum), buflen); return strerrbuf; #endif