@@ -76,6 +76,13 @@ typedef struct
7676#define token_is_keyword (t , k ) (!t->quoted && strcmp(t->string, k) == 0)
7777#define token_matches (t , k ) (strcmp(t->string, k) == 0)
7878
79+ /*
80+ * Memory context holding the list of TokenizedAuthLines when parsing
81+ * HBA or ident configuration files. This is created when opening the first
82+ * file (depth of 0).
83+ */
84+ static MemoryContext tokenize_context = NULL ;
85+
7986/*
8087 * pre-parsed content of HBA config file: list of HbaLine structs.
8188 * parsed_hba_context is the memory context where it lives.
@@ -121,9 +128,9 @@ static const char *const UserAuthName[] =
121128};
122129
123130
124- static List * tokenize_inc_file (List * tokens , const char * outer_filename ,
125- const char * inc_filename , int elevel ,
126- int depth , char * * err_msg );
131+ static List * tokenize_expand_file (List * tokens , const char * outer_filename ,
132+ const char * inc_filename , int elevel ,
133+ int depth , char * * err_msg );
127134static bool parse_hba_auth_opt (char * name , char * val , HbaLine * hbaline ,
128135 int elevel , char * * err_msg );
129136static int regcomp_auth_token (AuthToken * token , char * filename , int line_num ,
@@ -437,43 +444,53 @@ next_field_expand(const char *filename, char **lineptr,
437444
438445 /* Is this referencing a file? */
439446 if (!initial_quote && buf [0 ] == '@' && buf [1 ] != '\0' )
440- tokens = tokenize_inc_file (tokens , filename , buf + 1 ,
441- elevel , depth + 1 , err_msg );
447+ tokens = tokenize_expand_file (tokens , filename , buf + 1 ,
448+ elevel , depth + 1 , err_msg );
442449 else
450+ {
451+ MemoryContext oldcxt ;
452+
453+ /*
454+ * lappend() may do its own allocations, so move to the context
455+ * for the list of tokens.
456+ */
457+ oldcxt = MemoryContextSwitchTo (tokenize_context );
443458 tokens = lappend (tokens , make_auth_token (buf , initial_quote ));
459+ MemoryContextSwitchTo (oldcxt );
460+ }
444461 } while (trailing_comma && (* err_msg == NULL ));
445462
446463 return tokens ;
447464}
448465
449466/*
450- * tokenize_inc_file
467+ * tokenize_expand_file
451468 * Expand a file included from another file into an hba "field"
452469 *
453470 * Opens and tokenises a file included from another HBA config file with @,
454471 * and returns all values found therein as a flat list of AuthTokens. If a
455472 * @-token is found, recursively expand it. The newly read tokens are
456473 * appended to "tokens" (so that foo,bar,@baz does what you expect).
457- * All new tokens are allocated in caller's memory context.
474+ * All new tokens are allocated in the memory context dedicated to the
475+ * list of TokenizedAuthLines, aka tokenize_context.
458476 *
459477 * In event of an error, log a message at ereport level elevel, and also
460478 * set *err_msg to a string describing the error. Note that the result
461479 * may be non-NIL anyway, so *err_msg must be tested to determine whether
462480 * there was an error.
463481 */
464482static List *
465- tokenize_inc_file (List * tokens ,
466- const char * outer_filename ,
467- const char * inc_filename ,
468- int elevel ,
469- int depth ,
470- char * * err_msg )
483+ tokenize_expand_file (List * tokens ,
484+ const char * outer_filename ,
485+ const char * inc_filename ,
486+ int elevel ,
487+ int depth ,
488+ char * * err_msg )
471489{
472490 char * inc_fullname ;
473491 FILE * inc_file ;
474492 List * inc_lines ;
475493 ListCell * inc_line ;
476- MemoryContext linecxt ;
477494
478495 inc_fullname = AbsoluteConfigLocation (inc_filename , outer_filename );
479496 inc_file = open_auth_file (inc_fullname , elevel , depth , err_msg );
@@ -486,13 +503,15 @@ tokenize_inc_file(List *tokens,
486503 }
487504
488505 /* There is possible recursion here if the file contains @ */
489- linecxt = tokenize_auth_file (inc_fullname , inc_file , & inc_lines , elevel ,
490- depth );
506+ tokenize_auth_file (inc_fullname , inc_file , & inc_lines , elevel ,
507+ depth );
491508
492- FreeFile (inc_file );
493509 pfree (inc_fullname );
494510
495- /* Copy all tokens found in the file and append to the tokens list */
511+ /*
512+ * Move all the tokens found in the file to the tokens list. These are
513+ * already saved in tokenize_context.
514+ */
496515 foreach (inc_line , inc_lines )
497516 {
498517 TokenizedAuthLine * tok_line = (TokenizedAuthLine * ) lfirst (inc_line );
@@ -513,16 +532,40 @@ tokenize_inc_file(List *tokens,
513532 foreach (inc_token , inc_tokens )
514533 {
515534 AuthToken * token = lfirst (inc_token );
535+ MemoryContext oldcxt ;
516536
517- tokens = lappend (tokens , copy_auth_token (token ));
537+ /*
538+ * lappend() may do its own allocations, so move to the
539+ * context for the list of tokens.
540+ */
541+ oldcxt = MemoryContextSwitchTo (tokenize_context );
542+ tokens = lappend (tokens , token );
543+ MemoryContextSwitchTo (oldcxt );
518544 }
519545 }
520546 }
521547
522- MemoryContextDelete ( linecxt );
548+ free_auth_file ( inc_file , depth );
523549 return tokens ;
524550}
525551
552+ /*
553+ * free_auth_file
554+ * Free a file opened by open_auth_file().
555+ */
556+ void
557+ free_auth_file (FILE * file , int depth )
558+ {
559+ FreeFile (file );
560+
561+ /* If this is the last cleanup, remove the tokenization context */
562+ if (depth == 0 )
563+ {
564+ MemoryContextDelete (tokenize_context );
565+ tokenize_context = NULL ;
566+ }
567+ }
568+
526569/*
527570 * open_auth_file
528571 * Open the given file.
@@ -558,6 +601,22 @@ open_auth_file(const char *filename, int elevel, int depth,
558601 return NULL ;
559602 }
560603
604+ /*
605+ * When opening the top-level file, create the memory context used for the
606+ * tokenization. This will be closed with this file when coming back to
607+ * this level of cleanup.
608+ */
609+ if (depth == 0 )
610+ {
611+ /*
612+ * A context may be present, but assume that it has been eliminated
613+ * already.
614+ */
615+ tokenize_context = AllocSetContextCreate (CurrentMemoryContext ,
616+ "tokenize_context" ,
617+ ALLOCSET_START_SMALL_SIZES );
618+ }
619+
561620 file = AllocateFile (filename , "r" );
562621 if (file == NULL )
563622 {
@@ -570,6 +629,8 @@ open_auth_file(const char *filename, int elevel, int depth,
570629 if (err_msg )
571630 * err_msg = psprintf ("could not open file \"%s\": %s" ,
572631 filename , strerror (save_errno ));
632+ /* the caller may care about some specific errno */
633+ errno = save_errno ;
573634 return NULL ;
574635 }
575636
@@ -593,32 +654,34 @@ tokenize_error_callback(void *arg)
593654 * Tokenize the given file.
594655 *
595656 * The output is a list of TokenizedAuthLine structs; see the struct definition
596- * in libpq/hba.h.
657+ * in libpq/hba.h. This is the central piece in charge of parsing the
658+ * authentication files. All the operations of this function happen in its own
659+ * local memory context, easing the cleanup of anything allocated here. This
660+ * matters a lot when reloading authentication files in the postmaster.
597661 *
598662 * filename: the absolute path to the target file
599663 * file: the already-opened target file
600- * tok_lines: receives output list
664+ * tok_lines: receives output list, saved into tokenize_context
601665 * elevel: message logging level
602666 * depth: level of recursion when tokenizing the target file
603667 *
604668 * Errors are reported by logging messages at ereport level elevel and by
605669 * adding TokenizedAuthLine structs containing non-null err_msg fields to the
606670 * output list.
607- *
608- * Return value is a memory context which contains all memory allocated by
609- * this function (it's a child of caller's context).
610671 */
611- MemoryContext
672+ void
612673tokenize_auth_file (const char * filename , FILE * file , List * * tok_lines ,
613674 int elevel , int depth )
614675{
615676 int line_number = 1 ;
616677 StringInfoData buf ;
617678 MemoryContext linecxt ;
618- MemoryContext oldcxt ;
679+ MemoryContext funccxt ; /* context of this function's caller */
619680 ErrorContextCallback tokenerrcontext ;
620681 tokenize_error_callback_arg callback_arg ;
621682
683+ Assert (tokenize_context );
684+
622685 callback_arg .filename = filename ;
623686 callback_arg .linenum = line_number ;
624687
@@ -627,14 +690,19 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
627690 tokenerrcontext .previous = error_context_stack ;
628691 error_context_stack = & tokenerrcontext ;
629692
693+ /*
694+ * Do all the local tokenization in its own context, to ease the cleanup
695+ * of any memory allocated while tokenizing.
696+ */
630697 linecxt = AllocSetContextCreate (CurrentMemoryContext ,
631698 "tokenize_auth_file" ,
632699 ALLOCSET_SMALL_SIZES );
633- oldcxt = MemoryContextSwitchTo (linecxt );
700+ funccxt = MemoryContextSwitchTo (linecxt );
634701
635702 initStringInfo (& buf );
636703
637- * tok_lines = NIL ;
704+ if (depth == 0 )
705+ * tok_lines = NIL ;
638706
639707 while (!feof (file ) && !ferror (file ))
640708 {
@@ -694,7 +762,17 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
694762 elevel , depth , & err_msg );
695763 /* add field to line, unless we are at EOL or comment start */
696764 if (current_field != NIL )
765+ {
766+ MemoryContext oldcxt ;
767+
768+ /*
769+ * lappend() may do its own allocations, so move to the
770+ * context for the list of tokens.
771+ */
772+ oldcxt = MemoryContextSwitchTo (tokenize_context );
697773 current_line = lappend (current_line , current_field );
774+ MemoryContextSwitchTo (oldcxt );
775+ }
698776 }
699777
700778 /*
@@ -703,25 +781,27 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
703781 if (current_line != NIL || err_msg != NULL )
704782 {
705783 TokenizedAuthLine * tok_line ;
784+ MemoryContext oldcxt ;
706785
786+ oldcxt = MemoryContextSwitchTo (tokenize_context );
707787 tok_line = (TokenizedAuthLine * ) palloc (sizeof (TokenizedAuthLine ));
708788 tok_line -> fields = current_line ;
709789 tok_line -> file_name = pstrdup (filename );
710790 tok_line -> line_num = line_number ;
711791 tok_line -> raw_line = pstrdup (buf .data );
712- tok_line -> err_msg = err_msg ;
792+ tok_line -> err_msg = err_msg ? pstrdup ( err_msg ) : NULL ;
713793 * tok_lines = lappend (* tok_lines , tok_line );
794+ MemoryContextSwitchTo (oldcxt );
714795 }
715796
716797 line_number += continuations + 1 ;
717798 callback_arg .linenum = line_number ;
718799 }
719800
720- MemoryContextSwitchTo (oldcxt );
801+ MemoryContextSwitchTo (funccxt );
802+ MemoryContextDelete (linecxt );
721803
722804 error_context_stack = tokenerrcontext .previous ;
723-
724- return linecxt ;
725805}
726806
727807
@@ -2409,7 +2489,6 @@ load_hba(void)
24092489 ListCell * line ;
24102490 List * new_parsed_lines = NIL ;
24112491 bool ok = true;
2412- MemoryContext linecxt ;
24132492 MemoryContext oldcxt ;
24142493 MemoryContext hbacxt ;
24152494
@@ -2420,8 +2499,7 @@ load_hba(void)
24202499 return false;
24212500 }
24222501
2423- linecxt = tokenize_auth_file (HbaFileName , file , & hba_lines , LOG , 0 );
2424- FreeFile (file );
2502+ tokenize_auth_file (HbaFileName , file , & hba_lines , LOG , 0 );
24252503
24262504 /* Now parse all the lines */
24272505 Assert (PostmasterContext );
@@ -2472,7 +2550,7 @@ load_hba(void)
24722550 }
24732551
24742552 /* Free tokenizer memory */
2475- MemoryContextDelete ( linecxt );
2553+ free_auth_file ( file , 0 );
24762554 MemoryContextSwitchTo (oldcxt );
24772555
24782556 if (!ok )
@@ -2776,7 +2854,6 @@ load_ident(void)
27762854 * parsed_line_cell ;
27772855 List * new_parsed_lines = NIL ;
27782856 bool ok = true;
2779- MemoryContext linecxt ;
27802857 MemoryContext oldcxt ;
27812858 MemoryContext ident_context ;
27822859 IdentLine * newline ;
@@ -2789,8 +2866,7 @@ load_ident(void)
27892866 return false;
27902867 }
27912868
2792- linecxt = tokenize_auth_file (IdentFileName , file , & ident_lines , LOG , 0 );
2793- FreeFile (file );
2869+ tokenize_auth_file (IdentFileName , file , & ident_lines , LOG , 0 );
27942870
27952871 /* Now parse all the lines */
27962872 Assert (PostmasterContext );
@@ -2826,7 +2902,7 @@ load_ident(void)
28262902 }
28272903
28282904 /* Free tokenizer memory */
2829- MemoryContextDelete ( linecxt );
2905+ free_auth_file ( file , 0 );
28302906 MemoryContextSwitchTo (oldcxt );
28312907
28322908 if (!ok )
0 commit comments