Alexander Samoylov
Alexander Samoylov

Reputation: 2548

Using strerror() twice with different values within one printf() triggers a bug on Windows

According to the Microsoft docs the API char * strerror(int errnum)

"maps errnum to an error-message string and returns a pointer to the string"

On the practice it turned out that there is one important aspect which is not covered by the description:

This is the code which represents this behavior:

printf("---------- print separately [OK] ----------\n");
printf("strerror(1)=(%s), ptr=(%p)\n", strerror(1), strerror(1));
printf("strerror(2)=(%s), ptr=(%p)\n", strerror(2), strerror(2));
printf("---------- print together [BUG] ----------\n");
printf("strerror(1)=(%s), strerror(2)=(%s)\n", strerror(1), strerror(2));
printf("ptr_1=(%p), ptr_2=(%p)\n", strerror(1), strerror(2));
printf("---------- print together, get pointers separately [BUG] ----------\n");
const char * s1 = strerror(1);
const char * s2 = strerror(2);
printf("strerror(1)=(%s), strerror(2)=(%s)\n", s1, s2);
printf("ptr_1=(%p), ptr_2=(%p)\n", s1, s2);
printf("---------- --------------------------- ----------\n");

Output:

---------- print separately [OK] ----------
strerror(1)=(Operation not permitted), ptr=(000002756DE6BD90)
strerror(2)=(No such file or directory), ptr=(000002756DE6BD90)
---------- print together [BUG] ----------
strerror(1)=(Operation not permitted), strerror(2)=(Operation not permitted)
ptr_1=(000002756DE6BD90), ptr_2=(000002756DE6BD90)
---------- print together, get pointers separately [BUG] ----------
strerror(1)=(No such file or directory), strerror(2)=(No such file or directory)
ptr_1=(000002756DE6BD90), ptr_2=(000002756DE6BD90)
---------- --------------------------- ----------

Compiler optimization flags were not used. The same code works properly on Linux with gcc.

UPDATE: The questions are answered.

Q: Is this behavior a BUG?

Q: Is there another better API which works as strerror on Linux?

Upvotes: 3

Views: 220

Answers (3)

Rachid K.
Rachid K.

Reputation: 5201

With GNU C library you would get the same issue as strerror() is using a internal static buffer that is updated with the string corresponding to the error code passed as parameter. This is why strerror() is not multi-thread safe. The MT-safe version is strerror_r() which put the error string in a user allocated buffer instead of the internal static buffer.

Upvotes: 0

dbush
dbush

Reputation: 223689

The memory returned by strerror can be modified by by subsequent calls to the function.

Instead, use strerror_s which allows you to supply a buffer to write the error string to.

char s1[200], s2[200];
strerror_s(s1, sizeof s1, 1);
strerror_s(s2, sizeof s2, 2);

Upvotes: 4

hobbs
hobbs

Reputation: 239682

This isn't a bug. Per the POSIX documentation for strerror:

The returned string pointer might be invalidated or the string content might be overwritten by a subsequent call to strerror()

So if you call it twice in a single statement, you shouldn't expect more than one of the values to be valid (and it would be perfectly acceptable for your code to crash or do other weird things).

The underlying reason is probably because the Microsoft C library is using a single fixed buffer for the strerror return value, so each call overwrites the previous held value. This is specifically allowed by the standard, for ease of implementation.

Upvotes: 4

Related Questions