Fix unintentional locale dependency (#3358)

Avoid unintentional locale dependency

hb_variation_to_string uses sprintf with %g, which will produce
a locale-dependent decimal point, which is not desired here.

The output is supposed to be compatible with CSS syntax, and
that always uses '.' for the decimal point.

Fix this by changing the per-thread locale to "C" around sprintf call.

Fixes https://github.com/harfbuzz/harfbuzz/issues/3355
Fixes https://github.com/harfbuzz/harfbuzz/pull/3357
Fixes https://github.com/harfbuzz/harfbuzz/pull/3358

Co-authored-by: Matthias Clasen <mclasen@redhat.com>
This commit is contained in:
Behdad Esfahbod 2022-01-08 15:47:33 -08:00 committed by GitHub
parent d70825a6d1
commit a45a630539
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 5 deletions

View File

@ -68,8 +68,8 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
])
# Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h)
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale)
AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
# Compiler flags
AC_CANONICAL_HOST

View File

@ -61,6 +61,7 @@ check_headers = [
['unistd.h'],
['sys/mman.h'],
['stdbool.h'],
['xlocale.h'],
]
check_funcs = [
@ -70,6 +71,8 @@ check_funcs = [
['getpagesize'],
['mmap'],
['isatty'],
['uselocale'],
['newlocale'],
]
m_dep = cpp.find_library('m', required: false)

View File

@ -31,6 +31,10 @@
#include <locale.h>
#ifdef HAVE_XLOCALE_H
#include <xlocale.h> // Needed on BSD/OS X for uselocale
#endif
#ifdef HB_NO_SETLOCALE
#define setlocale(Category, Locale) "C"
#endif
@ -122,7 +126,7 @@ hb_tag_from_string (const char *str, int len)
* @tag: #hb_tag_t to convert
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string
*
* Converts an #hb_tag_t to a string and returns it in @buf.
* Converts an #hb_tag_t to a string and returns it in @buf.
* Strings will be four characters long.
*
* Since: 0.9.5
@ -151,13 +155,13 @@ const char direction_strings[][4] = {
* @str: (array length=len) (element-type uint8_t): String to convert
* @len: Length of @str, or -1 if it is %NULL-terminated
*
* Converts a string to an #hb_direction_t.
* Converts a string to an #hb_direction_t.
*
* Matching is loose and applies only to the first letter. For
* examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR.
*
* Unmatched strings will return #HB_DIRECTION_INVALID.
*
*
* Return value: The #hb_direction_t matching @str
*
* Since: 0.9.2
@ -1039,6 +1043,56 @@ hb_variation_from_string (const char *str, int len,
return false;
}
#if !defined(HARFBUZZ_NO_SETLOCALE) && defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE)
#ifdef WIN32
using locale_t = _locale_t;
#endif
static inline void free_static_C_locale ();
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<locale_t>,
hb_C_locale_lazy_loader_t>
{
static locale_t create ()
{
locale_t l = newlocale (LC_ALL_MASK, "C", NULL);
if (!l)
return l;
hb_atexit (free_static_C_locale);
return l;
}
static void destroy (locale_t l)
{
freelocale (l);
}
static locale_t get_null ()
{
return (locale_t) 0;
}
} static_C_locale;
static inline
void free_static_C_locale ()
{
static_C_locale.free_instance ();
}
static locale_t
get_C_locale ()
{
return static_C_locale.get_unconst ();
}
#else
#ifdef WIN32
#define locale_t void *
#endif
#define uselocale(Locale) ((locale_t) 0)
#endif
/**
* hb_variation_to_string:
* @variation: an #hb_variation_t to convert
@ -1064,7 +1118,11 @@ hb_variation_to_string (hb_variation_t *variation,
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
locale_t oldlocale HB_UNUSED;
oldlocale = uselocale (get_C_locale ());
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
(void) uselocale (oldlocale);
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);