Skip to content

Commit 0d17ce9

Browse files
committed
Fix breakage that had crept into setlocale() usage: once again we've
been bit by the fact that the locale functions return pointers to modifiable variables. I added some comments that might help us avoid the mistake in future.
1 parent 6c06bc2 commit 0d17ce9

File tree

1 file changed

+50
-25
lines changed

1 file changed

+50
-25
lines changed

src/backend/utils/adt/pg_locale.c

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
*
33
* PostgreSQL locale utilities
44
*
5-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.19 2002/09/04 20:31:28 momjian Exp $
6-
*
75
* Portions Copyright (c) 2002, PostgreSQL Global Development Group
86
*
7+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/pg_locale.c,v 1.20 2002/10/18 20:44:02 tgl Exp $
8+
*
99
*-----------------------------------------------------------------------
1010
*/
1111

12-
/*
12+
/*----------
1313
* Here is how the locale stuff is handled: LC_COLLATE and LC_CTYPE
1414
* are fixed by initdb, stored in pg_control, and cannot be changed.
1515
* Thus, the effects of strcoll(), strxfrm(), isupper(), toupper(),
@@ -20,14 +20,29 @@
2020
*
2121
* The other categories, LC_MONETARY, LC_NUMERIC, and LC_TIME are also
2222
* settable at run-time. However, we don't actually set those locale
23-
* categories permanently. This would have bizzare effects like no
23+
* categories permanently. This would have bizarre effects like no
2424
* longer accepting standard floating-point literals in some locales.
2525
* Instead, we only set the locales briefly when needed, cache the
2626
* required information obtained from localeconv(), and set them back.
27-
* The information is only used by the formatting functions (to_char,
28-
* etc.) and the money type. For the user, this should all be
27+
* The cached information is only used by the formatting functions
28+
* (to_char, etc.) and the money type. For the user, this should all be
2929
* transparent. (Actually, LC_TIME doesn't do anything at all right
3030
* now.)
31+
*
32+
* !!! NOW HEAR THIS !!!
33+
*
34+
* We've been bitten repeatedly by this bug, so let's try to keep it in
35+
* mind in future: on some platforms, the locale functions return pointers
36+
* to static data that will be overwritten by any later locale function.
37+
* Thus, for example, the obvious-looking sequence
38+
* save = setlocale(category, NULL);
39+
* if (!setlocale(category, value))
40+
* fail = true;
41+
* setlocale(category, save);
42+
* DOES NOT WORK RELIABLY: on some platforms the second setlocale() call
43+
* will change the memory save is pointing at. To do this sort of thing
44+
* safely, you *must* pstrdup what setlocale returns the first time.
45+
*----------
3146
*/
3247

3348

@@ -64,15 +79,19 @@ locale_xxx_assign(int category, const char *value, bool doit, bool interactive)
6479

6580
save = setlocale(category, NULL);
6681
if (!save)
67-
return NULL;
82+
return NULL; /* won't happen, we hope */
83+
84+
/* save may be pointing at a modifiable scratch variable, see above */
85+
save = pstrdup(save);
6886

6987
if (!setlocale(category, value))
70-
return NULL;
88+
value = NULL; /* set failure return marker */
7189

72-
setlocale(category, save);
90+
setlocale(category, save); /* assume this won't fail */
91+
pfree(save);
7392

74-
/* need to reload cache next time */
75-
if (doit)
93+
/* need to reload cache next time? */
94+
if (doit && value != NULL)
7695
CurrentLocaleConvValid = false;
7796

7897
return value;
@@ -99,7 +118,7 @@ locale_time_assign(const char *value, bool doit, bool interactive)
99118

100119

101120
/*
102-
* lc_messages takes effect immediately
121+
* We allow LC_MESSAGES to actually be set globally.
103122
*/
104123
const char *
105124
locale_messages_assign(const char *value, bool doit, bool interactive)
@@ -116,16 +135,7 @@ locale_messages_assign(const char *value, bool doit, bool interactive)
116135
}
117136
else
118137
{
119-
char *save;
120-
121-
save = setlocale(LC_MESSAGES, NULL);
122-
if (!save)
123-
return NULL;
124-
125-
if (!setlocale(LC_MESSAGES, value))
126-
return NULL;
127-
128-
setlocale(LC_MESSAGES, save);
138+
value = locale_xxx_assign(LC_MESSAGES, value, false, interactive);
129139
}
130140
#endif
131141
return value;
@@ -210,8 +220,13 @@ PGLC_localeconv(void)
210220

211221
free_struct_lconv(&CurrentLocaleConv);
212222

223+
/* Set user's values of monetary and numeric locales */
213224
save_lc_monetary = setlocale(LC_MONETARY, NULL);
225+
if (save_lc_monetary)
226+
save_lc_monetary = pstrdup(save_lc_monetary);
214227
save_lc_numeric = setlocale(LC_NUMERIC, NULL);
228+
if (save_lc_numeric)
229+
save_lc_numeric = pstrdup(save_lc_numeric);
215230

216231
setlocale(LC_MONETARY, locale_monetary);
217232
setlocale(LC_NUMERIC, locale_numeric);
@@ -221,7 +236,7 @@ PGLC_localeconv(void)
221236

222237
/*
223238
* Must copy all values since restoring internal settings may
224-
* overwrite
239+
* overwrite localeconv()'s results.
225240
*/
226241
CurrentLocaleConv = *extlconv;
227242
CurrentLocaleConv.currency_symbol = strdup(extlconv->currency_symbol);
@@ -236,8 +251,18 @@ PGLC_localeconv(void)
236251
CurrentLocaleConv.positive_sign = strdup(extlconv->positive_sign);
237252
CurrentLocaleConv.n_sign_posn = extlconv->n_sign_posn;
238253

239-
setlocale(LC_MONETARY, save_lc_monetary);
240-
setlocale(LC_NUMERIC, save_lc_numeric);
254+
/* Try to restore internal settings */
255+
if (save_lc_monetary)
256+
{
257+
setlocale(LC_MONETARY, save_lc_monetary);
258+
pfree(save_lc_monetary);
259+
}
260+
261+
if (save_lc_numeric)
262+
{
263+
setlocale(LC_NUMERIC, save_lc_numeric);
264+
pfree(save_lc_numeric);
265+
}
241266

242267
CurrentLocaleConvValid = true;
243268
return &CurrentLocaleConv;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy