summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cygwin/cygwin.c41
-rw-r--r--locale.c15
-rw-r--r--perl.h5
-rw-r--r--pod/perldelta.pod5
4 files changed, 60 insertions, 6 deletions
diff --git a/cygwin/cygwin.c b/cygwin/cygwin.c
index 59aa730448..24b278f2fd 100644
--- a/cygwin/cygwin.c
+++ b/cygwin/cygwin.c
@@ -154,7 +154,15 @@ wide_to_utf8(const wchar_t *wbuf)
{
char *buf;
int wlen = 0;
- char *oldlocale = setlocale(LC_CTYPE, NULL);
+ char *oldlocale;
+ dVAR;
+
+ /* Here and elsewhere in this file, we have a critical section to prevent
+ * another thread from changing the locale out from under us. XXX But why
+ * not just use uvchr_to_utf8? */
+ LOCALE_LOCK;
+
+ oldlocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "utf-8");
/* uvchr_to_utf8(buf, chr) or Encoding::_bytes_to_utf8(sv, "UCS-2BE"); */
@@ -164,6 +172,9 @@ wide_to_utf8(const wchar_t *wbuf)
if (oldlocale) setlocale(LC_CTYPE, oldlocale);
else setlocale(LC_CTYPE, "C");
+
+ LOCALE_UNLOCK;
+
return buf;
}
@@ -172,8 +183,13 @@ utf8_to_wide(const char *buf)
{
wchar_t *wbuf;
mbstate_t mbs;
- char *oldlocale = setlocale(LC_CTYPE, NULL);
+ char *oldlocale;
int wlen = sizeof(wchar_t)*strlen(buf);
+ dVAR;
+
+ LOCALE_LOCK;
+
+ oldlocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "utf-8");
wbuf = (wchar_t *) safemalloc(wlen);
@@ -182,6 +198,9 @@ utf8_to_wide(const char *buf)
if (oldlocale) setlocale(LC_CTYPE, oldlocale);
else setlocale(LC_CTYPE, "C");
+
+ LOCALE_UNLOCK;
+
return wbuf;
}
#endif /* cygwin 1.7 */
@@ -280,7 +299,12 @@ XS(XS_Cygwin_win_to_posix_path)
wchar_t *wbuf = (wchar_t *) safemalloc(wlen);
if (!IN_BYTES) {
mbstate_t mbs;
- char *oldlocale = setlocale(LC_CTYPE, NULL);
+ char *oldlocale;
+ dVAR;
+
+ LOCALE_LOCK;
+
+ oldlocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "utf-8");
/* utf8_to_uvchr_buf(src_path, src_path + wlen, wpath) or Encoding::_utf8_to_bytes(sv, "UCS-2BE"); */
wlen = mbsrtowcs(wpath, (const char**)&src_path, wlen, &mbs);
@@ -288,6 +312,8 @@ XS(XS_Cygwin_win_to_posix_path)
err = cygwin_conv_path(what, wpath, wbuf, wlen);
if (oldlocale) setlocale(LC_CTYPE, oldlocale);
else setlocale(LC_CTYPE, "C");
+
+ LOCALE_UNLOCK;
} else { /* use bytes; assume already ucs-2 encoded bytestream */
err = cygwin_conv_path(what, src_path, wbuf, wlen);
}
@@ -365,7 +391,12 @@ XS(XS_Cygwin_posix_to_win_path)
int wlen = sizeof(wchar_t)*(len + 260 + 1001);
wchar_t *wpath = (wchar_t *) safemalloc(sizeof(wchar_t)*len);
wchar_t *wbuf = (wchar_t *) safemalloc(wlen);
- char *oldlocale = setlocale(LC_CTYPE, NULL);
+ char *oldlocale;
+ dVAR;
+
+ LOCALE_LOCK;
+
+ oldlocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "utf-8");
if (!IN_BYTES) {
mbstate_t mbs;
@@ -388,6 +419,8 @@ XS(XS_Cygwin_posix_to_win_path)
wcsrtombs(win_path, (const wchar_t **)&wbuf, wlen, NULL);
if (oldlocale) setlocale(LC_CTYPE, oldlocale);
else setlocale(LC_CTYPE, "C");
+
+ LOCALE_UNLOCK;
} else {
int what = absolute_flag ? CCP_POSIX_TO_WIN_A : CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
win_path = (char *) safemalloc(len + 260 + 1001);
diff --git a/locale.c b/locale.c
index 6de9893283..bf8713a665 100644
--- a/locale.c
+++ b/locale.c
@@ -1809,13 +1809,21 @@ Perl__is_in_locale_category(pTHX_ const bool compiling, const int category)
char *
Perl_my_strerror(pTHX_ const int errnum) {
+ dVAR;
/* Uses C locale for the error text unless within scope of 'use locale' for
* LC_MESSAGES */
#ifdef USE_LOCALE_MESSAGES
if (! IN_LC(LC_MESSAGES)) {
- char * save_locale = setlocale(LC_MESSAGES, NULL);
+ char * save_locale;
+
+ /* We have a critical section to prevent another thread from changing
+ * the locale out from under us (or zapping the buffer returned from
+ * setlocale() ) */
+ LOCALE_LOCK;
+
+ save_locale = setlocale(LC_MESSAGES, NULL);
if (! isNAME_C_OR_POSIX(save_locale)) {
char *errstr;
@@ -1830,8 +1838,13 @@ Perl_my_strerror(pTHX_ const int errnum) {
setlocale(LC_MESSAGES, save_locale);
Safefree(save_locale);
+
+ LOCALE_UNLOCK;
+
return errstr;
}
+
+ LOCALE_UNLOCK;
}
#endif
diff --git a/perl.h b/perl.h
index 49330d1aed..396bc928b5 100644
--- a/perl.h
+++ b/perl.h
@@ -5958,6 +5958,9 @@ typedef struct am_table_short AMTS;
# define LOCALE_INIT MUTEX_INIT(&PL_locale_mutex)
# define LOCALE_TERM MUTEX_DESTROY(&PL_locale_mutex)
+# define LOCALE_LOCK MUTEX_LOCK(&PL_locale_mutex)
+# define LOCALE_UNLOCK MUTEX_UNLOCK(&PL_locale_mutex)
+
/* Returns TRUE if the plain locale pragma without a parameter is in effect
*/
# define IN_LOCALE_RUNTIME cBOOL(CopHINTS_get(PL_curcop) & HINT_LOCALE)
@@ -6043,6 +6046,8 @@ typedef struct am_table_short AMTS;
#else /* No locale usage */
# define LOCALE_INIT
# define LOCALE_TERM
+# define LOCALE_LOCK
+# define LOCALE_UNLOCK
# define IN_LOCALE_RUNTIME 0
# define IN_SOME_LOCALE_FORM_RUNTIME 0
# define IN_LOCALE_COMPILETIME 0
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 57cf7c1daa..4dcc7af6f5 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -341,7 +341,10 @@ files in F<ext/> and F<lib/> are best summarized in L</Modules and Pragmata>.
=item *
-XXX
+A race condition which occurred when computing C<"$!"> with threads
+activated has been fixed. This showed up only on Darwin platforms. A
+related problem on Cygwin platforms involving UTF-8 strings has also
+been fixed. [perl #127708]
=back