@@ -73,39 +73,59 @@ string do_strerror_r(int ev) {
73
73
std::snprintf (buffer, strerror_buff_size, " unknown error %d" , ev);
74
74
return string (buffer);
75
75
}
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
- }
84
76
#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.
86
113
string do_strerror_r (int ev) {
87
114
char buffer[strerror_buff_size];
115
+ // Preserve errno around the call. (The C++ standard requires that
116
+ // system_error functions not modify errno).
88
117
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;
104
124
}
105
- return string (buffer);
125
+ errno = old_errno;
126
+ return string (error_message);
106
127
}
107
128
#endif
108
-
109
129
} // end namespace
110
130
#endif
111
131
0 commit comments