Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)