Reputation: 19384
I'm fixing some Linux code which used strerror
(not thread-safe) for multi-threading. I found that strerror_r
and strerror_l
are both thread-safe. Due to different definitions for strerror_r
(depending on _GNU_SOURCE
it is differently defined) I'd like to use the newer strerror_l
function, but how am I supposed to obtain a locale_t
object for the current locale? I'm not using iconv
or anything, just plain libc, and I don't see how I can obtain a "default locale" object (I don't care in what language the error is printed, I just want a human readable string.)
Upvotes: 10
Views: 2020
Reputation: 494
If you pass "" to the locale parameter newlocale will allocate a locale object set to the current native locale[1]
[1]http://pubs.opengroup.org/onlinepubs/9699919799/functions/newlocale.html
static locale_t locale;
bool MyStrerrorInit(void)
{
locale = newlocale(LC_ALL_MASK,"",(locale_t)0);
if (locale == (locale_t)0) {
return false;
}
return true;
}
char * MyStrerror(int error)
{
return strerror_l(error, locale);
}
Upvotes: 4
Reputation: 1830
You could use POSIX uselocale
:
strerror_l(errno, uselocale((locate_t)0));
@TavianBarnes pointed out in the comment that this code can exhibit undefined behavior:
[CX] [Option Start] The behavior is undefined if the locale argument to strerror_l() is the special locale object LC_GLOBAL_LOCALE or is not a valid locale object handle. [Option End]
https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html
Upon successful completion, the uselocale() function shall return a handle for the thread-local locale that was in use as the current locale for the calling thread on entry to the function, or LC_GLOBAL_LOCALE if no thread-local locale was in use.
https://pubs.opengroup.org/onlinepubs/9699919799/functions/uselocale.html
Use of LC_GLOBAL_LOCALE with *_l() functions clarified the UB behavior of *_l()
functions when given LC_GLOBAL_LOCALE
as the locale
, provided a version without undefined behavior and discussed alternatives.
An obvious version that isn't thread safe:
locale_t locale = uselocale((locate_t)0);
if (locale == LC_GLOBAL_LOCALE) {
strerror(errno);
} else {
strerror_l(errno, locale);
}
A thread-safe version:
locale_t locale = uselocale((locate_t)0);
locale_t copy = loc;
if (copy == LC_GLOBAL_LOCALE) {
copy = duplocale(copy);
}
strerror_l(errno, copy);
if (loc == LC_GLOBAL_LOCALE) {
freelocale(copy);
}
Here's a full working example from @TavianBarnes.
Upvotes: 5