Skip to content

Commit 0c4457d

Browse files
committed
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.
1 parent 8fed3cc commit 0c4457d

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,6 @@ assign_locale_messages(const char *newval, void *extra)
363363
static void
364364
free_struct_lconv(struct lconv * s)
365365
{
366-
if (s == NULL)
367-
return;
368-
369366
if (s->currency_symbol)
370367
free(s->currency_symbol);
371368
if (s->decimal_point)
@@ -419,6 +416,7 @@ struct lconv *
419416
PGLC_localeconv(void)
420417
{
421418
static struct lconv CurrentLocaleConv;
419+
static bool CurrentLocaleConvAllocated = false;
422420
struct lconv *extlconv;
423421
char *save_lc_monetary;
424422
char *save_lc_numeric;
@@ -435,7 +433,12 @@ PGLC_localeconv(void)
435433
if (CurrentLocaleConvValid)
436434
return &CurrentLocaleConv;
437435

438-
free_struct_lconv(&CurrentLocaleConv);
436+
/* Free any already-allocated storage */
437+
if (CurrentLocaleConvAllocated)
438+
{
439+
free_struct_lconv(&CurrentLocaleConv);
440+
CurrentLocaleConvAllocated = false;
441+
}
439442

440443
/* Save user's values of monetary and numeric locales */
441444
save_lc_monetary = setlocale(LC_MONETARY, NULL);
@@ -499,7 +502,9 @@ PGLC_localeconv(void)
499502

500503
/*
501504
* Must copy all values since restoring internal settings may overwrite
502-
* localeconv()'s results.
505+
* localeconv()'s results. Note that if we were to fail within this
506+
* sequence before reaching "CurrentLocaleConvAllocated = true", we could
507+
* leak some memory --- but not much, so it's not worth agonizing over.
503508
*/
504509
CurrentLocaleConv = *extlconv;
505510
CurrentLocaleConv.decimal_point = decimal_point;
@@ -512,6 +517,7 @@ PGLC_localeconv(void)
512517
CurrentLocaleConv.mon_thousands_sep = db_encoding_strdup(encoding, extlconv->mon_thousands_sep);
513518
CurrentLocaleConv.negative_sign = db_encoding_strdup(encoding, extlconv->negative_sign);
514519
CurrentLocaleConv.positive_sign = db_encoding_strdup(encoding, extlconv->positive_sign);
520+
CurrentLocaleConvAllocated = true;
515521

516522
/* Try to restore internal settings */
517523
if (save_lc_monetary)

0 commit comments

Comments
 (0)