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

Commit 4b496a3

Browse files
committed
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.
1 parent 754b814 commit 4b496a3

File tree

1 file changed

+53
-12
lines changed

1 file changed

+53
-12
lines changed

src/backend/utils/misc/guc-file.l

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@
2020
#include "utils/guc.h"
2121

2222

23-
/* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
23+
/*
24+
* flex emits a yy_fatal_error() function that it calls in response to
25+
* critical errors like malloc failure, file I/O errors, and detection of
26+
* internal inconsistency. That function prints a message and calls exit().
27+
* Mutate it to instead call our handler, which jumps out of the parser.
28+
*/
2429
#undef fprintf
25-
#define fprintf(file, fmt, msg) ereport(ERROR, (errmsg_internal("%s", msg)))
30+
#define fprintf(file, fmt, msg) GUC_flex_fatal(msg)
2631

2732
enum {
2833
GUC_ID = 1,
@@ -37,10 +42,13 @@ enum {
3742
};
3843

3944
static unsigned int ConfigFileLineno;
45+
static const char *GUC_flex_fatal_errmsg;
46+
static sigjmp_buf *GUC_flex_fatal_jmp;
4047

4148
/* flex fails to supply a prototype for yylex, so provide one */
4249
int GUC_yylex(void);
4350

51+
static int GUC_flex_fatal(const char *msg);
4452
static char *GUC_scanstr(const char *s);
4553

4654
%}
@@ -436,6 +444,22 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
436444
return OK;
437445
}
438446

447+
/*
448+
* Flex fatal errors bring us here. Stash the error message and jump back to
449+
* ParseConfigFp(). Assume all msg arguments point to string constants; this
450+
* holds for flex 2.5.31 (earliest we support) and flex 2.5.35 (latest as of
451+
* this writing). Otherwise, we would need to copy the message.
452+
*
453+
* We return "int" since this takes the place of calls to fprintf().
454+
*/
455+
static int
456+
GUC_flex_fatal(const char *msg)
457+
{
458+
GUC_flex_fatal_errmsg = msg;
459+
siglongjmp(*GUC_flex_fatal_jmp, 1);
460+
return 0; /* keep compiler quiet */
461+
}
462+
439463
/*
440464
* Read and parse a single configuration file. This function recurses
441465
* to handle "include" directives.
@@ -464,19 +488,38 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
464488
ConfigVariable **head_p, ConfigVariable **tail_p)
465489
{
466490
bool OK = true;
467-
YY_BUFFER_STATE lex_buffer;
491+
unsigned int save_ConfigFileLineno = ConfigFileLineno;
492+
sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp;
493+
sigjmp_buf flex_fatal_jmp;
494+
volatile YY_BUFFER_STATE lex_buffer = NULL;
468495
int errorcount;
469496
int token;
470497

498+
if (sigsetjmp(flex_fatal_jmp, 1) == 0)
499+
GUC_flex_fatal_jmp = &flex_fatal_jmp;
500+
else
501+
{
502+
/*
503+
* Regain control after a fatal, internal flex error. It may have
504+
* corrupted parser state. Consequently, abandon the file, but trust
505+
* that the state remains sane enough for yy_delete_buffer().
506+
*/
507+
elog(elevel, "%s at file \"%s\" line %u",
508+
GUC_flex_fatal_errmsg, config_file, ConfigFileLineno);
509+
510+
OK = false;
511+
goto cleanup;
512+
}
513+
471514
/*
472515
* Parse
473516
*/
474-
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
475-
yy_switch_to_buffer(lex_buffer);
476-
477517
ConfigFileLineno = 1;
478518
errorcount = 0;
479519

520+
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
521+
yy_switch_to_buffer(lex_buffer);
522+
480523
/* This loop iterates once per logical line */
481524
while ((token = yylex()))
482525
{
@@ -526,14 +569,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
526569
* An include_if_exists directive isn't a variable and should be
527570
* processed immediately.
528571
*/
529-
unsigned int save_ConfigFileLineno = ConfigFileLineno;
530-
531572
if (!ParseConfigFile(opt_value, config_file, false,
532573
depth + 1, elevel,
533574
head_p, tail_p))
534575
OK = false;
535576
yy_switch_to_buffer(lex_buffer);
536-
ConfigFileLineno = save_ConfigFileLineno;
537577
pfree(opt_name);
538578
pfree(opt_value);
539579
}
@@ -543,14 +583,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
543583
* An include directive isn't a variable and should be processed
544584
* immediately.
545585
*/
546-
unsigned int save_ConfigFileLineno = ConfigFileLineno;
547-
548586
if (!ParseConfigFile(opt_value, config_file, true,
549587
depth + 1, elevel,
550588
head_p, tail_p))
551589
OK = false;
552590
yy_switch_to_buffer(lex_buffer);
553-
ConfigFileLineno = save_ConfigFileLineno;
554591
pfree(opt_name);
555592
pfree(opt_value);
556593
}
@@ -620,7 +657,11 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
620657
break;
621658
}
622659

660+
cleanup:
623661
yy_delete_buffer(lex_buffer);
662+
/* Each recursion level must save and restore these static variables. */
663+
ConfigFileLineno = save_ConfigFileLineno;
664+
GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp;
624665
return OK;
625666
}
626667

0 commit comments

Comments
 (0)