summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2000-07-07 21:12:53 +0000
committerTom Lane2000-07-07 21:12:53 +0000
commit12529a72c5480adbd404bd60cb418fe9d5f3870b (patch)
treecfbb0cff88c60df83dc601ff7b48c5977c49a6bf
parent393ee97077e50fee460f2fc94cc95c63fad91f96 (diff)
Fix misuse of StrNCpy to copy and add null to non-null-terminated data.
Does not work since it fetches one byte beyond the source data, and when the phase of the moon is wrong, the source data is smack up against the end of backend memory and you get SIGSEGV. Don't laugh, this is a fix for an actual user bug report.
-rw-r--r--contrib/miscutil/misc_utils.c4
-rw-r--r--src/backend/libpq/be-fsstubs.c24
-rw-r--r--src/backend/libpq/be-pqexec.c4
-rw-r--r--src/backend/port/dynloader/aix.c3
-rw-r--r--src/backend/utils/adt/like.c3
-rw-r--r--src/backend/utils/adt/not_in.c10
-rw-r--r--src/backend/utils/adt/regexp.c3
-rw-r--r--src/backend/utils/adt/varchar.c16
-rw-r--r--src/include/c.h18
9 files changed, 49 insertions, 36 deletions
diff --git a/contrib/miscutil/misc_utils.c b/contrib/miscutil/misc_utils.c
index f5a9868328..e7949d32aa 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 5032119c0b..db06b37945 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -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 20580898c3..490399c75d 100644
--- a/src/backend/libpq/be-pqexec.c
+++ b/src/backend/libpq/be-pqexec.c
@@ -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 6170555143..c6295406e2 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 c33b8b86b5..a417d2a70f 100644
--- a/src/backend/utils/adt/like.c
+++ b/src/backend/utils/adt/like.c
@@ -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 d3d858a664..2aa803be85 100644
--- a/src/backend/utils/adt/not_in.c
+++ b/src/backend/utils/adt/not_in.c
@@ -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 a8b37a6cd9..4b296c540e 100644
--- a/src/backend/utils/adt/regexp.c
+++ b/src/backend/utils/adt/regexp.c
@@ -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 8e40fdd594..6ee0940d4e 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -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 9d19606ab1..e7ed1b9a35 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -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 \