1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-03 18:25:35 +00:00

#5851: Use per-thread locale setup if possible

This prevents crashes on concurrent tr_variantFromBuf, tr_variantToBuf
and tr_variantGetReal use.
This commit is contained in:
Mike Gelfand 2015-06-01 05:25:14 +00:00
parent 2e6d5c8bc9
commit ae5755dc1e
3 changed files with 86 additions and 15 deletions

View file

@ -381,7 +381,8 @@ include(LargeFileSupport)
set(NEEDED_HEADERS set(NEEDED_HEADERS
stdbool.h stdbool.h
sys/statvfs.h sys/statvfs.h
xfs/xfs.h) xfs/xfs.h
xlocale.h)
if(ENABLE_NLS) if(ENABLE_NLS)
list(APPEND NEEDED_HEADERS libintl.h) list(APPEND NEEDED_HEADERS libintl.h)
@ -416,6 +417,7 @@ set(NEEDED_FUNCTIONS
strlcpy strlcpy
strsep strsep
syslog syslog
uselocale
valloc) valloc)
foreach(F ${NEEDED_FUNCTIONS}) foreach(F ${NEEDED_FUNCTIONS})

View file

@ -106,8 +106,8 @@ fi
AC_HEADER_STDC AC_HEADER_STDC
AC_HEADER_TIME AC_HEADER_TIME
AC_CHECK_HEADERS([stdbool.h]) AC_CHECK_HEADERS([stdbool.h xlocale.h])
AC_CHECK_FUNCS([iconv_open pread pwrite lrintf strlcpy daemon dirname basename canonicalize_file_name strcasecmp localtime_r fallocate64 posix_fallocate memmem strsep strtold syslog valloc getpagesize posix_memalign statvfs htonll ntohll mkdtemp]) AC_CHECK_FUNCS([iconv_open pread pwrite lrintf strlcpy daemon dirname basename canonicalize_file_name strcasecmp localtime_r fallocate64 posix_fallocate memmem strsep strtold syslog valloc getpagesize posix_memalign statvfs htonll ntohll mkdtemp uselocale])
AC_PROG_INSTALL AC_PROG_INSTALL
AC_PROG_MAKE_SET AC_PROG_MAKE_SET
ACX_PTHREAD ACX_PTHREAD

View file

@ -7,6 +7,15 @@
* $Id$ * $Id$
*/ */
#if defined (HAVE_USELOCALE) && (!defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 700)
#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
#endif
#if defined (HAVE_USELOCALE) && !defined (_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> /* strtod(), realloc(), qsort() */ #include <stdlib.h> /* strtod(), realloc(), qsort() */
@ -18,6 +27,10 @@
#include <locale.h> /* setlocale() */ #include <locale.h> /* setlocale() */
#if defined (HAVE_USELOCALE) && defined (HAVE_XLOCALE_H)
#include <xlocale.h>
#endif
#include <event2/buffer.h> #include <event2/buffer.h>
#define __LIBTRANSMISSION_VARIANT_MODULE__ #define __LIBTRANSMISSION_VARIANT_MODULE__
@ -34,6 +47,65 @@
*** ***
**/ **/
struct locale_context
{
#ifdef HAVE_USELOCALE
locale_t new_locale;
locale_t old_locale;
#else
#ifdef _WIN32
int old_thread_config;
#endif
int category;
char old_locale[128];
#endif
};
static void
use_numeric_locale (struct locale_context * context,
const char * locale_name)
{
#ifdef HAVE_USELOCALE
context->new_locale = newlocale (LC_NUMERIC_MASK, locale_name, NULL);
context->old_locale = uselocale (context->new_locale);
#else
#ifdef _WIN32
context->old_thread_config = _configthreadlocale (_ENABLE_PER_THREAD_LOCALE);
#endif
context->category = LC_NUMERIC;
tr_strlcpy (context->old_locale, setlocale (context->category, NULL), sizeof (context->old_locale));
setlocale (context->category, locale_name);
#endif
}
static void
restore_locale (struct locale_context * context)
{
#ifdef HAVE_USELOCALE
uselocale (context->old_locale);
freelocale (context->new_locale);
#else
setlocale (context->category, context->old_locale);
#ifdef _WIN32
_configthreadlocale (context->old_thread_config);
#endif
#endif
}
/***
****
***/
static bool static bool
tr_variantIsContainer (const tr_variant * v) tr_variantIsContainer (const tr_variant * v)
{ {
@ -301,14 +373,13 @@ tr_variantGetReal (const tr_variant * v, double * setme)
if (!success && tr_variantIsString (v)) if (!success && tr_variantIsString (v))
{ {
char * endptr; char * endptr;
char locale[128]; struct locale_context locale_ctx;
double d; double d;
/* the json spec requires a '.' decimal point regardless of locale */ /* the json spec requires a '.' decimal point regardless of locale */
tr_strlcpy (locale, setlocale (LC_NUMERIC, NULL), sizeof (locale)); use_numeric_locale (&locale_ctx, "C");
setlocale (LC_NUMERIC, "POSIX");
d = strtod (getStr (v), &endptr); d = strtod (getStr (v), &endptr);
setlocale (LC_NUMERIC, locale); restore_locale (&locale_ctx);
if ((success = (getStr (v) != endptr) && !*endptr)) if ((success = (getStr (v) != endptr) && !*endptr))
*setme = d; *setme = d;
@ -1093,12 +1164,11 @@ tr_variantMergeDicts (tr_variant * target, const tr_variant * source)
struct evbuffer * struct evbuffer *
tr_variantToBuf (const tr_variant * v, tr_variant_fmt fmt) tr_variantToBuf (const tr_variant * v, tr_variant_fmt fmt)
{ {
char lc_numeric[128]; struct locale_context locale_ctx;
struct evbuffer * buf = evbuffer_new(); struct evbuffer * buf = evbuffer_new();
/* parse with LC_NUMERIC="C" to ensure a "." decimal separator */ /* parse with LC_NUMERIC="C" to ensure a "." decimal separator */
tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric)); use_numeric_locale (&locale_ctx, "C");
setlocale (LC_NUMERIC, "C");
evbuffer_expand (buf, 4096); /* alloc a little memory to start off with */ evbuffer_expand (buf, 4096); /* alloc a little memory to start off with */
@ -1118,7 +1188,7 @@ tr_variantToBuf (const tr_variant * v, tr_variant_fmt fmt)
} }
/* restore the previous locale */ /* restore the previous locale */
setlocale (LC_NUMERIC, lc_numeric); restore_locale (&locale_ctx);
return buf; return buf;
} }
@ -1251,11 +1321,10 @@ tr_variantFromBuf (tr_variant * setme,
const char ** setme_end) const char ** setme_end)
{ {
int err; int err;
char lc_numeric[128]; struct locale_context locale_ctx;
/* parse with LC_NUMERIC="C" to ensure a "." decimal separator */ /* parse with LC_NUMERIC="C" to ensure a "." decimal separator */
tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric)); use_numeric_locale (&locale_ctx, "C");
setlocale (LC_NUMERIC, "C");
switch (fmt) switch (fmt)
{ {
@ -1270,6 +1339,6 @@ tr_variantFromBuf (tr_variant * setme,
} }
/* restore the previous locale */ /* restore the previous locale */
setlocale (LC_NUMERIC, lc_numeric); restore_locale (&locale_ctx);
return err; return err;
} }