postgres.git / summary / log / commit / refs

commit    13967fe0e2b64cfcaab53ca05f4e11b34147423e
Author:   Michael Paquier <michael@paquier.xyz>
Date:     Sun Aug 16 23:53:24 2026 +0000

    Fix ASAN failure after flex errors in GUC file parsing
    
    As detected by ASAN, the scanner value used when parsing GUC files can
    be indeterminate when the flex error handler sigjumps to the old cleanup
    path, before yylex_init() is called.
    
    The flex scanner state is now made volatile in ParseConfigFp(), since
    its value is assigned after sigsetjmp() and cna be accessed after
    siglongjmp().  yylex_init() cannot use a volatile pointer; a temporary
    variable is used before assigning the result of yylex_init() to it.
    
    While on it, yy_create_buffer() is changed to detect the case where it
    returns a NULL value.  Based on my read of the flex code, this cannot be
    reached currently.  Future upstream changes or changes in the error
    logic of the GUC file parsing could make that reachable, and it is four
    extra lines of code.
    
    Oversight in d663f150b5ed.
    
    Reported-by: Ilia Kashintsev <ilia.kashintsev@gmail.com>
    Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
    Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
    Discussion: https://postgr.es/m/19612-24ccb4fc6da7786f@postgresql.org
    Backpatch-through: 18


src/backend/utils/misc/guc-file.l | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index 58669a67e05..8c38a23a84d 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -354,7 +354,8 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, unsigned int save_ConfigFileLineno = ConfigFileLineno; sigjmp_buf *save_GUC_flex_fatal_jmp = GUC_flex_fatal_jmp; sigjmp_buf flex_fatal_jmp; - yyscan_t scanner; + volatile yyscan_t scanner = NULL; + yyscan_t scanner_init = NULL; /* non-volatile for yylex_init() */ struct yyguts_t *yyg; /* needed for yytext macro */ volatile YY_BUFFER_STATE lex_buffer = NULL; int errorcount; @@ -384,11 +385,20 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, ConfigFileLineno = 1; errorcount = 0; - if (yylex_init(&scanner) != 0) + if (yylex_init(&scanner_init) != 0) + { elog(elevel, "yylex_init() failed: %m"); + goto cleanup; + } + scanner = scanner_init; yyg = (struct yyguts_t *) scanner; lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE, scanner); + if (lex_buffer == NULL) + { + elog(elevel, "yy_create_buffer() failed"); + goto cleanup; + } yy_switch_to_buffer(lex_buffer, scanner); /* This loop iterates once per logical line */ @@ -559,8 +569,11 @@ parse_error: } cleanup: - yy_delete_buffer(lex_buffer, scanner); - yylex_destroy(scanner); + if (scanner) + { + yy_delete_buffer(lex_buffer, scanner); + yylex_destroy(scanner); + } /* Each recursion level must save and restore these static variables. */ ConfigFileLineno = save_ConfigFileLineno; GUC_flex_fatal_jmp = save_GUC_flex_fatal_jmp; [parent: 7b846015a40d]