aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetri Lehtinen <petri@digip.org>2024-03-08 21:53:07 +0200
committerGitHub <noreply@github.com>2024-03-08 21:53:07 +0200
commit842708ac0cbf29155cd186a2bf90fa899665b3d9 (patch)
treec663630339ba20e64c0c21b221e7ee47492cdf7e
parent9b9b5e81cf64936207c2081a123fa02dd943916f (diff)
parent2d1c13224f757e780763e205e22fdf0517db82d0 (diff)
downloadjansson-842708ac0cbf29155cd186a2bf90fa899665b3d9.zip
jansson-842708ac0cbf29155cd186a2bf90fa899665b3d9.tar.gz
jansson-842708ac0cbf29155cd186a2bf90fa899665b3d9.tar.bz2
Merge pull request #677 from akheron/ditch-localeconv
Use sprintf() to determine locale's decimal point
-rw-r--r--CHANGES11
-rw-r--r--CMakeLists.txt11
-rw-r--r--android/jansson_config.h4
-rw-r--r--cmake/jansson_config.h.cmake3
-rw-r--r--configure.ac8
-rw-r--r--src/jansson_config.h.in4
-rw-r--r--src/strconv.c36
7 files changed, 29 insertions, 48 deletions
diff --git a/CHANGES b/CHANGES
index f2d26ac..c5853c7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+Version 2.14.1
+==============
+
+Work in progress
+
+* Fixes:
+
+ - Fix thread safety of encoding and decoding when `uselocale` or `newlocale`
+ is used to switch locales inside the threads (#674, #675, #677. Thanks to
+ Bruno Haible the report and help with fixing.)
+
Version 2.14
============
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8788afe..4a93a71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -215,18 +215,7 @@ if (NOT DEFINED JSON_INT_T)
endif ()
endif ()
-
-# If locale.h and localeconv() are available, define to 1, otherwise to 0.
check_include_files (locale.h HAVE_LOCALE_H)
-check_function_exists (localeconv HAVE_LOCALECONV)
-
-if (HAVE_LOCALECONV AND HAVE_LOCALE_H)
- set (JSON_HAVE_LOCALECONV 1)
-else ()
- set (JSON_HAVE_LOCALECONV 0)
-endif()
-
-# check if we have setlocale
check_function_exists(setlocale HAVE_SETLOCALE)
# Check what the inline keyword is.
diff --git a/android/jansson_config.h b/android/jansson_config.h
index 618a0da..448010a 100644
--- a/android/jansson_config.h
+++ b/android/jansson_config.h
@@ -32,10 +32,6 @@
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
-/* If locale.h and localeconv() are available, define to 1,
- otherwise to 0. */
-#define JSON_HAVE_LOCALECONV 0
-
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
diff --git a/cmake/jansson_config.h.cmake b/cmake/jansson_config.h.cmake
index 2f248cb..542e57b 100644
--- a/cmake/jansson_config.h.cmake
+++ b/cmake/jansson_config.h.cmake
@@ -56,9 +56,6 @@
#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@
-/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */
-#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@
-
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@
diff --git a/configure.ac b/configure.ac
index f022eb7..15721f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,7 @@ esac
AC_SUBST([json_inline])
# Checks for library functions.
-AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll])
+AC_CHECK_FUNCS([close getpid gettimeofday open read setlocale sched_yield strtoll])
AC_MSG_CHECKING([for gcc __sync builtins])
have_sync_builtins=no
@@ -74,12 +74,6 @@ case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
esac
AC_SUBST([json_have_long_long])
-case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in
- yesyes) json_have_localeconv=1;;
- *) json_have_localeconv=0;;
-esac
-AC_SUBST([json_have_localeconv])
-
# Features
AC_ARG_ENABLE([urandom],
[AS_HELP_STRING([--disable-urandom],
diff --git a/src/jansson_config.h.in b/src/jansson_config.h.in
index fe692ab..791f60d 100644
--- a/src/jansson_config.h.in
+++ b/src/jansson_config.h.in
@@ -32,10 +32,6 @@
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@
-/* If locale.h and localeconv() are available, define to 1,
- otherwise to 0. */
-#define JSON_HAVE_LOCALECONV @json_have_localeconv@
-
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@
diff --git a/src/strconv.c b/src/strconv.c
index c6f4fd1..7d317dd 100644
--- a/src/strconv.c
+++ b/src/strconv.c
@@ -11,57 +11,57 @@
#include <jansson_private_config.h>
#endif
-#if JSON_HAVE_LOCALECONV
-#include <locale.h>
-
/*
- This code assumes that the decimal separator is exactly one
character.
- If setlocale() is called by another thread between the call to
- localeconv() and the call to sprintf() or strtod(), the result may
- be wrong. setlocale() is not thread-safe and should not be used
- this way. Multi-threaded programs should use uselocale() instead.
+ get_decimal_point() and the call to sprintf() or strtod(), the
+ result may be wrong. setlocale() is not thread-safe and should
+ not be used this way. Multi-threaded programs should use
+ uselocale() instead.
*/
+static char get_decimal_point() {
+ char buf[3];
+ sprintf(buf, "%#.0f", 1.0); // "1." in the current locale
+ return buf[1];
+}
static void to_locale(strbuffer_t *strbuffer) {
- const char *point;
+ char point;
char *pos;
- point = localeconv()->decimal_point;
- if (*point == '.') {
+ point = get_decimal_point();
+ if (point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if (pos)
- *pos = *point;
+ *pos = point;
}
static void from_locale(char *buffer) {
- const char *point;
+ char point;
char *pos;
- point = localeconv()->decimal_point;
- if (*point == '.') {
+ point = get_decimal_point();
+ if (point == '.') {
/* No conversion needed */
return;
}
- pos = strchr(buffer, *point);
+ pos = strchr(buffer, point);
if (pos)
*pos = '.';
}
-#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
double value;
char *end;
-#if JSON_HAVE_LOCALECONV
to_locale(strbuffer);
-#endif
errno = 0;
value = strtod(strbuffer->value, &end);
@@ -92,9 +92,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
if (length >= size)
return -1;
-#if JSON_HAVE_LOCALECONV
from_locale(buffer);
-#endif
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */