mirror of
https://github.com/postgres/postgres.git
synced 2025-05-06 19:59:18 +03:00
Avoid multiple free_struct_lconv() calls on same data.
A failure partway through PGLC_localeconv() led to a situation where the next call would call free_struct_lconv() a second time, leading to free() on already-freed strings, typically leading to a core dump. Add a flag to remember whether we need to do that. Per report from Thom Brown. His example case only provokes the failure as far back as 9.4, but nonetheless this code is obviously broken, so back-patch to all supported branches.
This commit is contained in:
parent
573cffc7a0
commit
2d43c45e9d
@ -387,9 +387,6 @@ assign_locale_messages(const char *newval, void *extra)
|
|||||||
static void
|
static void
|
||||||
free_struct_lconv(struct lconv * s)
|
free_struct_lconv(struct lconv * s)
|
||||||
{
|
{
|
||||||
if (s == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (s->currency_symbol)
|
if (s->currency_symbol)
|
||||||
free(s->currency_symbol);
|
free(s->currency_symbol);
|
||||||
if (s->decimal_point)
|
if (s->decimal_point)
|
||||||
@ -441,6 +438,7 @@ struct lconv *
|
|||||||
PGLC_localeconv(void)
|
PGLC_localeconv(void)
|
||||||
{
|
{
|
||||||
static struct lconv CurrentLocaleConv;
|
static struct lconv CurrentLocaleConv;
|
||||||
|
static bool CurrentLocaleConvAllocated = false;
|
||||||
struct lconv *extlconv;
|
struct lconv *extlconv;
|
||||||
char *save_lc_monetary;
|
char *save_lc_monetary;
|
||||||
char *save_lc_numeric;
|
char *save_lc_numeric;
|
||||||
@ -457,7 +455,12 @@ PGLC_localeconv(void)
|
|||||||
if (CurrentLocaleConvValid)
|
if (CurrentLocaleConvValid)
|
||||||
return &CurrentLocaleConv;
|
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 user's values of monetary and numeric locales */
|
||||||
save_lc_monetary = setlocale(LC_MONETARY, NULL);
|
save_lc_monetary = setlocale(LC_MONETARY, NULL);
|
||||||
@ -521,7 +524,9 @@ PGLC_localeconv(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Must copy all values since restoring internal settings may overwrite
|
* 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 = *extlconv;
|
||||||
CurrentLocaleConv.decimal_point = decimal_point;
|
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.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep);
|
||||||
CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
|
CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
|
||||||
CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);
|
CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);
|
||||||
|
CurrentLocaleConvAllocated = true;
|
||||||
|
|
||||||
/* Try to restore internal settings */
|
/* Try to restore internal settings */
|
||||||
if (save_lc_monetary)
|
if (save_lc_monetary)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user