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.
This commit is contained in:
Tom Lane 2003-10-31 17:43:10 +00:00
parent 774f57038a
commit bcf4d35699
1 changed files with 34 additions and 21 deletions

View File

@ -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)