3

Consider the following minimalistic code fragment:

#include <stdio.h>
#include <errno.h>
#include <locale.h>

int main() {
    const char *locale = setlocale(LC_ALL, "");
    if (errno == ENOENT) {
        printf("Locale %s unavailable.\n", locale ? locale : "<unknown>");
    } else if (errno) {
        printf("setlocale() failed: errno = %d\n", errno);
        perror("setlocale() failed");
    }

    if (locale) {
        printf("Current locale: %s\n", locale);
    }

    return errno;
}

This runs successfully on a number of UNIX boxes (Solaris 8, Debian Linux 8, OpenBSD 5.8). There's a few exceptions, however.

According to the manual page, setlocale returns NULL if locale specified by the process environment (LC_ALL et al.) is unavailable (i. e. the corresponding files are missing and need to be generated with localegen or a similar tool). Testing reveals that errno is set to ENOENT in this case, but on one of Debian 7 boxes setlocale returns a valid non-NULL locale string and sets errno to ENOENT.

The other strange behaviour is exhibited by Cygwin: for each of the single-byte Cyrillic locales (ru_RU.CP1251, ru_RU.CP866, ru_RU.KOI8-R, ru_RU.ISO-8859-5), setlocale returns a correct locale string and sets errno to EILSEQ. At the same time, ru_RU.UTF-8 is not affected.

How can any of the above cases be further diagnosed?

fuz
  • 88,405
  • 25
  • 200
  • 352
Bass
  • 4,977
  • 2
  • 36
  • 82
  • 2
    Make sure to set `errno` to zero *before* calling `setlocale` because `setlocale` (just like all POSIX functions) will leave `errno` unchanged if it is successful. – fuz Nov 12 '15 at 10:01
  • @FUZxxl: thanks, forgot that, but setting `errno` to 0 before `setlocale` invocation doesn't change the whole picture: I still get `ENOENT` and `EILSEQ` for valid and available locales. – Bass Nov 12 '15 at 10:10
  • @FUZxxl That is not true at all. POSIX explicitly says: "The setting of errno after a successful call to a function is unspecified unless the description of that function specifies that errno shall not be modified." `setlocale` doesn't say that it won't change errno, so it is allowed to do so. – Art Nov 12 '15 at 11:09
  • @Art Okay, seems like I was misinformed in this regard. – fuz Nov 12 '15 at 11:15

2 Answers2

1

POSIX does not specify how setlocale affects errno (see section ERRORS where it says “no errors are specified”). You can safely disregard the value of errno after a setlocale call.

An implementation of setlocale should never touch errno, but it seems like some of the implementations you tested are buggy in this regard. I recommend you to file a bug report against the projects that supplied the faulty setlocale implementation.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • I'm pretty sure *Cygwin*'s `setlocale` implementation raises `EILSEQ` because of the underlying call to `iconv`. – Bass Nov 12 '15 at 10:27
  • 1
    To be more precise: *The value of errno shall be defined only after a call to a function for which it is explicitly stated to be set and until it is changed by the next function call or if the application assigns it a value. The value of errno should only be examined when it is indicated to be valid by a function's return value.* http://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html#tag_16_110 Since most functions specify something like *the functions shall return -1 and set errno to indicate the error* (from `read`), `errno` will be indeterminate unless the call failed. – Andrew Henle Nov 12 '15 at 10:43
  • 1
    So in this case, since the `setlocale()` call does not explicitly set `errno` when it succeeds, the value of `errno` is undefined. Even setting it to zero before calling `setlocale()` wouldn't guarantee its value after the call. – Andrew Henle Nov 12 '15 at 10:49
1

In general when it comes to most functions from POSIX you are not supposed to look at errno unless the function returned an error.

POSIX documents it here.

The value of errno should only be examined when it is indicated to be valid by a function's return value.

Functions are allowed to change errno even when they succeed:

The setting of errno after a successful call to a function is unspecified unless the description of that function specifies that errno shall not be modified.

This happens quite commonly where a function tries one thing, that fails, tries another thing and that succeeds. It's often too expensive or too hard to preserve errno around system calls in libraries.

Looking at errno without the function signaling an error to you is a bug, you can't do that.

Art
  • 19,807
  • 1
  • 34
  • 60