Add GNU-compatible strerror_r.
We already had the POSIX strerror_r, but some third-party code defines
_GNU_SOURCE and expects to get the GNU strerror_r instead.
This exposed a bug in the libc internal logging functions where unlike
their standard brethren they wouldn't return the number of bytes they'd
have liked to have written.
Bug: 16243479
Change-Id: I1745752ccbdc569646d34f5071f6df2be066d5f4
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 5655526..49a3762 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -75,10 +75,12 @@
len = strlen(data);
}
+ total += len;
+
while (len > 0) {
int avail = end_ - pos_;
if (avail == 0) {
- break;
+ return;
}
if (avail > len) {
avail = len;
@@ -87,11 +89,10 @@
pos_ += avail;
pos_[0] = '\0';
len -= avail;
- total += avail;
}
}
- int total;
+ size_t total;
private:
char* buffer_;
@@ -109,18 +110,19 @@
len = strlen(data);
}
+ total += len;
+
while (len > 0) {
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
if (rc == -1) {
- break;
+ return;
}
data += rc;
len -= rc;
- total += rc;
}
}
- int total;
+ size_t total;
private:
int fd_;
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
index 1e57cc0..d419fb1 100644
--- a/libc/bionic/strerror_r.cpp
+++ b/libc/bionic/strerror_r.cpp
@@ -1,11 +1,16 @@
/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
/* Public Domain <marc@snafu.org> */
+// G++ automatically defines _GNU_SOURCE, which then means that <string.h>
+// gives us the GNU variant.
+#undef _GNU_SOURCE
+
+#include <string.h>
+
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
-#include <string.h>
#include "private/ErrnoRestorer.h"
#include "private/libc_logging.h"
@@ -62,6 +67,12 @@
return 0;
}
+extern "C" char* __gnu_strerror_r(int error_number, char* buf, size_t buf_len) {
+ ErrnoRestorer errno_restorer; // The glibc strerror_r doesn't set errno if it truncates...
+ strerror_r(error_number, buf, buf_len);
+ return buf; // ...and just returns whatever fit.
+}
+
extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
const char* signal_name = __strsignal_lookup(signal_number);
if (signal_name != NULL) {
diff --git a/libc/include/string.h b/libc/include/string.h
index 0a1d653..b0643af 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -67,8 +67,12 @@
extern char* strtok(char* __restrict, const char* __restrict);
extern char* strtok_r(char* __restrict, const char* __restrict, char** __restrict);
-extern char* strerror(int);
-extern int strerror_r(int errnum, char *buf, size_t n);
+extern char* strerror(int);
+#if defined(__USE_GNU)
+extern char* strerror_r(int, char*, size_t) __RENAME(__gnu_strerror_r);
+#else /* POSIX */
+extern int strerror_r(int, char*, size_t);
+#endif
extern size_t strnlen(const char *, size_t) __purefunc;
extern char* strncat(char* __restrict, const char* __restrict, size_t);