diff --git a/contrib/miscutil/misc_utils.c b/contrib/miscutil/misc_utils.c
index f5a98683280e3cfd9b1251662315ef8eb1150d2e..e7949d32aa6da3d591fc80a074752cbe726b95c6 100644
--- a/contrib/miscutil/misc_utils.c
+++ b/contrib/miscutil/misc_utils.c
@@ -99,9 +99,9 @@ active_listeners(text *relname)
 
 	if (relname && (VARSIZE(relname) > VARHDRSZ))
 	{
+		MemSet(listen_name, 0, NAMEDATALEN);
 		len = MIN(VARSIZE(relname) - VARHDRSZ, NAMEDATALEN - 1);
-		strncpy(listen_name, VARDATA(relname), len);
-		listen_name[len] = '\0';
+		memcpy(listen_name, VARDATA(relname), len);
 		ScanKeyEntryInitialize(&key, 0,
 							   Anum_pg_listener_relname,
 							   F_NAMEEQ,
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 91769120f959edfa2a3972e0d0c75e8b119c2d85..929ddad5aa85cff56afc401fab53bf4682caa377 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.48 2000/07/03 23:09:37 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.49 2000/07/07 21:12:53 tgl Exp $
  *
  * NOTES
  *	  This should be moved to a more appropriate place.  It is here
@@ -379,26 +379,23 @@ lo_import(PG_FUNCTION_ARGS)
 	/*
 	 * open the file to be read in
 	 */
-	nbytes = VARSIZE(filename) - VARHDRSZ + 1;
-	if (nbytes > FNAME_BUFSIZE)
-		nbytes = FNAME_BUFSIZE;
-	StrNCpy(fnamebuf, VARDATA(filename), nbytes);
+	nbytes = VARSIZE(filename) - VARHDRSZ;
+	if (nbytes >= FNAME_BUFSIZE)
+		nbytes = FNAME_BUFSIZE-1;
+	memcpy(fnamebuf, VARDATA(filename), nbytes);
+	fnamebuf[nbytes] = '\0';
 	fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
 	if (fd < 0)
-	{							/* error */
 		elog(ERROR, "lo_import: can't open unix file \"%s\": %m",
 			 fnamebuf);
-	}
 
 	/*
 	 * create an inversion "object"
 	 */
 	lobj = inv_create(INV_READ | INV_WRITE);
 	if (lobj == NULL)
-	{
 		elog(ERROR, "lo_import: can't create inv object for \"%s\"",
 			 fnamebuf);
-	}
 
 	/*
 	 * the oid for the large object is just the oid of the relation
@@ -461,18 +458,17 @@ lo_export(PG_FUNCTION_ARGS)
 	 * 022.  This code used to drop it all the way to 0, but creating
 	 * world-writable export files doesn't seem wise.
 	 */
-	nbytes = VARSIZE(filename) - VARHDRSZ + 1;
-	if (nbytes > FNAME_BUFSIZE)
-		nbytes = FNAME_BUFSIZE;
-	StrNCpy(fnamebuf, VARDATA(filename), nbytes);
+	nbytes = VARSIZE(filename) - VARHDRSZ;
+	if (nbytes >= FNAME_BUFSIZE)
+		nbytes = FNAME_BUFSIZE-1;
+	memcpy(fnamebuf, VARDATA(filename), nbytes);
+	fnamebuf[nbytes] = '\0';
 	oumask = umask((mode_t) 0022);
 	fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
 	umask(oumask);
 	if (fd < 0)
-	{							/* error */
 		elog(ERROR, "lo_export: can't open unix file \"%s\": %m",
 			 fnamebuf);
-	}
 
 	/*
 	 * read in from the Unix file and write to the inversion file
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
index 78745d50a7f30e362188051402e794d5361ed0b8..474da587792ad32343b1d49fd5d889b979bc451f 100644
--- a/src/backend/libpq/be-pqexec.c
+++ b/src/backend/libpq/be-pqexec.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.35 2000/07/05 23:11:19 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.36 2000/07/07 21:12:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -236,8 +236,8 @@ strmake(char *str, int len)
 	if (len <= 0)
 		len = strlen(str);
 
-	newstr = (char *) palloc((unsigned) len + 1);
-	StrNCpy(newstr, str, len + 1);
+	newstr = (char *) palloc(len + 1);
+	memcpy(newstr, str, len);
 	newstr[len] = (char) 0;
 	return newstr;
 }
diff --git a/src/backend/port/dynloader/aix.c b/src/backend/port/dynloader/aix.c
index 61705551430cb1d93047cd2186af1bc11ad7cbd8..c6295406e2273ea3ff1cef5af7b6193a024c5c69 100644
--- a/src/backend/port/dynloader/aix.c
+++ b/src/backend/port/dynloader/aix.c
@@ -536,7 +536,8 @@ readExports(ModulePtr mp)
 			 * first SYMNMLEN chars and make sure we have a zero byte at
 			 * the end.
 			 */
-			StrNCpy(tmpsym, ls->l_name, SYMNMLEN + 1);
+			strncpy(tmpsym, ls->l_name, SYMNMLEN);
+			tmpsym[SYMNMLEN] = '\0';
 			symname = tmpsym;
 		}
 		ep->name = strdup(symname);
diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c
index 6fbd95ffe25ac53ce55016e641a0f038e45d7930..5a7b84733924a1ea403c9a255917fa5cf7dd2157 100644
--- a/src/backend/utils/adt/like.c
+++ b/src/backend/utils/adt/like.c
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	$Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.36 2000/07/06 05:48:11 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.37 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,8 @@ fixedlen_like(char *s, text *p, int charlen)
 	(void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
 #else
 	sterm = (char *) palloc(charlen + 1);
-	StrNCpy(sterm, s, charlen + 1);
+	memcpy(sterm, s, charlen);
+	sterm[charlen] = '\0';
 #endif
 
 	/*
diff --git a/src/backend/utils/adt/not_in.c b/src/backend/utils/adt/not_in.c
index ec3b82c502a0efa6369b7ddf19bb54c990bd0ed5..55182f1bf94436886020d02fabb112a61bc18bc9 100644
--- a/src/backend/utils/adt/not_in.c
+++ b/src/backend/utils/adt/not_in.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.23 2000/06/09 01:11:09 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.24 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,10 +52,12 @@ int4notin(PG_FUNCTION_ARGS)
 	char		my_copy[NAMEDATALEN * 2 + 2];
 	Datum		value;
 
-	strlength = VARSIZE(relation_and_attr) - VARHDRSZ + 1;
-	if (strlength > sizeof(my_copy))
-		strlength = sizeof(my_copy);
-	StrNCpy(my_copy, VARDATA(relation_and_attr), strlength);
+	/* make a null-terminated copy of text */
+	strlength = VARSIZE(relation_and_attr) - VARHDRSZ;
+	if (strlength >= sizeof(my_copy))
+		strlength = sizeof(my_copy)-1;
+	memcpy(my_copy, VARDATA(relation_and_attr), strlength);
+	my_copy[strlength] = '\0';
 
 	relation = (char *) strtok(my_copy, ".");
 	attribute = (char *) strtok(NULL, ".");
diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c
index dcf158c7a28ee8f8b01fe5fde4bc760410883c9e..5e9a91dbf48a4abd20ff1ef3988cfbf34d756afa 100644
--- a/src/backend/utils/adt/regexp.c
+++ b/src/backend/utils/adt/regexp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.32 2000/07/06 05:48:11 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.33 2000/07/07 21:12:50 tgl Exp $
  *
  *		Alistair Crooks added the code for the regex caching
  *		agc - cached the regular expressions used - there's a good chance
@@ -164,7 +164,8 @@ fixedlen_regexeq(char *s, text *p, int charlen, int cflags)
 
 	/* be sure sterm is null-terminated */
 	sterm = (char *) palloc(charlen + 1);
-	StrNCpy(sterm, s, charlen + 1);
+	memcpy(sterm, s, charlen);
+	sterm[charlen] = '\0';
 
 	result = RE_compile_and_execute(p, sterm, cflags);
 
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 6f17cb589ae60f59a8b19c50a59299ae0ebca655..58b24f339e185209d632ed174db6f3d106780d34 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.67 2000/07/03 23:09:53 wieck Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.68 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,9 +115,11 @@ bpcharout(PG_FUNCTION_ARGS)
 	char	   *result;
 	int			len;
 
+	/* copy and add null term */
 	len = VARSIZE(s) - VARHDRSZ;
 	result = (char *) palloc(len + 1);
-	StrNCpy(result, VARDATA(s), len + 1); /* copy and add null term */
+	memcpy(result, VARDATA(s), len);
+	result[len] = '\0';
 
 #ifdef CYR_RECODE
 	convertstr(result, len, 1);
@@ -268,8 +270,8 @@ bpchar_name(char *s)
 		return NULL;
 
 	len = VARSIZE(s) - VARHDRSZ;
-	if (len > NAMEDATALEN)
-		len = NAMEDATALEN;
+	if (len >= NAMEDATALEN)
+		len = NAMEDATALEN-1;
 
 	while (len > 0)
 	{
@@ -284,7 +286,7 @@ bpchar_name(char *s)
 #endif
 
 	result = (NameData *) palloc(NAMEDATALEN);
-	StrNCpy(NameStr(*result), VARDATA(s), NAMEDATALEN);
+	memcpy(NameStr(*result), VARDATA(s), len);
 
 	/* now null pad to full length... */
 	while (len < NAMEDATALEN)
@@ -316,7 +318,7 @@ name_bpchar(NameData *s)
 #endif
 
 	result = (char *) palloc(VARHDRSZ + len);
-	strncpy(VARDATA(result), NameStr(*s), len);
+	memcpy(VARDATA(result), NameStr(*s), len);
 	VARATT_SIZEP(result) = len + VARHDRSZ;
 
 	return result;
@@ -365,9 +367,11 @@ varcharout(PG_FUNCTION_ARGS)
 	char	   *result;
 	int			len;
 
+	/* copy and add null term */
 	len = VARSIZE(s) - VARHDRSZ;
 	result = (char *) palloc(len + 1);
-	StrNCpy(result, VARDATA(s), len + 1); /* copy and add null term */
+	memcpy(result, VARDATA(s), len);
+	result[len] = '\0';
 
 #ifdef CYR_RECODE
 	convertstr(result, len, 1);
diff --git a/src/include/c.h b/src/include/c.h
index 65ff45aa9234fd7e6d3184f5bbc83462afaa0b79..250a8c6db164f98928b1928431201bcce6ca79df 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: c.h,v 1.75 2000/07/06 21:33:44 petere Exp $
+ * $Id: c.h,v 1.76 2000/07/07 21:12:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -781,11 +781,19 @@ extern int	assertTest(int val);
 
 /*
  * 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).
+ *	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 \