Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • On Windows the same pointer for different values of errnum is used. It caused unexpected behavior: strerror() with different errnum in one printf() shows the same value!

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?

  • NO.

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

  • YES. strerror_s.
like image 671
Alexander Samoylov Avatar asked Dec 06 '25 11:12

Alexander Samoylov


1 Answers

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.

like image 65
hobbs Avatar answered Dec 09 '25 02:12

hobbs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!