Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit beca984

Browse files
committed
Fix bugs in plpgsql and ecpg caused by assuming that isspace() would only
return true for exactly the characters treated as whitespace by their flex scanners. Per report from Victor Snezhko and subsequent investigation. Also fix a passel of unsafe usages of <ctype.h> functions, that is, ye olde char-vs-unsigned-char issue. I won't miss <ctype.h> when we are finally able to stop using it.
1 parent 6d0efd3 commit beca984

File tree

19 files changed

+112
-61
lines changed

19 files changed

+112
-61
lines changed

contrib/fuzzystrmatch/dmetaphone.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* This is a port of the Double Metaphone algorithm for use in PostgreSQL.
33
*
4-
* $PostgreSQL: pgsql/contrib/fuzzystrmatch/dmetaphone.c,v 1.9 2006/07/16 02:44:00 tgl Exp $
4+
* $PostgreSQL: pgsql/contrib/fuzzystrmatch/dmetaphone.c,v 1.10 2006/09/22 21:39:56 tgl Exp $
55
*
66
* Double Metaphone computes 2 "sounds like" strings - a primary and an
77
* alternate. In most cases they are the same, but for foreign names
@@ -318,7 +318,7 @@ MakeUpper(metastring * s)
318318
char *i;
319319

320320
for (i = s->str; *i; i++)
321-
*i = toupper(*i);
321+
*i = toupper((unsigned char) *i);
322322
}
323323

324324

contrib/hstore/hstore_io.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
5151
elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), (int4)(state->ptr-state->begin));
5252
} else if ( *(state->ptr) == '\\' ) {
5353
st = GV_WAITESCIN;
54-
} else if ( !isspace(*(state->ptr)) ) {
54+
} else if ( !isspace((unsigned char) *(state->ptr)) ) {
5555
*(state->cur) = *(state->ptr);
5656
state->cur++;
5757
st = GV_INVAL;
@@ -65,7 +65,7 @@ get_val( HSParser *state, bool ignoreeq, bool *escaped ) {
6565
} else if ( *(state->ptr) == ',' && ignoreeq ) {
6666
state->ptr--;
6767
return true;
68-
} else if ( isspace(*(state->ptr)) ) {
68+
} else if ( isspace((unsigned char) *(state->ptr)) ) {
6969
return true;
7070
} else if ( *(state->ptr) == '\0' ) {
7171
state->ptr--;
@@ -146,7 +146,7 @@ parse_hstore( HSParser *state ) {
146146
st = WGT;
147147
} else if ( *(state->ptr) == '\0' ) {
148148
elog(ERROR,"Unexpectd end of string");
149-
} else if (!isspace(*(state->ptr))) {
149+
} else if (!isspace((unsigned char) *(state->ptr))) {
150150
elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), (int4)(state->ptr-state->begin));
151151
}
152152
} else if ( st == WGT ) {
@@ -177,7 +177,7 @@ parse_hstore( HSParser *state ) {
177177
st = WKEY;
178178
} else if ( *(state->ptr) == '\0' ) {
179179
return;
180-
} else if (!isspace(*(state->ptr))) {
180+
} else if (!isspace((unsigned char) *(state->ptr))) {
181181
elog(ERROR,"Syntax error near '%c' at postion %d", *(state->ptr), (int4)(state->ptr-state->begin));
182182
}
183183
} else

contrib/isn/isn.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.2 2006/09/10 20:45:17 tgl Exp $
10+
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.3 2006/09/22 21:39:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -72,13 +72,16 @@ bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2])
7272
aux2 = TABLE[i][1];
7373

7474
/* must always start with a digit: */
75-
if(!isdigit(*aux1) || !isdigit(*aux2)) goto invalidtable;
75+
if (!isdigit((unsigned char) *aux1) || !isdigit((unsigned char) *aux2))
76+
goto invalidtable;
7677
a = *aux1 - '0';
7778
b = *aux2 - '0';
7879

7980
/* must always have the same format and length: */
8081
while(*aux1 && *aux2) {
81-
if(!(isdigit(*aux1) && isdigit(*aux2)) && (*aux1!=*aux2 || *aux1 != '-'))
82+
if (!(isdigit((unsigned char) *aux1) &&
83+
isdigit((unsigned char) *aux2)) &&
84+
(*aux1 != *aux2 || *aux1 != '-'))
8285
goto invalidtable;
8386
aux1++;
8487
aux2++;
@@ -124,7 +127,7 @@ unsigned dehyphenate(char *bufO, char *bufI)
124127
{
125128
unsigned ret = 0;
126129
while(*bufI) {
127-
if(isdigit(*bufI)) {
130+
if(isdigit((unsigned char) *bufI)) {
128131
*bufO++ = *bufI;
129132
ret++;
130133
}
@@ -183,7 +186,7 @@ unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsign
183186

184187
firstdig++, ean_aux1++, ean_aux2++;
185188
if(!(*ean_aux1 && *ean_aux2 && *firstdig)) break;
186-
if(!isdigit(*ean_aux1)) ean_aux1++, ean_aux2++;
189+
if(!isdigit((unsigned char) *ean_aux1)) ean_aux1++, ean_aux2++;
187190
} else {
188191
/* check in what direction we should go and move the pointer accordingly */
189192
if(*firstdig < *ean_aux1 && !ean_in1) upper = search;
@@ -227,7 +230,7 @@ unsigned weight_checkdig(char *isn, unsigned size)
227230
{
228231
unsigned weight = 0;
229232
while(*isn && size>1) {
230-
if(isdigit(*isn)) {
233+
if(isdigit((unsigned char) *isn)) {
231234
weight += size-- * (*isn - '0');
232235
}
233236
isn++;
@@ -254,7 +257,7 @@ unsigned checkdig(char *num, unsigned size)
254257
pos = 1;
255258
}
256259
while(*num && size>1) {
257-
if(isdigit(*num)) {
260+
if(isdigit((unsigned char) *num)) {
258261
if(pos++%2) check3 += *num - '0';
259262
else check += *num - '0';
260263
size--;
@@ -366,7 +369,7 @@ void ean2ISBN(char *isn)
366369
hyphenate(isn, isn+4, NULL, NULL);
367370
check = weight_checkdig(isn, 10);
368371
aux = strchr(isn, '\0');
369-
while(!isdigit(*--aux));
372+
while(!isdigit((unsigned char) *--aux));
370373
if(check == 10) *aux = 'X';
371374
else *aux = check + '0';
372375
}
@@ -411,7 +414,7 @@ ean13 str2ean(const char *num)
411414
{
412415
ean13 ean = 0; /* current ean */
413416
while(*num) {
414-
if(isdigit(*num)) ean = 10 * ean + (*num - '0');
417+
if(isdigit((unsigned char) *num)) ean = 10 * ean + (*num - '0');
415418
num++;
416419
}
417420
return (ean<<1); /* also give room to a flag */
@@ -570,7 +573,7 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
570573
/* recognize and validate the number: */
571574
while(*aux2 && length <= 13) {
572575
last = (*(aux2+1) == '!' || *(aux2+1) == '\0'); /* is the last character */
573-
digit = (isdigit(*aux2)!=0); /* is current character a digit? */
576+
digit = (isdigit((unsigned char) *aux2)!=0); /* is current character a digit? */
574577
if(*aux2=='?' && last) /* automagically calculate check digit if it's '?' */
575578
magic = digit = true;
576579
if(length == 0 && (*aux2=='M' || *aux2=='m')) {
@@ -583,13 +586,13 @@ bool string2ean(const char *str, bool errorOK, ean13 *result,
583586
/* only ISSN can be here */
584587
if(type != INVALID) goto eaninvalid;
585588
type = ISSN;
586-
*aux1++ = toupper(*aux2);
589+
*aux1++ = toupper((unsigned char) *aux2);
587590
length++;
588591
} else if(length == 9 && (digit || *aux2=='X' || *aux2=='x') && last) {
589592
/* only ISBN and ISMN can be here */
590593
if(type != INVALID && type != ISMN) goto eaninvalid;
591594
if(type == INVALID) type = ISBN; /* ISMN must start with 'M' */
592-
*aux1++ = toupper(*aux2);
595+
*aux1++ = toupper((unsigned char) *aux2);
593596
length++;
594597
} else if(length == 11 && digit && last) {
595598
/* only UPC can be here */

contrib/ltree/crc32.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/* Both POSIX and CRC32 checksums */
22

3-
/* $PostgreSQL: pgsql/contrib/ltree/crc32.c,v 1.6 2006/03/11 04:38:29 momjian Exp $ */
3+
/* $PostgreSQL: pgsql/contrib/ltree/crc32.c,v 1.7 2006/09/22 21:39:57 tgl Exp $ */
44

55
#include <sys/types.h>
66
#include <stdio.h>
77
#include <sys/types.h>
88

99
#ifdef LOWER_NODE
1010
#include <ctype.h>
11-
#define TOLOWER(x) tolower(x)
11+
#define TOLOWER(x) tolower((unsigned char) (x))
1212
#else
1313
#define TOLOWER(x) (x)
1414
#endif

contrib/ltree/ltree_io.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* in/out function for ltree and lquery
33
* Teodor Sigaev <teodor@stack.net>
4-
* $PostgreSQL: pgsql/contrib/ltree/ltree_io.c,v 1.12 2006/03/11 04:38:29 momjian Exp $
4+
* $PostgreSQL: pgsql/contrib/ltree/ltree_io.c,v 1.13 2006/09/22 21:39:57 tgl Exp $
55
*/
66

77
#include "ltree.h"
@@ -332,7 +332,7 @@ lquery_in(PG_FUNCTION_ARGS)
332332
{
333333
if (*ptr == ',')
334334
state = LQPRS_WAITSNUM;
335-
else if (isdigit((unsigned int) *ptr))
335+
else if (isdigit((unsigned char) *ptr))
336336
{
337337
curqlevel->low = atoi(ptr);
338338
state = LQPRS_WAITND;
@@ -342,7 +342,7 @@ lquery_in(PG_FUNCTION_ARGS)
342342
}
343343
else if (state == LQPRS_WAITSNUM)
344344
{
345-
if (isdigit((unsigned int) *ptr))
345+
if (isdigit((unsigned char) *ptr))
346346
{
347347
curqlevel->high = atoi(ptr);
348348
state = LQPRS_WAITCLOSE;
@@ -359,7 +359,7 @@ lquery_in(PG_FUNCTION_ARGS)
359359
{
360360
if (*ptr == '}')
361361
state = LQPRS_WAITEND;
362-
else if (!isdigit((unsigned int) *ptr))
362+
else if (!isdigit((unsigned char) *ptr))
363363
UNCHAR;
364364
}
365365
else if (state == LQPRS_WAITND)
@@ -371,7 +371,7 @@ lquery_in(PG_FUNCTION_ARGS)
371371
}
372372
else if (*ptr == ',')
373373
state = LQPRS_WAITSNUM;
374-
else if (!isdigit((unsigned int) *ptr))
374+
else if (!isdigit((unsigned char) *ptr))
375375
UNCHAR;
376376
}
377377
else if (state == LQPRS_WAITEND)

contrib/ltree/ltxtquery_io.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* txtquery io
33
* Teodor Sigaev <teodor@stack.net>
4-
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_io.c,v 1.11 2006/03/11 04:38:29 momjian Exp $
4+
* $PostgreSQL: pgsql/contrib/ltree/ltxtquery_io.c,v 1.12 2006/09/22 21:39:57 tgl Exp $
55
*/
66

77
#include "ltree.h"
@@ -81,7 +81,7 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, uint1
8181
*lenval = 1;
8282
*flag = 0;
8383
}
84-
else if (!isspace((unsigned int) *(state->buf)))
84+
else if (!isspace((unsigned char) *(state->buf)))
8585
ereport(ERROR,
8686
(errcode(ERRCODE_SYNTAX_ERROR),
8787
errmsg("operand syntax error")));

contrib/pgcrypto/imath.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2828
SOFTWARE.
2929
*/
30-
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.c,v 1.4 2006/07/19 17:05:50 neilc Exp $ */
30+
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.c,v 1.5 2006/09/22 21:39:57 tgl Exp $ */
3131

3232
#include "postgres.h"
3333
#include "px.h"
@@ -1799,7 +1799,7 @@ mp_result mp_int_read_cstring(mp_int z, mp_size radix, const char *str, char **e
17991799
return MP_RANGE;
18001800

18011801
/* Skip leading whitespace */
1802-
while(isspace((int)*str))
1802+
while(isspace((unsigned char) *str))
18031803
++str;
18041804

18051805
/* Handle leading sign tag (+/-, positive default) */
@@ -3127,10 +3127,10 @@ static int s_ch2val(char c, int r)
31273127
{
31283128
int out;
31293129

3130-
if(isdigit((int)c))
3130+
if(isdigit((unsigned char)c))
31313131
out = c - '0';
3132-
else if(r > 10 && isalpha((int)c))
3133-
out = toupper(c) - 'A' + 10;
3132+
else if(r > 10 && isalpha((unsigned char) c))
3133+
out = toupper((unsigned char) c) - 'A' + 10;
31343134
else
31353135
return -1;
31363136

@@ -3151,7 +3151,7 @@ static char s_val2ch(int v, int caps)
31513151
char out = (v - 10) + 'a';
31523152

31533153
if(caps)
3154-
return toupper(out);
3154+
return toupper((unsigned char) out);
31553155
else
31563156
return out;
31573157
}

src/backend/parser/scan.l

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* Portions Copyright (c) 1994, Regents of the University of California
2525
*
2626
* IDENTIFICATION
27-
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.137 2006/09/03 03:19:44 momjian Exp $
27+
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.138 2006/09/22 21:39:57 tgl Exp $
2828
*
2929
*-------------------------------------------------------------------------
3030
*/
@@ -145,6 +145,9 @@ static unsigned char unescape_single_char(unsigned char c);
145145
* did not end with a newline.
146146
*
147147
* XXX perhaps \f (formfeed) should be treated as a newline as well?
148+
*
149+
* XXX if you change the set of whitespace characters, fix scanner_isspace()
150+
* to agree, and see also the plpgsql lexer.
148151
*/
149152

150153
space [ \t\n\r\f]

src/backend/parser/scansup.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/parser/scansup.c,v 1.33 2006/07/14 14:52:22 momjian Exp $
12+
* $PostgreSQL: pgsql/src/backend/parser/scansup.c,v 1.34 2006/09/22 21:39:57 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -183,3 +183,26 @@ truncate_identifier(char *ident, int len, bool warn)
183183
ident[len] = '\0';
184184
}
185185
}
186+
187+
/*
188+
* scanner_isspace() --- return TRUE if flex scanner considers char whitespace
189+
*
190+
* This should be used instead of the potentially locale-dependent isspace()
191+
* function when it's important to match the lexer's behavior.
192+
*
193+
* In principle we might need similar functions for isalnum etc, but for the
194+
* moment only isspace seems needed.
195+
*/
196+
bool
197+
scanner_isspace(char ch)
198+
{
199+
/* This must match scan.l's list of {space} characters */
200+
/* and plpgsql's scan.l as well */
201+
if (ch == ' ' ||
202+
ch == '\t' ||
203+
ch == '\n' ||
204+
ch == '\r' ||
205+
ch == '\f')
206+
return true;
207+
return false;
208+
}

src/backend/utils/misc/guc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Written by Peter Eisentraut <peter_e@gmx.net>.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.351 2006/09/22 17:41:21 petere Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.352 2006/09/22 21:39:57 tgl Exp $
1414
*
1515
*--------------------------------------------------------------------
1616
*/
@@ -6155,7 +6155,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
61556155
initStringInfo(&buf);
61566156
while ((c = *cp++) != 0)
61576157
{
6158-
if (isspace(c))
6158+
if (isspace((unsigned char) c))
61596159
{
61606160
if (symLen > 0)
61616161
hasSpaceAfterToken = true;
@@ -6173,7 +6173,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
61736173
continue;
61746174
}
61756175

6176-
if (hasSpaceAfterToken || !isalnum(c))
6176+
if (hasSpaceAfterToken || !isalnum((unsigned char) c))
61776177
{
61786178
/*
61796179
* Syntax error due to token following space after token or non

src/bin/pg_dump/pg_dump.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* by PostgreSQL
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
15+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.448 2006/09/22 21:39:57 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -367,10 +367,10 @@ main(int argc, char **argv)
367367

368368
new_obj_name->next = NULL;
369369
new_obj_name->name = strdup(optarg);
370-
new_obj_name->is_include = islower(c) ? true : false;
370+
new_obj_name->is_include = islower((unsigned char) c) ? true : false;
371371

372372
/* add new entry to the proper list */
373-
if (tolower(c) == 'n')
373+
if (tolower((unsigned char) c) == 'n')
374374
{
375375
if (!schemaList_tail)
376376
schemaList_tail = schemaList = new_obj_name;

0 commit comments

Comments
 (0)