mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
Catch fatal flex errors in the GUC file lexer.
This prevents the postmaster from unexpectedly croaking if postgresql.conf contains something like: include 'invalid_directory_name' Noah Misch. Reviewed by Tom Lane and myself.
This commit is contained in:
parent
754b8140a1
commit
4b496a3583
@ -20,9 +20,14 @@
|
|||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
|
|
||||||
|
|
||||||
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
|
/*
|
||||||
|
* flex emits a yy_fatal_error() function that it calls in response to
|
||||||
|
* critical errors like malloc failure, file I/O errors, and detection of
|
||||||
|
* internal inconsistency. That function prints a message and calls exit().
|
||||||
|
* Mutate it to instead call our handler, which jumps out of the parser.
|
||||||
|
*/
|
||||||
#undef fprintf
|
#undef fprintf
|
||||||
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
|
#define fprintf(file, fmt, msg) GUC_flex_fatal(msg)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GUC_ID = 1,
|
GUC_ID = 1,
|
||||||
@ -37,10 +42,13 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int ConfigFileLineno;
|
static unsigned int ConfigFileLineno;
|
||||||
|
static const char *GUC_flex_fatal_errmsg;
|
||||||
|
static sigjmp_buf *GUC_flex_fatal_jmp;
|
||||||
|
|
||||||
/* flex fails to supply a prototype for yylex, so provide one */
|
/* flex fails to supply a prototype for yylex, so provide one */
|
||||||
int GUC_yylex(void);
|
int GUC_yylex(void);
|
||||||
|
|
||||||
|
static int GUC_flex_fatal(const char *msg);
|
||||||
static char *GUC_scanstr(const char *s);
|
static char *GUC_scanstr(const char *s);
|
||||||
|
|
||||||
%}
|
%}
|
||||||
@ -436,6 +444,22 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flex fatal errors bring us here. Stash the error message and jump back to
|
||||||
|
* ParseConfigFp(). Assume all msg arguments point to string constants; this
|
||||||
|
* holds for flex 2.5.31 (earliest we support) and flex 2.5.35 (latest as of
|
||||||
|
* this writing). Otherwise, we would need to copy the message.
|
||||||
|
*
|
||||||
|
* We return "int" since this takes the place of calls to fprintf().
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
GUC_flex_fatal(const char *msg)
|
||||||
|
{
|
||||||
|
GUC_flex_fatal_errmsg = msg;
|
||||||
|
siglongjmp(*GUC_flex_fatal_jmp, 1);
|
||||||
|
return 0; /* keep compiler quiet */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read and parse a single configuration file. This function recurses
|
* Read and parse a single configuration file. This function recurses
|
||||||
* to handle "include" directives.
|
* to handle "include" directives.
|
||||||
@ -464,19 +488,38 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
|
|||||||
ConfigVariable **head_p, ConfigVariable **tail_p)
|
ConfigVariable **head_p, ConfigVariable **tail_p)
|
||||||
{
|
{
|
||||||
bool OK = true;
|
bool OK = true;
|
||||||
YY_BUFFER_STATE lex_buffer;
|
unsigned int save_ConfigFileLineno = ConfigFileLineno;
|
||||||
|
sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp;
|
||||||
|
sigjmp_buf flex_fatal_jmp;
|
||||||
|
volatile YY_BUFFER_STATE lex_buffer = NULL;
|
||||||
int errorcount;
|
int errorcount;
|
||||||
int token;
|
int token;
|
||||||
|
|
||||||
|
if (sigsetjmp(flex_fatal_jmp, 1) == 0)
|
||||||
|
GUC_flex_fatal_jmp = &flex_fatal_jmp;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Regain control after a fatal, internal flex error. It may have
|
||||||
|
* corrupted parser state. Consequently, abandon the file, but trust
|
||||||
|
* that the state remains sane enough for yy_delete_buffer().
|
||||||
|
*/
|
||||||
|
elog(elevel, "%s at file \"%s\" line %u",
|
||||||
|
GUC_flex_fatal_errmsg, config_file, ConfigFileLineno);
|
||||||
|
|
||||||
|
OK = false;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse
|
* Parse
|
||||||
*/
|
*/
|
||||||
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
|
|
||||||
yy_switch_to_buffer(lex_buffer);
|
|
||||||
|
|
||||||
ConfigFileLineno = 1;
|
ConfigFileLineno = 1;
|
||||||
errorcount = 0;
|
errorcount = 0;
|
||||||
|
|
||||||
|
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
|
||||||
|
yy_switch_to_buffer(lex_buffer);
|
||||||
|
|
||||||
/* This loop iterates once per logical line */
|
/* This loop iterates once per logical line */
|
||||||
while ((token = yylex()))
|
while ((token = yylex()))
|
||||||
{
|
{
|
||||||
@ -526,14 +569,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
|
|||||||
* An include_if_exists directive isn't a variable and should be
|
* An include_if_exists directive isn't a variable and should be
|
||||||
* processed immediately.
|
* processed immediately.
|
||||||
*/
|
*/
|
||||||
unsigned int save_ConfigFileLineno = ConfigFileLineno;
|
|
||||||
|
|
||||||
if (!ParseConfigFile(opt_value, config_file, false,
|
if (!ParseConfigFile(opt_value, config_file, false,
|
||||||
depth + 1, elevel,
|
depth + 1, elevel,
|
||||||
head_p, tail_p))
|
head_p, tail_p))
|
||||||
OK = false;
|
OK = false;
|
||||||
yy_switch_to_buffer(lex_buffer);
|
yy_switch_to_buffer(lex_buffer);
|
||||||
ConfigFileLineno = save_ConfigFileLineno;
|
|
||||||
pfree(opt_name);
|
pfree(opt_name);
|
||||||
pfree(opt_value);
|
pfree(opt_value);
|
||||||
}
|
}
|
||||||
@ -543,14 +583,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
|
|||||||
* An include directive isn't a variable and should be processed
|
* An include directive isn't a variable and should be processed
|
||||||
* immediately.
|
* immediately.
|
||||||
*/
|
*/
|
||||||
unsigned int save_ConfigFileLineno = ConfigFileLineno;
|
|
||||||
|
|
||||||
if (!ParseConfigFile(opt_value, config_file, true,
|
if (!ParseConfigFile(opt_value, config_file, true,
|
||||||
depth + 1, elevel,
|
depth + 1, elevel,
|
||||||
head_p, tail_p))
|
head_p, tail_p))
|
||||||
OK = false;
|
OK = false;
|
||||||
yy_switch_to_buffer(lex_buffer);
|
yy_switch_to_buffer(lex_buffer);
|
||||||
ConfigFileLineno = save_ConfigFileLineno;
|
|
||||||
pfree(opt_name);
|
pfree(opt_name);
|
||||||
pfree(opt_value);
|
pfree(opt_value);
|
||||||
}
|
}
|
||||||
@ -620,7 +657,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
yy_delete_buffer(lex_buffer);
|
yy_delete_buffer(lex_buffer);
|
||||||
|
/* Each recursion level must save and restore these static variables. */
|
||||||
|
ConfigFileLineno = save_ConfigFileLineno;
|
||||||
|
GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user