Reputation: 3726
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?
I've been told that C and/or C++ standards don't permit errno strings to be generated at runtime, with specific-to-circumstance messages (for example, strerror(EINVAL)
also using other metadata which was set at the same time as errno
), and I've never heard of an implementation like that.
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 my constant small error message
).
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, it seemed better to exclude that code on platforms which 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 do it") is educational.
This question contains answers for the strings given by strerror_r
on VxWorks, but I don't feel comfortable generalizing that to all systems.
Upvotes: 18
Views: 2372
Reputation:
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
.
Upvotes: 3
Reputation: 25409
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.
Upvotes: 6
Reputation: 12382
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.
Upvotes: 2
Reputation: 614
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).
Upvotes: 17