Is there any way to get the maximum size of any string correlated with errno
at compile time (at preprocessor time would be even better)? E.g. an upper bound on strlen(strerror(errno))
?
The best I can think of is running a program to do a brute-force search over the range of an int, over each locale, to get the string associated with each {errno, locale} pair, get its size, and generate a header on that system, then hooking that into e.g. a makefile or autoconf or whatever. I can't think of a better way to do it, but it seems ridiculous that it would be so: the standard library for a system has that information built-in, if only implicitly. Is there really no good way to get that information?
Okay, I'll admit the C and/or C++ standards might permit for error strings generated at runtime, with e.g. specific-to-circumstance messages (e.g. strerror(EINVAL)
giving a string derived from other runtime metadata set when errno
was last set, or something) - not sure if that is allowed, and I'd actually welcome such an implementation, but I've never heard of one existing which did so, or had more than one string for a given {errno
, locale} pair.
For context, what I specifically wanted (but I think this question is valuable in a more general way, as was discussed amongst the comments) that led to this question was to be able to use the error string associated with errno
in the syscall/function writev
. In my specific usecase, I was using strings out of argv
and errno
-linked strings. This set my "worst-case" length to ARG_MAX
+ some max errno string length
+ size of a few other small strings
).
Every *nix document I've consulted seems to indicate writev
will (or "may", for what little good that difference makes in this case) error out with errno
set to EINVAL
if the sum of the iov_len
values overflows SSIZE_MAX
. Intuitively, I know every errno
string I've seen is very short, and in practice this is a non-issue. But I don't want my code mysteriously failing to print an error at all on some system if it's possible for this assumption to be false. So I wrote code to handle such a case - but at the same time, I don't want that additional code being compiled in for the platforms which generally clearly don't need it.
The combined input of the answers and comments so far is making me lean towards thinking that in my particular use-case, the "right" solution is to just truncate obscenely long messages - but this is why I asked the question how I did initially: such information would also help select a size for a buffer to strerror_r
/strerror_s
(*nix/Windows respectively), and even a negative answer (e.g. "you can't really do it") is in my view useful for others' education.
This question contains answers for the strings given by strerror_r
on VxWorks, but I don't feel comfortable generalizing that to all systems.
The C library that you build against may not be the same (ABI compatible C library maybe used) or even exact version of the C library (On GNU/Linux consider glibc 2.2.5 vs. glibc 2.23) that you run against, therefore computing the maximum size of the locale-dependent string returned from strerror
can only be done at runtime during process execution. On top of this the locale translations may be updated on the target system at any time, and this again invalidates any pre-computation of this upper bound.
Unfortunately there is no guarantee that the values returned by strerror
are constant for the lifetime of the process, and so they may also change at a later time, thus invalidating any early computation of the bound.
I suggest using strerror_r to save the error string and avoid any issues with non-multi-thread aware libraries that might call sterror and possibly change the result of the string as you are copying it. Then instead of translating the string on-the-fly you would use the saved result, and potentially truncate to SSIZE_MAX
(never going to happen in reality).
I'm not aware that the C or C++ standards make any assertions regarding the length of these messages. The platforms you're interested in might provide some stronger implementation-defined guarantees, though.
For example, for POSIX systems, I found the following in limits.h
.
The following constants shall be defined on all implementations in
<limits.h>
:
- […]
{NL_TEXTMAX}
Maximum number of bytes in a message string.
Minimum Acceptable Value:{_POSIX2_LINE_MAX}
I believe that error messages produced by strerror
would fall into this category.
That said, I'm unable to get this macro on my system. However, I do have _POSIX2_LINE_MAX
(from <unistd.h>
). It is #define
d to 2048. Since the standard only says that this is a lower bound, that might not be too helpful, though.
The standards make no guarantees about the size limits of the null-terminated string returned by strerror
.
In practice, this is never going to be an issue. However, if you're that paranoid about it, I would suggest that you just copy the string returned from strerr
and clamp its length to SSIZE_MAX
before passing it to writev
.
It is safe to assume that SSIZE_MAX
will be greater than the longest string (character array) that strerror returns in a normal C or C++ system. This is because usable system memory (usable directly by your C program) can be no larger than SIZE_MAX
(an unsigned integer value) and SSIZE_MAX
will have at least the same number of bits so using 2's compliment math to account for the signed nature of SSIZE_MAX (and ssize_t) SSIZE_MAX will be at least 1/2 the size of system memory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With