2
char *strerror_r(int errnum, char *buf, size_t buflen);

What are these buf/buflen parameters for?

Empty buffer works like a charm:

char* buf = nullptr;
fprintf(stderr, strerror_r(errno, buf, 0));

Also this buffer looks like unused:

char buf[1024];
fprintf(stderr, "%s\n", strerror_r(errno, buf, sizeof buf)); // Correct message here
fprintf(stderr, "%s\n", buf); // Empty
vp_arth
  • 14,461
  • 4
  • 37
  • 66

2 Answers2

3

Quoting from the man page, emphasis mine

The GNU-specific strerror_r() returns a pointer to a string containing the error message. This may be either a pointer to a string that the function stores in buf, or a pointer to some (immutable) static string (in which case buf is unused).

So it is very much possible that buf is left unused and in case, buf is unused, the buflen does not matter.

[....] If the function stores a string in buf, then at most buflen bytes are stored (the string may be truncated if buflen is too small and errnum is unknown). [...]

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • So, is it used only for `Unknown error errno` messages? And I still can use return value to access it, right? – vp_arth Dec 30 '16 at 05:53
  • 2
    It's probably only used if/when needed. The `_r` suffix usually means *reentrant*, so perhaps in the presence of threads it will be used. – Iharob Al Asimi Dec 30 '16 at 05:54
  • I was mean `buffer memory` by "it used", not `strerror_r` – vp_arth Dec 30 '16 at 05:55
  • presence of threads changes nothing: [cpp.sh](http://cpp.sh/2l7f6). I just what to know: are there any buffer using messages, that longer than `Unknown error %int%`, or I can use, say `char buf[30]` to not truncate anything? – vp_arth Dec 30 '16 at 06:19
2

As you noticed in comments, buf and buflen parameters is used only if you pass invalid errnum, negative or unknown errno value. This is confirmed by the source code of the function.

char *
__strerror_r (int errnum, char *buf, size_t buflen)
{
  if (__builtin_expect (errnum < 0 || errnum >= _sys_nerr_internal
                        || _sys_errlist_internal[errnum] == NULL, 0))
    {
      /* To fill up buf with "Unknown error" localized string and to append
         digits of errnum. Nothing happens if buflen equals zero. */

      ...

      return buf;
    }

  return (char *) _(_sys_errlist_internal[errnum]);
}

In relation capacity of the buffer, I think 1024 bytes will be enough. Moreover, it's the exact same size which strerror implementation uses (that's thread unsafe). See also the related answer and the comment to it.

Of course, it all is concern of GNU-version of the function. XSI-compliant version always uses this buffer for copy of a static string.

Community
  • 1
  • 1
mymedia
  • 572
  • 6
  • 26
  • Can you point, why 32 bytes is not enough? `"Unknown error %d"` never exceeds it... Oh, key is `localized string`. It can be some longer in other locales. Am I right? – vp_arth Mar 06 '17 at 08:23
  • 1
    Yeah. For example, if you set Russian locale, this string will be translated as `"Неизвестная ошибка"`, which occupies 35 bytes in UTF-8 encoding. Also add to it 11 symbols (minimum value of **int** contains at least 10 digits and minus sign, but **__strerror_r** reserves 20 characters for this purpose). – mymedia Mar 06 '17 at 08:37