Reduce strerror(3)'s impact on .data.rel.ro.
Test: tests pass
Change-Id: I60b15dfac6ca7dce45f4858ad10b8255e2f1b66d
diff --git a/libc/Android.bp b/libc/Android.bp
index 6b46ba0..2a2c763 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1142,7 +1142,6 @@
"bionic/stdlib_l.cpp",
"bionic/strchrnul.cpp",
"bionic/strerror.cpp",
- "bionic/strerror_r.cpp",
"bionic/string_l.cpp",
"bionic/strings_l.cpp",
"bionic/strsignal.cpp",
diff --git a/libc/bionic/strerror.cpp b/libc/bionic/strerror.cpp
index 99692ca..38d8191 100644
--- a/libc/bionic/strerror.cpp
+++ b/libc/bionic/strerror.cpp
@@ -26,11 +26,188 @@
* SUCH DAMAGE.
*/
+// 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 <async_safe/log.h>
+
+#include "private/ErrnoRestorer.h"
+
#include <string.h>
#include "bionic/pthread_internal.h"
-extern "C" const char* __strerror_lookup(int);
+static const char* __sys_error_strings[] = {
+ [0] = "Success",
+ [EPERM] = "Operation not permitted",
+ [ENOENT] = "No such file or directory",
+ [ESRCH] = "No such process",
+ [EINTR] = "Interrupted system call",
+ [EIO] = "I/O error",
+ [ENXIO] = "No such device or address",
+ [E2BIG] = "Argument list too long",
+ [ENOEXEC] = "Exec format error",
+ [EBADF] = "Bad file descriptor",
+ [ECHILD] = "No child processes",
+ [EAGAIN] = "Try again",
+ [ENOMEM] = "Out of memory",
+ [EACCES] = "Permission denied",
+ [EFAULT] = "Bad address",
+ [ENOTBLK] = "Block device required",
+ [EBUSY] = "Device or resource busy",
+ [EEXIST] = "File exists",
+ [EXDEV] = "Cross-device link",
+ [ENODEV] = "No such device",
+ [ENOTDIR] = "Not a directory",
+ [EISDIR] = "Is a directory",
+ [EINVAL] = "Invalid argument",
+ [ENFILE] = "File table overflow",
+ [EMFILE] = "Too many open files",
+ [ENOTTY] = "Not a typewriter",
+ [ETXTBSY] = "Text file busy",
+ [EFBIG] = "File too large",
+ [ENOSPC] = "No space left on device",
+ [ESPIPE] = "Illegal seek",
+ [EROFS] = "Read-only file system",
+ [EMLINK] = "Too many links",
+ [EPIPE] = "Broken pipe",
+ [EDOM] = "Math argument out of domain of func",
+ [ERANGE] = "Math result not representable",
+ [EDEADLK] = "Resource deadlock would occur",
+ [ENAMETOOLONG] = "File name too long",
+ [ENOLCK] = "No record locks available",
+ [ENOSYS] = "Function not implemented",
+ [ENOTEMPTY] = "Directory not empty",
+ [ELOOP] = "Too many symbolic links encountered",
+ [ENOMSG] = "No message of desired type",
+ [EIDRM] = "Identifier removed",
+ [ECHRNG] = "Channel number out of range",
+ [EL2NSYNC] = "Level 2 not synchronized",
+ [EL3HLT] = "Level 3 halted",
+ [EL3RST] = "Level 3 reset",
+ [ELNRNG] = "Link number out of range",
+ [EUNATCH] = "Protocol driver not attached",
+ [ENOCSI] = "No CSI structure available",
+ [EL2HLT] = "Level 2 halted",
+ [EBADE] = "Invalid exchange",
+ [EBADR] = "Invalid request descriptor",
+ [EXFULL] = "Exchange full",
+ [ENOANO] = "No anode",
+ [EBADRQC] = "Invalid request code",
+ [EBADSLT] = "Invalid slot",
+ [EBFONT] = "Bad font file format",
+ [ENOSTR] = "Device not a stream",
+ [ENODATA] = "No data available",
+ [ETIME] = "Timer expired",
+ [ENOSR] = "Out of streams resources",
+ [ENONET] = "Machine is not on the network",
+ [ENOPKG] = "Package not installed",
+ [EREMOTE] = "Object is remote",
+ [ENOLINK] = "Link has been severed",
+ [EADV] = "Advertise error",
+ [ESRMNT] = "Srmount error",
+ [ECOMM] = "Communication error on send",
+ [EPROTO] = "Protocol error",
+ [EMULTIHOP] = "Multihop attempted",
+ [EDOTDOT] = "RFS specific error",
+ [EBADMSG] = "Not a data message",
+ [EOVERFLOW] = "Value too large for defined data type",
+ [ENOTUNIQ] = "Name not unique on network",
+ [EBADFD] = "File descriptor in bad state",
+ [EREMCHG] = "Remote address changed",
+ [ELIBACC] = "Can not access a needed shared library",
+ [ELIBBAD] = "Accessing a corrupted shared library",
+ [ELIBSCN] = ".lib section in a.out corrupted",
+ [ELIBMAX] = "Attempting to link in too many shared libraries",
+ [ELIBEXEC] = "Cannot exec a shared library directly",
+ [EILSEQ] = "Illegal byte sequence",
+ [ERESTART] = "Interrupted system call should be restarted",
+ [ESTRPIPE] = "Streams pipe error",
+ [EUSERS] = "Too many users",
+ [ENOTSOCK] = "Socket operation on non-socket",
+ [EDESTADDRREQ] = "Destination address required",
+ [EMSGSIZE] = "Message too long",
+ [EPROTOTYPE] = "Protocol wrong type for socket",
+ [ENOPROTOOPT] = "Protocol not available",
+ [EPROTONOSUPPORT] = "Protocol not supported",
+ [ESOCKTNOSUPPORT] = "Socket type not supported",
+ [EOPNOTSUPP] = "Operation not supported on transport endpoint",
+ [EPFNOSUPPORT] = "Protocol family not supported",
+ [EAFNOSUPPORT] = "Address family not supported by protocol",
+ [EADDRINUSE] = "Address already in use",
+ [EADDRNOTAVAIL] = "Cannot assign requested address",
+ [ENETDOWN] = "Network is down",
+ [ENETUNREACH] = "Network is unreachable",
+ [ENETRESET] = "Network dropped connection because of reset",
+ [ECONNABORTED] = "Software caused connection abort",
+ [ECONNRESET] = "Connection reset by peer",
+ [ENOBUFS] = "No buffer space available",
+ [EISCONN] = "Transport endpoint is already connected",
+ [ENOTCONN] = "Transport endpoint is not connected",
+ [ESHUTDOWN] = "Cannot send after transport endpoint shutdown",
+ [ETOOMANYREFS] = "Too many references: cannot splice",
+ [ETIMEDOUT] = "Connection timed out",
+ [ECONNREFUSED] = "Connection refused",
+ [EHOSTDOWN] = "Host is down",
+ [EHOSTUNREACH] = "No route to host",
+ [EALREADY] = "Operation already in progress",
+ [EINPROGRESS] = "Operation now in progress",
+ [ESTALE] = "Stale NFS file handle",
+ [EUCLEAN] = "Structure needs cleaning",
+ [ENOTNAM] = "Not a XENIX named type file",
+ [ENAVAIL] = "No XENIX semaphores available",
+ [EISNAM] = "Is a named type file",
+ [EREMOTEIO] = "Remote I/O error",
+ [EDQUOT] = "Quota exceeded",
+ [ENOMEDIUM] = "No medium found",
+ [EMEDIUMTYPE] = "Wrong medium type",
+ [ECANCELED] = "Operation Canceled",
+ [ENOKEY] = "Required key not available",
+ [EKEYEXPIRED] = "Key has expired",
+ [EKEYREVOKED] = "Key has been revoked",
+ [EKEYREJECTED] = "Key was rejected by service",
+ [EOWNERDEAD] = "Owner died",
+ [ENOTRECOVERABLE] = "State not recoverable",
+ [ERFKILL] = "Operation not possible due to RF-kill",
+ [EHWPOISON] = "Memory page has hardware error",
+};
+
+static inline const char* __strerror_lookup(int error_number) {
+ if (error_number < 0 || error_number >= static_cast<int>(arraysize(__sys_error_strings))) {
+ return nullptr;
+ }
+ return __sys_error_strings[error_number];
+}
+
+int strerror_r(int error_number, char* buf, size_t buf_len) {
+ ErrnoRestorer errno_restorer;
+ size_t length;
+
+ const char* error_name = __strerror_lookup(error_number);
+ if (error_name != nullptr) {
+ length = strlcpy(buf, error_name, buf_len);
+ } else {
+ length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
+ }
+ if (length >= buf_len) {
+ errno_restorer.override(ERANGE);
+ return -1;
+ }
+
+ 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.
+}
char* strerror(int error_number) {
// Just return the original constant in the easy cases.
diff --git a/libc/bionic/strerror_r.cpp b/libc/bionic/strerror_r.cpp
deleted file mode 100644
index 326d4b1..0000000
--- a/libc/bionic/strerror_r.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/* $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 <async_safe/log.h>
-
-#include "private/ErrnoRestorer.h"
-
-struct Pair {
- int code;
- const char* msg;
-};
-
-static const char* __code_string_lookup(const Pair* strings, int code) {
- for (size_t i = 0; strings[i].msg != nullptr; ++i) {
- if (strings[i].code == code) {
- return strings[i].msg;
- }
- }
- return nullptr;
-}
-
-static const Pair _sys_error_strings[] = {
- {0, "Success"},
- {EPERM, "Operation not permitted"},
- {ENOENT, "No such file or directory"},
- {ESRCH, "No such process"},
- {EINTR, "Interrupted system call"},
- {EIO, "I/O error"},
- {ENXIO, "No such device or address"},
- {E2BIG, "Argument list too long"},
- {ENOEXEC, "Exec format error"},
- {EBADF, "Bad file descriptor"},
- {ECHILD, "No child processes"},
- {EAGAIN, "Try again"},
- {ENOMEM, "Out of memory"},
- {EACCES, "Permission denied"},
- {EFAULT, "Bad address"},
- {ENOTBLK, "Block device required"},
- {EBUSY, "Device or resource busy"},
- {EEXIST, "File exists"},
- {EXDEV, "Cross-device link"},
- {ENODEV, "No such device"},
- {ENOTDIR, "Not a directory"},
- {EISDIR, "Is a directory"},
- {EINVAL, "Invalid argument"},
- {ENFILE, "File table overflow"},
- {EMFILE, "Too many open files"},
- {ENOTTY, "Not a typewriter"},
- {ETXTBSY, "Text file busy"},
- {EFBIG, "File too large"},
- {ENOSPC, "No space left on device"},
- {ESPIPE, "Illegal seek"},
- {EROFS, "Read-only file system"},
- {EMLINK, "Too many links"},
- {EPIPE, "Broken pipe"},
- {EDOM, "Math argument out of domain of func"},
- {ERANGE, "Math result not representable"},
- {EDEADLK, "Resource deadlock would occur"},
- {ENAMETOOLONG, "File name too long"},
- {ENOLCK, "No record locks available"},
- {ENOSYS, "Function not implemented"},
- {ENOTEMPTY, "Directory not empty"},
- {ELOOP, "Too many symbolic links encountered"},
- {ENOMSG, "No message of desired type"},
- {EIDRM, "Identifier removed"},
- {ECHRNG, "Channel number out of range"},
- {EL2NSYNC, "Level 2 not synchronized"},
- {EL3HLT, "Level 3 halted"},
- {EL3RST, "Level 3 reset"},
- {ELNRNG, "Link number out of range"},
- {EUNATCH, "Protocol driver not attached"},
- {ENOCSI, "No CSI structure available"},
- {EL2HLT, "Level 2 halted"},
- {EBADE, "Invalid exchange"},
- {EBADR, "Invalid request descriptor"},
- {EXFULL, "Exchange full"},
- {ENOANO, "No anode"},
- {EBADRQC, "Invalid request code"},
- {EBADSLT, "Invalid slot"},
- {EBFONT, "Bad font file format"},
- {ENOSTR, "Device not a stream"},
- {ENODATA, "No data available"},
- {ETIME, "Timer expired"},
- {ENOSR, "Out of streams resources"},
- {ENONET, "Machine is not on the network"},
- {ENOPKG, "Package not installed"},
- {EREMOTE, "Object is remote"},
- {ENOLINK, "Link has been severed"},
- {EADV, "Advertise error"},
- {ESRMNT, "Srmount error"},
- {ECOMM, "Communication error on send"},
- {EPROTO, "Protocol error"},
- {EMULTIHOP, "Multihop attempted"},
- {EDOTDOT, "RFS specific error"},
- {EBADMSG, "Not a data message"},
- {EOVERFLOW, "Value too large for defined data type"},
- {ENOTUNIQ, "Name not unique on network"},
- {EBADFD, "File descriptor in bad state"},
- {EREMCHG, "Remote address changed"},
- {ELIBACC, "Can not access a needed shared library"},
- {ELIBBAD, "Accessing a corrupted shared library"},
- {ELIBSCN, ".lib section in a.out corrupted"},
- {ELIBMAX, "Attempting to link in too many shared libraries"},
- {ELIBEXEC, "Cannot exec a shared library directly"},
- {EILSEQ, "Illegal byte sequence"},
- {ERESTART, "Interrupted system call should be restarted"},
- {ESTRPIPE, "Streams pipe error"},
- {EUSERS, "Too many users"},
- {ENOTSOCK, "Socket operation on non-socket"},
- {EDESTADDRREQ, "Destination address required"},
- {EMSGSIZE, "Message too long"},
- {EPROTOTYPE, "Protocol wrong type for socket"},
- {ENOPROTOOPT, "Protocol not available"},
- {EPROTONOSUPPORT, "Protocol not supported"},
- {ESOCKTNOSUPPORT, "Socket type not supported"},
- {EOPNOTSUPP, "Operation not supported on transport endpoint"},
- {EPFNOSUPPORT, "Protocol family not supported"},
- {EAFNOSUPPORT, "Address family not supported by protocol"},
- {EADDRINUSE, "Address already in use"},
- {EADDRNOTAVAIL, "Cannot assign requested address"},
- {ENETDOWN, "Network is down"},
- {ENETUNREACH, "Network is unreachable"},
- {ENETRESET, "Network dropped connection because of reset"},
- {ECONNABORTED, "Software caused connection abort"},
- {ECONNRESET, "Connection reset by peer"},
- {ENOBUFS, "No buffer space available"},
- {EISCONN, "Transport endpoint is already connected"},
- {ENOTCONN, "Transport endpoint is not connected"},
- {ESHUTDOWN, "Cannot send after transport endpoint shutdown"},
- {ETOOMANYREFS, "Too many references: cannot splice"},
- {ETIMEDOUT, "Connection timed out"},
- {ECONNREFUSED, "Connection refused"},
- {EHOSTDOWN, "Host is down"},
- {EHOSTUNREACH, "No route to host"},
- {EALREADY, "Operation already in progress"},
- {EINPROGRESS, "Operation now in progress"},
- {ESTALE, "Stale NFS file handle"},
- {EUCLEAN, "Structure needs cleaning"},
- {ENOTNAM, "Not a XENIX named type file"},
- {ENAVAIL, "No XENIX semaphores available"},
- {EISNAM, "Is a named type file"},
- {EREMOTEIO, "Remote I/O error"},
- {EDQUOT, "Quota exceeded"},
- {ENOMEDIUM, "No medium found"},
- {EMEDIUMTYPE, "Wrong medium type"},
- {ECANCELED, "Operation Canceled"},
- {ENOKEY, "Required key not available"},
- {EKEYEXPIRED, "Key has expired"},
- {EKEYREVOKED, "Key has been revoked"},
- {EKEYREJECTED, "Key was rejected by service"},
- {EOWNERDEAD, "Owner died"},
- {ENOTRECOVERABLE, "State not recoverable"},
- {ERFKILL, "Operation not possible due to RF-kill"},
- {EHWPOISON, "Memory page has hardware error"},
- {0, nullptr}
-};
-
-extern "C" __LIBC_HIDDEN__ const char* __strerror_lookup(int error_number) {
- return __code_string_lookup(_sys_error_strings, error_number);
-}
-
-int strerror_r(int error_number, char* buf, size_t buf_len) {
- ErrnoRestorer errno_restorer;
- size_t length;
-
- const char* error_name = __strerror_lookup(error_number);
- if (error_name != nullptr) {
- length = strlcpy(buf, error_name, buf_len);
- } else {
- length = async_safe_format_buffer(buf, buf_len, "Unknown error %d", error_number);
- }
- if (length >= buf_len) {
- errno_restorer.override(ERANGE);
- return -1;
- }
-
- 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.
-}