Commit bcf4d356 authored by Tom Lane's avatar Tom Lane

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.
parent 774f5703
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2326,21 +2326,21 @@ PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen)
return result; 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 * PQunescapeBytea - converts the null terminated string representation
* of a bytea, strtext, into binary, filling a buffer. It returns a * 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 * buffer in retbuflen. The pointer may subsequently be used as an
* argument to the function free(3). It is the reverse of PQescapeBytea. * argument to the function free(3). It is the reverse of PQescapeBytea.
* *
* The following transformations are made: * The following transformations are made:
* \' == ASCII 39 == '
* \\ == ASCII 92 == \ * \\ == ASCII 92 == \
* \ooo == a byte whose value = ooo (ooo is an octal number) * \ooo == a byte whose value = ooo (ooo is an octal number)
* \x == x (x is any character not matched by the above transformations) * \x == x (x is any character not matched by the above transformations)
*
*/ */
unsigned char * unsigned char *
PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
...@@ -2349,21 +2349,22 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) ...@@ -2349,21 +2349,22 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
buflen; buflen;
unsigned char *buffer, unsigned char *buffer,
*tmpbuf; *tmpbuf;
int i, size_t i,
j, j;
byte;
if (strtext == NULL) if (strtext == NULL)
return NULL; return NULL;
strtextlen = strlen(strtext); /* will shrink, also we discover strtextlen = strlen(strtext);
* if strtext isn't NULL /*
* terminated */ * Length of input is max length of output, but add one to avoid
buffer = (unsigned char *) malloc(strtextlen); * unportable malloc(0) if input is zero-length.
*/
buffer = (unsigned char *) malloc(strtextlen + 1);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
for (i = j = buflen = 0; i < (int)strtextlen;) for (i = j = 0; i < strtextlen; )
{ {
switch (strtext[i]) switch (strtext[i])
{ {
...@@ -2373,26 +2374,38 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen) ...@@ -2373,26 +2374,38 @@ PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen)
buffer[j++] = strtext[i++]; buffer[j++] = strtext[i++];
else else
{ {
if ((isdigit(strtext[i])) && if ((ISFIRSTOCTDIGIT(strtext[i])) &&
(isdigit(strtext[i + 1])) && (ISOCTDIGIT(strtext[i + 1])) &&
(isdigit(strtext[i + 2]))) (ISOCTDIGIT(strtext[i + 2])))
{ {
byte = VAL(strtext[i++]); int byte;
byte = (byte << 3) + VAL(strtext[i++]);
buffer[j++] = (byte << 3) + VAL(strtext[i++]); 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; break;
default: default:
buffer[j++] = strtext[i++]; buffer[j++] = strtext[i++];
break;
} }
} }
buflen = j; /* buflen is the length of the unquoted buflen = j; /* buflen is the length of the dequoted
* data */ * data */
/* Shrink the buffer to be no larger than necessary */ /* 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... */ /* It would only be a very brain-dead realloc that could fail, but... */
if (!tmpbuf) if (!tmpbuf)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment