From bcf4d35699fdbd43c5226be5ff2a62b5461813ff Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 31 Oct 2003 17:43:10 +0000 Subject: [PATCH] Minor cleanup of PQunescapeBytea(). Avoid unportable assumptions about behavior of malloc and realloc when request size is 0. Fix escape sequence recognizer so that only valid 3-digit octal sequences are treated as escape sequences ... isdigit() is not a correct test. --- src/interfaces/libpq/fe-exec.c | 55 +++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index 1967d7429b..d25943ee11 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.152 2003/10/19 21:36:41 tgl Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.153 2003/10/31 17:43:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2326,21 +2326,21 @@ PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen) return result; } -#define VAL(CH) ((CH) - '0') +#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3') +#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7') +#define OCTVAL(CH) ((CH) - '0') /* * PQunescapeBytea - converts the null terminated string representation * of a bytea, strtext, into binary, filling a buffer. It returns a - * pointer to the buffer which is NULL on error, and the size of the + * pointer to the buffer (or NULL on error), and the size of the * buffer in retbuflen. The pointer may subsequently be used as an * argument to the function free(3). It is the reverse of PQescapeBytea. * * The following transformations are made: - * \' == ASCII 39 == ' * \\ == ASCII 92 == \ * \ooo == a byte whose value = ooo (ooo is an octal number) * \x == x (x is any character not matched by the above transformations) - * */ unsigned char * PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) @@ -2349,21 +2349,22 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) buflen; unsigned char *buffer, *tmpbuf; - int i, - j, - byte; + size_t i, + j; if (strtext == NULL) return NULL; - strtextlen = strlen(strtext); /* will shrink, also we discover - * if strtext isn't NULL - * terminated */ - buffer = (unsigned char *) malloc(strtextlen); + strtextlen = strlen(strtext); + /* + * Length of input is max length of output, but add one to avoid + * unportable malloc(0) if input is zero-length. + */ + buffer = (unsigned char *) malloc(strtextlen + 1); if (buffer == NULL) return NULL; - for (i = j = buflen = 0; i < (int)strtextlen;) + for (i = j = 0; i < strtextlen; ) { switch (strtext[i]) { @@ -2373,26 +2374,38 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) buffer[j++] = strtext[i++]; else { - if ((isdigit(strtext[i])) && - (isdigit(strtext[i + 1])) && - (isdigit(strtext[i + 2]))) + if ((ISFIRSTOCTDIGIT(strtext[i])) && + (ISOCTDIGIT(strtext[i + 1])) && + (ISOCTDIGIT(strtext[i + 2]))) { - byte = VAL(strtext[i++]); - byte = (byte << 3) + VAL(strtext[i++]); - buffer[j++] = (byte << 3) + VAL(strtext[i++]); + int byte; + + byte = OCTVAL(strtext[i++]); + byte = (byte << 3) + OCTVAL(strtext[i++]); + byte = (byte << 3) + OCTVAL(strtext[i++]); + buffer[j++] = byte; } } + /* + * Note: if we see '\' followed by something that isn't + * a recognized escape sequence, we loop around having + * done nothing except advance i. Therefore the something + * will be emitted as ordinary data on the next cycle. + * Corner case: '\' at end of string will just be discarded. + */ break; default: buffer[j++] = strtext[i++]; + break; } } - buflen = j; /* buflen is the length of the unquoted + buflen = j; /* buflen is the length of the dequoted * data */ /* Shrink the buffer to be no larger than necessary */ - tmpbuf = realloc(buffer, buflen); + /* +1 avoids unportable behavior when buflen==0 */ + tmpbuf = realloc(buffer, buflen + 1); /* It would only be a very brain-dead realloc that could fail, but... */ if (!tmpbuf)