Bug 15459 - RFE: Add |localeconv_l()| to allow porting of FreeBSD/OSX applications...
Summary: RFE: Add |localeconv_l()| to allow porting of FreeBSD/OSX applications...
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: locale (show other bugs)
Version: unspecified
: P2 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 15634 15732 (view as bug list)
Depends on:
Blocks:
 
Reported: 2013-05-11 01:18 UTC by Roland Mainz
Modified: 2015-08-27 22:14 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Roland Mainz 2013-05-11 01:18:15 UTC
RFE: Add |localeconv_l()| to allow porting of FreeBSD/OSX applications.

|localeconv_l()| is the same as |localeconv()| but takes a pointer to a |locale_t| (see https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/localeconv_l.3.html)

The function is needed so different locales can be used simultaneously in the same thread or different threads within shared libraries (|uselocale()| should not be used in such cases since it affects the current thread's locale settings (bad behaviour for a shared library) and there is no way to get/save/restore the currently used |locale_t| for a given thread (so even if |uselocale()| is used there is no way to restore the previous setting)).
Comment 1 Carlos O'Donell 2013-05-11 03:26:21 UTC
Interesting feature request. Thanks for filing the issue. I'd say that right now we don't have the community resources to field something like this, but we'd be happy to review a patch.
Comment 2 Rich Felker 2013-05-11 23:44:14 UTC
The bug reporter's claims about uselocale are blatantly false. The whole point of uselocale is that you can save, change, and restore the (thread-local) locale safely from library code. The return value of uselocale is a locale_t value representing the old locale, which can be restored by passing it back to uselocale before returning from your library function. See http://pubs.opengroup.org/onlinepubs/9699919799/functions/uselocale.html

With that said, unless someone is interesting in liaising with the Austin Group to get additional *_l functions added to Issue 8, I think it's harmful to keep adding them. To be portable, applications have to include fallback code (#if !defined(HAVE_LOCALECONV_L), etc.) using uselocale anyway.

Assuming applications/libraries have this code for using uselocale, the only reasonable motivation for a new *_l function would be that the uselocale approach is prohibitive from a performance standpoint. I don't see that applying to localeconv since it just returns data that's constant for the locale. You can simply call it once and save the results (either the full result or just the part(s) you need).
Comment 3 Carlos O'Donell 2013-05-14 14:17:13 UTC
Rich,

My primary desire would be to enable more seamless porting of BSD/OSX applications by supporting more BSD interfaces, regardless of truth of the rationale provided.

Why do you think it harmful to add localeconv_l()?

Why must programs have uselocale() fallbacks? They don't have to, they may never have been ported from BSD, and they might only be expected to work when localeconv_l is present. Compiling such a program with a new enough glibc with localeconv_l would just work, and that would be good.
Comment 4 Rich Felker 2013-05-14 17:02:26 UTC
By harmful, I meant harmful to portability and/or application simplicity. If there's already a simple, portable way to do something that doesn't have excessive cost, adding a second way to do it means an application will take one of three paths:

1. Using the portable way and ignoring the availability of the non-portable one.

2. Adding configure checks and #ifdefs to use the new way optionally.

3. Using the new non-portable way unconditionally.

Of these, I would consider option 1 the best for applications, since it minimizes complexity and maximizes compatibility. Option 2 risks bitrot in the code path that's not taken on the developers' systems. Option 3 means the program can only be used on BSD and GNU systems.

Now if GNU is the only major system lacking this interface, or if other vendors are equally interested and willing to add it, then a path towards standardization, with applications using option 2 above and gradually phasing out the old option as implementations adopt the new interface(s), would be very reasonable. Actually glibc and BSD already have a number of *_l functions outside the ones standardized in POSIX 2008, so if this is the approach you want to take, it would be good to see if the committee is opposed to adding them all in Issue 8, and if not, doing the work to get them added (which basically amounts to writing the proposed text for the standard).
Comment 5 Carlos O'Donell 2013-05-14 19:02:07 UTC
(In reply to comment #4)
> By harmful, I meant harmful to portability and/or application simplicity. If
> there's already a simple, portable way to do something that doesn't have
> excessive cost, adding a second way to do it means an application will take one
> of three paths:
> 
> 1. Using the portable way and ignoring the availability of the non-portable
> one.
> 
> 2. Adding configure checks and #ifdefs to use the new way optionally.
> 
> 3. Using the new non-portable way unconditionally.

Rich, Thanks for clarifying. That makes sense.
Comment 6 Roland Mainz 2013-05-14 21:50:37 UTC
Erm... we're talking about a shared library here. Shared libraries are usually not supposed to change the thread-local or global variables of a caller, even temporary (unless documented and _needed_), because (for example) a consumer calls your library, the library switches thread-local locale using |uselocale()| and then something like a signal handler setup by the caller gets executed you're ending-up running it with the "wrong" locale...

... and don't get me started with the performance implications of wrapping _every_ library call with |saved_locale=uselocale(mylocale); ... ; (void)uselocale(saved_locale);|
Comment 7 Rich Felker 2013-05-14 22:07:11 UTC
Of course libraries can save and restore the locale with uselocale. That's the whole point of the uselocale function. There is NO WAY this can affect correct code, because if your library is using locale, it's calling functions that are async-signal-unsafe, and thus signal handlers that interrupt your library can only call async-signal-safe functions. There are no async-signal-safe functions whose behavior depends on locale; in fact this is one of the contraindications for specifying a function to be async-signal-safe.

> ... and don't get me started with the performance implications of wrapping
> _every_ library call with |saved_locale=uselocale(mylocale); ... ;
> (void)uselocale(saved_locale);|

Have you measured the performance implications? In any case, nobody said to wrap every single library call. A number of *_l functions exist, especially for functions like is*_l which are expected to have very short runtime and for which cycling uselocale would be proportionally high overhead. As already noted, localeconv returns data which is _constant_ for the locale in question, and thus there's no need to call it more than a small finite number of times.

I am not 100% opposed to adding more *_l functions, but your arguments for doing so, so far, are a mix of invalid (the library-safety issue) and unconvincing (the performance issue).
Comment 8 Rich Felker 2013-06-16 04:30:31 UTC
*** Bug 15634 has been marked as a duplicate of this bug. ***
Comment 9 Carlos O'Donell 2013-07-12 01:47:20 UTC
*** Bug 15732 has been marked as a duplicate of this bug. ***
Comment 10 Wendy Llin 2013-07-12 02:44:06 UTC
Has anyone found a practical workaround for this problem? The "workarounds" described here are useless because they come either with a dramatic performance penalty or require major design changes in the application libraries.
Comment 11 Wendy Llin 2013-07-12 02:54:44 UTC
(In reply to Jakub Jelinek from comment #2)
> Just use
> locale_t old = uselocale (l);
> res = localeinfo (...);
> uselocale (old);
> instead.  It doesn't make sense to add *_l variant to every library function.

The workaround is useless. On OSX uselocale() is expensive (~ 200 times the time of a single malloc(100)) and adding manual code to copy the data requires a free function which requires a API redesign.

From a point of portability we would have to create different code paths, one for OSX/FreeBSD/AIX/Solaris 11.1/Illumos and one for Linux. That expense doesn't pay off.
Comment 12 Rich Felker 2013-07-12 03:20:45 UTC
> The workaround is useless. On OSX uselocale() is expensive (~ 200 times the
> time of a single malloc(100)) and adding manual code to copy the data requires
> a free function which requires a API redesign.

Then this seems like a bug in OSX, not glibc. The whole point of
uselocale is to be able to use it like this. If it's prohibitively
slow, that's a serious QoI issue. If it's also slow on glibc, then the
slowness, not the lack of the *_l function, is the bug that should be
addressed.

> From a point of portability we would have to create different code paths, one
> for OSX/FreeBSD/AIX/Solaris 11.1/Illumos and one for Linux. That expense
> doesn't pay off.

I don't see how this is a problem. If the *_l function exists, use it.
If not, provide your own implementation of the *_l function as a
wrapper around the non-_l version using uselocale.
Comment 13 Jakub Jelinek 2013-07-12 05:25:16 UTC
(In reply to Rich Felker from comment #12)
> > The workaround is useless. On OSX uselocale() is expensive (~ 200 times the
> > time of a single malloc(100)) and adding manual code to copy the data requires
> > a free function which requires a API redesign.
> 
> Then this seems like a bug in OSX, not glibc. The whole point of
> uselocale is to be able to use it like this. If it's prohibitively
> slow, that's a serious QoI issue. If it's also slow on glibc, then the
> slowness, not the lack of the *_l function, is the bug that should be
> addressed.

Yeah, that sounds like a serious flaw in OSX (one of many), even on very slow Linux box I can run 100000000 uselocale calls in a second.
If uselocale is so slow on OSX, then it doesn't surprise me they wanted to add functions like localeconv_l, but the whole point of uselocale is that it is very fast and *_l functions are there mainly for APIs that are often implemented inline and just dereference some data pointed by the locale_t handle.