Skip to content

Commit 929f159

Browse files
committed
Rework libcxx strerror_r handling.
The set of #ifdefs used to handle the two incompatible variants of strerror_r were not complete (they didn't handle newlib appropriately). Rather than attempting to make the ifdefs more complex, make them unnecessary by choosing which behavior to use dependent upon the return type. Reviewers: waltl Differential Revision: https://reviews.llvm.org/D34294 llvm-svn: 308528
1 parent 3610942 commit 929f159

File tree

1 file changed

+46
-26
lines changed

1 file changed

+46
-26
lines changed

libcxx/src/system_error.cpp

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,39 +73,59 @@ string do_strerror_r(int ev) {
7373
std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
7474
return string(buffer);
7575
}
76-
#elif defined(__linux__) && !defined(_LIBCPP_HAS_MUSL_LIBC) && \
77-
(!defined(__ANDROID__) || __ANDROID_API__ >= 23)
78-
// GNU Extended version
79-
string do_strerror_r(int ev) {
80-
char buffer[strerror_buff_size];
81-
char* ret = ::strerror_r(ev, buffer, strerror_buff_size);
82-
return string(ret);
83-
}
8476
#else
85-
// POSIX version
77+
78+
// Only one of the two following functions will be used, depending on
79+
// the return type of strerror_r:
80+
81+
// For the GNU variant, a char* return value:
82+
__attribute__((unused)) const char *
83+
handle_strerror_r_return(char *strerror_return, char *buffer) {
84+
// GNU always returns a string pointer in its return value. The
85+
// string might point to either the input buffer, or a static
86+
// buffer, but we don't care which.
87+
return strerror_return;
88+
}
89+
90+
// For the POSIX variant: an int return value.
91+
__attribute__((unused)) const char *
92+
handle_strerror_r_return(int strerror_return, char *buffer) {
93+
// The POSIX variant either:
94+
// - fills in the provided buffer and returns 0
95+
// - returns a positive error value, or
96+
// - returns -1 and fills in errno with an error value.
97+
if (strerror_return == 0)
98+
return buffer;
99+
100+
// Only handle EINVAL. Other errors abort.
101+
int new_errno = strerror_return == -1 ? errno : strerror_return;
102+
if (new_errno == EINVAL)
103+
return "";
104+
105+
_LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r");
106+
// FIXME maybe? 'strerror_buff_size' is likely to exceed the
107+
// maximum error size so ERANGE shouldn't be returned.
108+
std::abort();
109+
}
110+
111+
// This function handles both GNU and POSIX variants, dispatching to
112+
// one of the two above functions.
86113
string do_strerror_r(int ev) {
87114
char buffer[strerror_buff_size];
115+
// Preserve errno around the call. (The C++ standard requires that
116+
// system_error functions not modify errno).
88117
const int old_errno = errno;
89-
int ret;
90-
if ((ret = ::strerror_r(ev, buffer, strerror_buff_size)) != 0) {
91-
// If `ret == -1` then the error is specified using `errno`, otherwise
92-
// `ret` represents the error.
93-
const int new_errno = ret == -1 ? errno : ret;
94-
errno = old_errno;
95-
if (new_errno == EINVAL) {
96-
std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
97-
return string(buffer);
98-
} else {
99-
_LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerr_r");
100-
// FIXME maybe? 'strerror_buff_size' is likely to exceed the
101-
// maximum error size so ERANGE shouldn't be returned.
102-
std::abort();
103-
}
118+
const char *error_message = handle_strerror_r_return(
119+
::strerror_r(ev, buffer, strerror_buff_size), buffer);
120+
// If we didn't get any message, print one now.
121+
if (!error_message[0]) {
122+
std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
123+
error_message = buffer;
104124
}
105-
return string(buffer);
125+
errno = old_errno;
126+
return string(error_message);
106127
}
107128
#endif
108-
109129
} // end namespace
110130
#endif
111131

0 commit comments

Comments
 (0)