diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c index d91959ea7f8..76acdcb274f 100644 --- a/src/backend/utils/adt/pg_locale.c +++ b/src/backend/utils/adt/pg_locale.c @@ -387,9 +387,6 @@ assign_locale_messages(const char *newval, void *extra) static void free_struct_lconv(struct lconv * s) { - if (s == NULL) - return; - if (s->currency_symbol) free(s->currency_symbol); if (s->decimal_point) @@ -441,6 +438,7 @@ struct lconv * PGLC_localeconv(void) { static struct lconv CurrentLocaleConv; + static bool CurrentLocaleConvAllocated = false; struct lconv *extlconv; char *save_lc_monetary; char *save_lc_numeric; @@ -457,7 +455,12 @@ PGLC_localeconv(void) if (CurrentLocaleConvValid) return &CurrentLocaleConv; - free_struct_lconv(&CurrentLocaleConv); + /* Free any already-allocated storage */ + if (CurrentLocaleConvAllocated) + { + free_struct_lconv(&CurrentLocaleConv); + CurrentLocaleConvAllocated = false; + } /* Save user's values of monetary and numeric locales */ save_lc_monetary = setlocale(LC_MONETARY, NULL); @@ -521,7 +524,9 @@ PGLC_localeconv(void) /* * Must copy all values since restoring internal settings may overwrite - * localeconv()'s results. + * localeconv()'s results. Note that if we were to fail within this + * sequence before reaching "CurrentLocaleConvAllocated = true", we could + * leak some memory --- but not much, so it's not worth agonizing over. */ CurrentLocaleConv = *extlconv; CurrentLocaleConv.decimal_point = decimal_point; @@ -534,6 +539,7 @@ PGLC_localeconv(void) CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep); CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign); CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign); + CurrentLocaleConvAllocated = true; /* Try to restore internal settings */ if (save_lc_monetary)