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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy