qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] QEMU produces invalid JSON due to locale-dependent code


From: Daniel P. Berrange
Subject: Re: [Qemu-devel] QEMU produces invalid JSON due to locale-dependent code
Date: Wed, 26 Aug 2015 10:22:36 +0100
User-agent: Mutt/1.5.23 (2014-03-12)

On Wed, Aug 26, 2015 at 11:13:00AM +0200, Alberto Garcia wrote:
> On Tue 25 Aug 2015 09:54:42 AM CEST, Markus Armbruster wrote:
> 
> >> (D) Run in a controlled mixed locale
> >>    GTK runs completely in the locale determined by setlocale() (since it
> >> never has to display raw JSON)
> >>    We fix our JSON output code to use thread-specific locale
> >> manipulations to (temporarily) switch to C locale before printing JSON
> >>
> >> that way, GTK still shows full German formatting for any localized
> >> message in the GUI that happens to print numbers, but the JSON output
> >> (which is independent of the GUI) also behaves correctly as a C-only
> >> entity.
> >
> > Switching back to C locale whenever some unwanted locale-dependency
> > breaks the code is problematic, because it involves finding all the
> > places that break, iteratively (euphemism for "we debug one breakage
> > after the other, adding temporary locale switches as we go).
> 
> For some cases we probably don't even need to switch the locale. For the
> JSON case cannot we just easily convert the QFloat into a string
> ourselves without using printf's "%f" ?

FWIW, libvirt had this exact same problem with formatting doubles for
JSON while non-C locales are in effect. We used the glibc thread-local
locale support, and fallback to some sick string munging in non-glibc
case:


/* In case thread-safe locales are available */
#if HAVE_NEWLOCALE

static locale_t virLocale;

static int
virLocaleOnceInit(void)
{
    virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
    if (!virLocale)
        return -1;
    return 0;
}

VIR_ONCE_GLOBAL_INIT(virLocale)
#endif

/**
 * virDoubleToStr
 *
 * converts double to string with C locale (thread-safe).
 *
 * Returns -1 on error, size of the string otherwise.
 */
int
virDoubleToStr(char **strp, double number)
{
    int ret = -1;

#if HAVE_NEWLOCALE

    locale_t old_loc;

    if (virLocaleInitialize() < 0)
        goto error;

    old_loc = uselocale(virLocale);
    ret = virAsprintf(strp, "%lf", number);
    uselocale(old_loc);

#else

    char *radix, *tmp;
    struct lconv *lc;

    if ((ret = virVasprintf(strp, "%lf", number) < 0)
        goto error;

    lc = localeconv();
    radix = lc->decimal_point;
    tmp = strstr(*strp, radix);
    if (tmp) {
        *tmp = '.';
        if (strlen(radix) > 1)
            memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - str));
    }

#endif /* HAVE_NEWLOCALE */
 error:
    return ret;
}


> That doesn't invalidate however your point.
> 
> > I'd feel much better about confining GTK in its own thread, and
> > setting only that thread's locale.
> 
> I haven't digged much into that part of the QEMU code, but if my
> assumptions are true I think we would need at least:
> 
> - A separate GMainContext with its own main loop
> - Making sure that all the code that touches the UI runs from that
>   thread.
> 
> This is in principle possible, but I fear that we might be opening a can
> of worms.

Agreed, my experiance is that you should always run GTK in the main
thread and never try todo anything more clever with threads + GTK.
It has always ended in tears for me - even if you think you have it
working on your system, you'll inevitably find a different version
of GTK where it has broken. It just isn't worth the pain to try to
run anything GTK related in a non-main thread.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|



reply via email to

[Prev in Thread] Current Thread [Next in Thread]