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
2732enum {
2833 GUC_ID = 1 ,
@@ -37,10 +42,13 @@ enum {
3742};
3843
3944static 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 */
4249int GUC_yylex (void );
4350
51+ static int GUC_flex_fatal (const char *msg);
4452static 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