mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
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.
This commit is contained in:
@ -24,7 +24,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.137 2006/09/03 03:19:44 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.138 2006/09/22 21:39:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -145,6 +145,9 @@ static unsigned char unescape_single_char(unsigned char c);
|
||||
* did not end with a newline.
|
||||
*
|
||||
* XXX perhaps \f (formfeed) should be treated as a newline as well?
|
||||
*
|
||||
* XXX if you change the set of whitespace characters, fix scanner_isspace()
|
||||
* to agree, and see also the plpgsql lexer.
|
||||
*/
|
||||
|
||||
space [ \t\n\r\f]
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scansup.c,v 1.33 2006/07/14 14:52:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scansup.c,v 1.34 2006/09/22 21:39:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -183,3 +183,26 @@ truncate_identifier(char *ident, int len, bool warn)
|
||||
ident[len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* scanner_isspace() --- return TRUE if flex scanner considers char whitespace
|
||||
*
|
||||
* This should be used instead of the potentially locale-dependent isspace()
|
||||
* function when it's important to match the lexer's behavior.
|
||||
*
|
||||
* In principle we might need similar functions for isalnum etc, but for the
|
||||
* moment only isspace seems needed.
|
||||
*/
|
||||
bool
|
||||
scanner_isspace(char ch)
|
||||
{
|
||||
/* This must match scan.l's list of {space} characters */
|
||||
/* and plpgsql's scan.l as well */
|
||||
if (ch == ' ' ||
|
||||
ch == '\t' ||
|
||||
ch == '\n' ||
|
||||
ch == '\r' ||
|
||||
ch == '\f')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.351 2006/09/22 17:41:21 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.352 2006/09/22 21:39:57 tgl Exp $
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
@ -6155,7 +6155,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
|
||||
initStringInfo(&buf);
|
||||
while ((c = *cp++) != 0)
|
||||
{
|
||||
if (isspace(c))
|
||||
if (isspace((unsigned char) c))
|
||||
{
|
||||
if (symLen > 0)
|
||||
hasSpaceAfterToken = true;
|
||||
@ -6173,7 +6173,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasSpaceAfterToken || !isalnum(c))
|
||||
if (hasSpaceAfterToken || !isalnum((unsigned char) c))
|
||||
{
|
||||
/*
|
||||
* Syntax error due to token following space after token or non
|
||||
|
@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.447 2006/08/21 00:57:25 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.448 2006/09/22 21:39:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -367,10 +367,10 @@ main(int argc, char **argv)
|
||||
|
||||
new_obj_name->next = NULL;
|
||||
new_obj_name->name = strdup(optarg);
|
||||
new_obj_name->is_include = islower(c) ? true : false;
|
||||
new_obj_name->is_include = islower((unsigned char) c) ? true : false;
|
||||
|
||||
/* add new entry to the proper list */
|
||||
if (tolower(c) == 'n')
|
||||
if (tolower((unsigned char) c) == 'n')
|
||||
{
|
||||
if (!schemaList_tail)
|
||||
schemaList_tail = schemaList = new_obj_name;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.154 2006/07/14 14:52:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.155 2006/09/22 21:39:57 tgl Exp $
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
@ -1090,8 +1090,8 @@ psql_completion(char *text, int start, int end)
|
||||
/* Complete "AS ON <sth with a 'T' :)>" with a "TO" */
|
||||
else if (pg_strcasecmp(prev3_wd, "AS") == 0 &&
|
||||
pg_strcasecmp(prev2_wd, "ON") == 0 &&
|
||||
(toupper((unsigned char) prev_wd[4]) == 'T' ||
|
||||
toupper((unsigned char) prev_wd[5]) == 'T'))
|
||||
(pg_toupper((unsigned char) prev_wd[4]) == 'T' ||
|
||||
pg_toupper((unsigned char) prev_wd[5]) == 'T'))
|
||||
COMPLETE_WITH_CONST("TO");
|
||||
/* Complete "AS ON <sth> TO" with a table name */
|
||||
else if (pg_strcasecmp(prev4_wd, "AS") == 0 &&
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/parser/scansup.h,v 1.19 2006/03/05 15:58:58 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/parser/scansup.h,v 1.20 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -22,4 +22,6 @@ extern char *downcase_truncate_identifier(const char *ident, int len,
|
||||
|
||||
extern void truncate_identifier(char *ident, int len, bool warn);
|
||||
|
||||
extern bool scanner_isspace(char ch);
|
||||
|
||||
#endif /* SCANSUP_H */
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/port.h,v 1.98 2006/09/11 20:10:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/port.h,v 1.99 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -59,7 +59,7 @@ extern void get_parent_directory(char *path);
|
||||
( \
|
||||
((filename)[0] == '/') || \
|
||||
(filename)[0] == '\\' || \
|
||||
(isalpha((filename)[0]) && (filename)[1] == ':' && \
|
||||
(isalpha((unsigned char) ((filename)[0])) && (filename)[1] == ':' && \
|
||||
((filename)[2] == '\\' || (filename)[2] == '/')) \
|
||||
)
|
||||
#endif
|
||||
|
@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.149 2006/08/18 15:59:35 meskes Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.150 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -47,6 +47,7 @@ static void addlit(char *ytext, int yleng);
|
||||
static void addlitchar (unsigned char);
|
||||
static void parse_include (void);
|
||||
static void check_escape_warning(void);
|
||||
static bool ecpg_isspace(char ch);
|
||||
|
||||
char *token_start;
|
||||
int state_before;
|
||||
@ -245,6 +246,9 @@ param \${integer}
|
||||
* did not end with a newline.
|
||||
*
|
||||
* XXX perhaps \f (formfeed) should be treated as a newline as well?
|
||||
*
|
||||
* XXX if you change the set of whitespace characters, fix ecpg_isspace()
|
||||
* to agree.
|
||||
*/
|
||||
|
||||
ccomment "//".*\n
|
||||
@ -872,7 +876,7 @@ cppline {space}*#(.*\\{space})*.*{newline}
|
||||
* contains at least one non-space character plus the ";"
|
||||
*/
|
||||
for (i = strlen(yytext)-2;
|
||||
i > 0 && isspace((unsigned char) yytext[i]);
|
||||
i > 0 && ecpg_isspace(yytext[i]);
|
||||
i-- )
|
||||
;
|
||||
yytext[i+1] = '\0';
|
||||
@ -1060,7 +1064,7 @@ cppline {space}*#(.*\\{space})*.*{newline}
|
||||
* contains at least one non-space character plus the ";"
|
||||
*/
|
||||
for (i = strlen(yytext)-2;
|
||||
i > 0 && isspace((unsigned char) yytext[i]);
|
||||
i > 0 && ecpg_isspace(yytext[i]);
|
||||
i-- )
|
||||
;
|
||||
yytext[i+1] = '\0';
|
||||
@ -1252,7 +1256,7 @@ parse_include(void)
|
||||
* yytext contains at least one non-space character plus the ";"
|
||||
*/
|
||||
for (i = strlen(yytext)-2;
|
||||
i > 0 && isspace((unsigned char) yytext[i]);
|
||||
i > 0 && ecpg_isspace(yytext[i]);
|
||||
i--)
|
||||
;
|
||||
|
||||
@ -1328,3 +1332,18 @@ check_escape_warning(void)
|
||||
mmerror (PARSE_ERROR, ET_WARNING, "nonstandard use of escape in a string literal");
|
||||
warn_on_first_escape = false; /* warn only once per string */
|
||||
}
|
||||
|
||||
/*
|
||||
* ecpg_isspace() --- return TRUE if flex scanner considers char whitespace
|
||||
*/
|
||||
static bool
|
||||
ecpg_isspace(char ch)
|
||||
{
|
||||
if (ch == ' ' ||
|
||||
ch == '\t' ||
|
||||
ch == '\n' ||
|
||||
ch == '\r' ||
|
||||
ch == '\f')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.119 2006/07/14 14:52:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.120 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -89,7 +89,7 @@ pg_an_to_ln(char *aname)
|
||||
*p = '\0';
|
||||
#ifdef WIN32
|
||||
for (p = aname; *p; p++)
|
||||
*p = pg_tolower(*p);
|
||||
*p = pg_tolower((unsigned char) *p);
|
||||
#endif
|
||||
|
||||
return aname;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.178 2006/09/06 20:40:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.179 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,6 +26,7 @@
|
||||
#include "funcapi.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/scansup.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
@ -2527,7 +2528,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
|
||||
char *ptr;
|
||||
|
||||
for (ptr = querystr; *ptr; ptr++)
|
||||
if (!isspace((unsigned char) *ptr))
|
||||
if (!scanner_isspace(*ptr))
|
||||
break;
|
||||
if (*ptr == 'S' || *ptr == 's')
|
||||
ereport(ERROR,
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.54 2006/08/14 21:14:41 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.55 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -381,7 +381,7 @@ plpgsql_convert_ident(const char *s, char **output, int numidents)
|
||||
/* Normal identifier: extends till dot or whitespace */
|
||||
const char *thisstart = s;
|
||||
|
||||
while (*s && *s != '.' && !isspace((unsigned char) *s))
|
||||
while (*s && *s != '.' && !scanner_isspace(*s))
|
||||
s++;
|
||||
/* Downcase and truncate to NAMEDATALEN */
|
||||
curident = downcase_truncate_identifier(thisstart, s - thisstart,
|
||||
@ -400,11 +400,11 @@ plpgsql_convert_ident(const char *s, char **output, int numidents)
|
||||
/* If not done, skip whitespace, dot, whitespace */
|
||||
if (*s)
|
||||
{
|
||||
while (*s && isspace((unsigned char) *s))
|
||||
while (*s && scanner_isspace(*s))
|
||||
s++;
|
||||
if (*s++ != '.')
|
||||
elog(ERROR, "expected dot between identifiers: %s", sstart);
|
||||
while (*s && isspace((unsigned char) *s))
|
||||
while (*s && scanner_isspace(*s))
|
||||
s++;
|
||||
if (*s == '\0')
|
||||
elog(ERROR, "expected another identifier: %s", sstart);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/port/path.c,v 1.67 2006/09/11 20:10:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/port/path.c,v 1.68 2006/09/22 21:39:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -69,7 +69,7 @@ skip_drive(const char *path)
|
||||
while (*path && !IS_DIR_SEP(*path))
|
||||
path++;
|
||||
}
|
||||
else if (isalpha(path[0]) && path[1] == ':')
|
||||
else if (isalpha((unsigned char) path[0]) && path[1] == ':')
|
||||
{
|
||||
path += 2;
|
||||
}
|
||||
|
Reference in New Issue
Block a user