Merge "Make res_init() work again."
diff --git a/docs/native_allocator.md b/docs/native_allocator.md
index 139d664..9fc9a31 100644
--- a/docs/native_allocator.md
+++ b/docs/native_allocator.md
@@ -329,7 +329,7 @@
To run these benchmarks, first copy the trace files to the target using
these commands:
- adb shell push system/extras/traces /data/local/tmp
+ adb push system/extras/memory_replay/traces /data/local/tmp
Since all of the traces come from applications, the `memory_replay` program
will always call `mallopt(M_DECAY_TIME, 1)' before running the trace.
diff --git a/libc/Android.bp b/libc/Android.bp
index 0cfa53c..a52f1a4 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1028,9 +1028,7 @@
"bionic/arpa_inet.cpp",
"bionic/assert.cpp",
"bionic/atof.cpp",
- "bionic/bind.cpp",
"bionic/bionic_allocator.cpp",
- "bionic/bionic_appcompat.cpp",
"bionic/bionic_arc4random.cpp",
"bionic/bionic_futex.cpp",
"bionic/bionic_netlink.cpp",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index ec34828..391e7af 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -245,7 +245,7 @@
# sockets
int __socket:socket(int, int, int) arm,lp64
int __socketpair:socketpair(int, int, int, int*) arm,lp64
-int __bind:bind(int, struct sockaddr*, socklen_t) arm,lp64
+int bind(int, struct sockaddr*, socklen_t) arm,lp64
int __connect:connect(int, struct sockaddr*, socklen_t) arm,lp64
int listen(int, int) arm,lp64
int __accept4:accept4(int, struct sockaddr*, socklen_t*, int) arm,lp64
@@ -263,7 +263,7 @@
# sockets for x86. These are done as an "indexed" call to socketcall syscall.
int __socket:socketcall:1(int, int, int) x86
-int __bind:socketcall:2(int, struct sockaddr*, int) x86
+int bind:socketcall:2(int, struct sockaddr*, int) x86
int __connect:socketcall:3(int, struct sockaddr*, socklen_t) x86
int listen:socketcall:4(int, int) x86
int getsockname:socketcall:6(int, struct sockaddr*, socklen_t*) x86
diff --git a/libc/bionic/bind.cpp b/libc/bionic/bind.cpp
deleted file mode 100644
index 79e8020..0000000
--- a/libc/bionic/bind.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-// b/170214442: Intercept bind calls on NETLINK_ROUTE sockets.
-// This entire file will be reverted before release.
-
-#include <async_safe/log.h>
-#include <errno.h>
-#include <linux/rtnetlink.h>
-#include <string.h>
-#include <sys/socket.h>
-
-#include "bionic_appcompat.h"
-
-extern "C" int __bind(int fd, const struct sockaddr* addr, socklen_t addr_length);
-
-int bind(int fd, const struct sockaddr* addr, socklen_t addr_length) {
- if (should_apply_soft_mac_bind_restrictions()) {
- int sock_domain, sock_protocol;
- socklen_t sock_domain_length = sizeof(sock_domain);
- socklen_t sock_protocol_length = sizeof(sock_protocol);
- if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &sock_domain, &sock_domain_length) < 0 ||
- getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &sock_protocol, &sock_protocol_length) < 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, "mac-restrictions",
- "Could not get socket type/protocol: %s", strerror(errno));
- } else if (AF_NETLINK == sock_domain && NETLINK_ROUTE == sock_protocol) {
- char package_name[MAX_PACKAGE_NAME_LENGTH + 1];
- get_package_name(package_name, sizeof(package_name));
- async_safe_format_log(
- ANDROID_LOG_ERROR, "mac-restrictions",
- "%s tried to call bind() on a NETLINK_ROUTE socket, which is not allowed. Please follow "
- "instructions at go/netlink-bug if this app behaves incorrectly.",
- package_name);
- errno = EACCES;
- return -1;
- }
- }
-
- return __bind(fd, addr, addr_length);
-}
diff --git a/libc/bionic/bionic_appcompat.cpp b/libc/bionic/bionic_appcompat.cpp
deleted file mode 100644
index dcca0da..0000000
--- a/libc/bionic/bionic_appcompat.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-// b/170214442: Intercept bind calls on NETLINK_ROUTE sockets and getifaddrs() calls.
-// This entire file will be reverted before release.
-
-#include <async_safe/log.h>
-#include <cutils/misc.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bionic_appcompat.h"
-
-bool should_apply_soft_mac_restrictions(const char* const allowlist[]) {
- if (getuid() < FIRST_APPLICATION_UID) {
- // System app. No restrictions should be applied.
- return false;
- }
- if (android_get_application_target_sdk_version() >= __ANDROID_API_R__) {
- // Restrictions already applied by SELinux. Behave as normally.
- return false;
- }
-
- char package_name[MAX_PACKAGE_NAME_LENGTH + 1];
- if (get_package_name(package_name, sizeof(package_name)) < 0) {
- // Error in getting own package name. Apply restrictions by default.
- async_safe_format_log(ANDROID_LOG_ERROR, "mac-restrictions",
- "Could not determine own package name for uid %d", getuid());
- return true;
- }
- for (int i = 0; allowlist[i] != nullptr; i++) {
- if (strcmp(package_name, allowlist[i]) == 0) {
- async_safe_format_log(ANDROID_LOG_WARN, "mac-restrictions",
- "Temporarily allowing %s to bypass MAC address restrictions.",
- package_name);
- return false;
- }
- }
- return true;
-}
-
-bool should_apply_soft_mac_bind_restrictions() {
- return should_apply_soft_mac_restrictions(soft_mac_bind_allowlist);
-}
-
-bool should_apply_soft_mac_getlink_restrictions() {
- return should_apply_soft_mac_restrictions(soft_mac_getlink_allowlist);
-}
-
-int get_package_name(char* buffer, const int bufferlen) {
- int file = open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC);
- if (file < 0) {
- return file;
- }
-
- ssize_t len = read(file, buffer, bufferlen - 1);
- if (len < 0) {
- close(file);
- return -1;
- }
- buffer[len] = 0;
-
- close(file);
- return 0;
-}
diff --git a/libc/bionic/bionic_appcompat.h b/libc/bionic/bionic_appcompat.h
deleted file mode 100644
index e67e50c..0000000
--- a/libc/bionic/bionic_appcompat.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#pragma once
-
-constexpr int MAX_PACKAGE_NAME_LENGTH = 230;
-
-static inline const char* const soft_mac_bind_allowlist[] = {
- "com.cisco.anyconnect.vpn.android.avf:nchs",
- "com.skype.raider",
- nullptr,
-};
-
-static inline const char* const soft_mac_getlink_allowlist[] = {
- "com.cisco.anyconnect.vpn.android.avf:nchs",
- nullptr,
-};
-
-int get_package_name(char* buffer, const int bufferlen);
-bool should_apply_soft_mac_bind_restrictions();
-bool should_apply_soft_mac_getlink_restrictions();
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index 043510c..48e8674 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -137,14 +137,6 @@
return;
}
- // Lots of code will (sensibly) fork, call close on all of their fds,
- // and then exec. Compare our cached pid value against the real one to detect
- // this scenario and permit it.
- pid_t cached_pid = __get_cached_pid();
- if (cached_pid == 0 || cached_pid != syscall(__NR_getpid)) {
- return;
- }
-
struct {
size_t size;
char buf[512];
diff --git a/libc/bionic/fdtrack.cpp b/libc/bionic/fdtrack.cpp
index 1123512..89a208f 100644
--- a/libc/bionic/fdtrack.cpp
+++ b/libc/bionic/fdtrack.cpp
@@ -37,8 +37,14 @@
_Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+bool __android_fdtrack_globally_disabled = false;
+
+void android_fdtrack_set_globally_enabled(bool new_value) {
+ __android_fdtrack_globally_disabled = !new_value;
+}
+
bool android_fdtrack_get_enabled() {
- return !__get_bionic_tls().fdtrack_disabled;
+ return !__get_bionic_tls().fdtrack_disabled && !__android_fdtrack_globally_disabled;
}
bool android_fdtrack_set_enabled(bool new_value) {
diff --git a/libc/bionic/fork.cpp b/libc/bionic/fork.cpp
index 8c5cf2b..d432c6d 100644
--- a/libc/bionic/fork.cpp
+++ b/libc/bionic/fork.cpp
@@ -31,6 +31,7 @@
#include <android/fdsan.h>
#include "private/bionic_defs.h"
+#include "private/bionic_fdtrack.h"
#include "pthread_internal.h"
__BIONIC_WEAK_FOR_NATIVE_BRIDGE_INLINE
@@ -55,9 +56,10 @@
int result = __clone_for_fork();
if (result == 0) {
- // Disable fdsan post-fork, so we don't falsely trigger on processes that
+ // Disable fdsan and fdtrack post-fork, so we don't falsely trigger on processes that
// fork, close all of their fds, and then exec.
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
+ android_fdtrack_set_globally_enabled(false);
// Reset the stack_and_tls VMA name so it doesn't end with a tid from the
// parent process.
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
index 22ecdb4..1536333 100644
--- a/libc/bionic/ifaddrs.cpp
+++ b/libc/bionic/ifaddrs.cpp
@@ -42,7 +42,6 @@
#include "private/ErrnoRestorer.h"
-#include "bionic_appcompat.h"
#include "bionic_netlink.h"
// The public ifaddrs struct is full of pointers. Rather than track several
@@ -311,12 +310,9 @@
// - System apps
// - Apps with a target SDK version lower than R
bool getlink_success = false;
- if (!should_apply_soft_mac_getlink_restrictions()) {
+ if (getuid() < FIRST_APPLICATION_UID ||
+ android_get_application_target_sdk_version() < __ANDROID_API_R__) {
getlink_success = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__getifaddrs_callback, out);
- } else if (android_get_application_target_sdk_version() < __ANDROID_API_R__) {
- async_safe_format_log(ANDROID_LOG_WARN, "mac-restrictions",
- "ifaddr no longer returns link info. Please follow instructions at "
- "go/netlink-bug if this app behaves incorrectly.");
}
bool getaddr_success =
nc.SendRequest(RTM_GETADDR) && nc.ReadResponses(__getifaddrs_callback, out);
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 51a1076..c31e306 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1772,6 +1772,7 @@
android_fdtrack_compare_exchange_hook; # llndk
android_fdtrack_get_enabled; # llndk
android_fdtrack_set_enabled; # llndk
+ android_fdtrack_set_globally_enabled; # llndk
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/platform/bionic/fdtrack.h b/libc/platform/bionic/fdtrack.h
index 6eb379b..fe6ca84 100644
--- a/libc/platform/bionic/fdtrack.h
+++ b/libc/platform/bionic/fdtrack.h
@@ -70,4 +70,8 @@
bool android_fdtrack_get_enabled() __INTRODUCED_IN(30);
bool android_fdtrack_set_enabled(bool new_value) __INTRODUCED_IN(30);
+// Globally enable/disable fdtrack.
+// This is primaryily useful to reenable fdtrack after it's been automatically disabled post-fork.
+void android_fdtrack_set_globally_enabled(bool new_value) __INTRODUCED_IN(31);
+
__END_DECLS
diff --git a/libc/private/bionic_fdtrack.h b/libc/private/bionic_fdtrack.h
index 259897c..c05b32b 100644
--- a/libc/private/bionic_fdtrack.h
+++ b/libc/private/bionic_fdtrack.h
@@ -28,41 +28,43 @@
#pragma once
-#include <sys/cdefs.h>
#include <stdatomic.h>
+#include <sys/cdefs.h>
#include "platform/bionic/fdtrack.h"
#include "bionic/pthread_internal.h"
-#include "private/bionic_tls.h"
#include "private/ErrnoRestorer.h"
+#include "private/bionic_tls.h"
extern "C" _Atomic(android_fdtrack_hook_t) __android_fdtrack_hook;
+extern "C" bool __android_fdtrack_globally_disabled;
// Macro to record file descriptor creation.
// e.g.:
// int socket(int domain, int type, int protocol) {
// return FDTRACK_CREATE_NAME("socket", __socket(domain, type, protocol));
// }
-#define FDTRACK_CREATE_NAME(name, fd_value) \
- ({ \
- int __fd = (fd_value); \
- if (__fd != -1 && __predict_false(__android_fdtrack_hook) && \
- !__predict_false(__get_thread()->is_vforked())) { \
- bionic_tls& tls = __get_bionic_tls(); \
- /* fdtrack_disabled is only true during reentrant calls. */ \
- if (!__predict_false(tls.fdtrack_disabled)) { \
- ErrnoRestorer r; \
- tls.fdtrack_disabled = true; \
- android_fdtrack_event event; \
- event.fd = __fd; \
- event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE; \
- event.data.create.function_name = name; \
- atomic_load(&__android_fdtrack_hook)(&event); \
- tls.fdtrack_disabled = false; \
- } \
- } \
- __fd; \
+#define FDTRACK_CREATE_NAME(name, fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook) && \
+ !__predict_false(__get_thread()->is_vforked())) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ /* fdtrack_disabled is only true during reentrant calls. */ \
+ if (!__predict_false(tls.fdtrack_disabled) && \
+ !__predict_false(__android_fdtrack_globally_disabled)) { \
+ ErrnoRestorer r; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CREATE; \
+ event.data.create.function_name = name; \
+ atomic_load (&__android_fdtrack_hook)(&event); \
+ tls.fdtrack_disabled = false; \
+ } \
+ } \
+ __fd; \
})
// Macro to record file descriptor creation, with the current function's name.
@@ -74,22 +76,23 @@
// Macro to record file descriptor closure.
// Note that this does not actually close the file descriptor.
-#define FDTRACK_CLOSE(fd_value) \
- ({ \
- int __fd = (fd_value); \
- if (__fd != -1 && __predict_false(__android_fdtrack_hook) && \
- !__predict_false(__get_thread()->is_vforked())) { \
- bionic_tls& tls = __get_bionic_tls(); \
- if (!__predict_false(tls.fdtrack_disabled)) { \
- int saved_errno = errno; \
- tls.fdtrack_disabled = true; \
- android_fdtrack_event event; \
- event.fd = __fd; \
- event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE; \
- atomic_load(&__android_fdtrack_hook)(&event); \
- tls.fdtrack_disabled = false; \
- errno = saved_errno; \
- } \
- } \
- __fd; \
+#define FDTRACK_CLOSE(fd_value) \
+ ({ \
+ int __fd = (fd_value); \
+ if (__fd != -1 && __predict_false(__android_fdtrack_hook) && \
+ !__predict_false(__get_thread()->is_vforked())) { \
+ bionic_tls& tls = __get_bionic_tls(); \
+ if (!__predict_false(tls.fdtrack_disabled) && \
+ !__predict_false(__android_fdtrack_globally_disabled)) { \
+ int saved_errno = errno; \
+ tls.fdtrack_disabled = true; \
+ android_fdtrack_event event; \
+ event.fd = __fd; \
+ event.type = ANDROID_FDTRACK_EVENT_TYPE_CLOSE; \
+ atomic_load (&__android_fdtrack_hook)(&event); \
+ tls.fdtrack_disabled = false; \
+ errno = saved_errno; \
+ } \
+ } \
+ __fd; \
})
diff --git a/libfdtrack/fdtrack.cpp b/libfdtrack/fdtrack.cpp
index fd56274..2e9cfbc 100644
--- a/libfdtrack/fdtrack.cpp
+++ b/libfdtrack/fdtrack.cpp
@@ -93,6 +93,8 @@
android_fdtrack_hook_t expected = nullptr;
installed = android_fdtrack_compare_exchange_hook(&expected, &fd_hook);
}
+
+ android_fdtrack_set_globally_enabled(true);
}
__attribute__((destructor)) static void dtor() {
diff --git a/tests/arpa_inet_test.cpp b/tests/arpa_inet_test.cpp
index a368b8f..8dec2e3 100644
--- a/tests/arpa_inet_test.cpp
+++ b/tests/arpa_inet_test.cpp
@@ -158,3 +158,95 @@
ASSERT_STREQ("::1", inet_ntop(AF_INET6, &ss6, s6, INET6_ADDRSTRLEN));
ASSERT_STREQ("::1", inet_ntop(AF_INET6, &ss6, s6, 2*INET6_ADDRSTRLEN));
}
+
+TEST(arpa_inet, inet_nsap_addr) {
+ // inet_nsap_addr() doesn't seem to be documented anywhere, but it's basically
+ // text to binary for arbitrarily-long strings like "0xdeadbeef". Any
+ // '.', '+', or '/' characters are ignored as punctuation. The return value is
+ // the length in bytes, or 0 for all errors.
+ u_char buf[32];
+
+ // Missing "0x" prefix.
+ ASSERT_EQ(0U, inet_nsap_addr("123", buf, sizeof(buf)));
+ ASSERT_EQ(0U, inet_nsap_addr("012", buf, sizeof(buf)));
+
+ // 1 byte.
+ ASSERT_EQ(1U, inet_nsap_addr("0x12", buf, sizeof(buf)));
+ ASSERT_EQ(0x12, buf[0]);
+
+ // 10 bytes.
+ ASSERT_EQ(10U, inet_nsap_addr("0x1234567890abcdef0011", buf, sizeof(buf)));
+ ASSERT_EQ(0x12, buf[0]);
+ ASSERT_EQ(0x34, buf[1]);
+ ASSERT_EQ(0x56, buf[2]);
+ ASSERT_EQ(0x78, buf[3]);
+ ASSERT_EQ(0x90, buf[4]);
+ ASSERT_EQ(0xab, buf[5]);
+ ASSERT_EQ(0xcd, buf[6]);
+ ASSERT_EQ(0xef, buf[7]);
+ ASSERT_EQ(0x00, buf[8]);
+ ASSERT_EQ(0x11, buf[9]);
+
+ // Ignored punctuation.
+ ASSERT_EQ(10U, inet_nsap_addr("0x1122.3344+5566/7788/99aa", buf, sizeof(buf)));
+ ASSERT_EQ(0x11, buf[0]);
+ ASSERT_EQ(0x22, buf[1]);
+ ASSERT_EQ(0x33, buf[2]);
+ ASSERT_EQ(0x44, buf[3]);
+ ASSERT_EQ(0x55, buf[4]);
+ ASSERT_EQ(0x66, buf[5]);
+ ASSERT_EQ(0x77, buf[6]);
+ ASSERT_EQ(0x88, buf[7]);
+ ASSERT_EQ(0x99, buf[8]);
+ ASSERT_EQ(0xaa, buf[9]);
+
+ // Truncated.
+ ASSERT_EQ(4U, inet_nsap_addr("0xdeadbeef666666666666", buf, 4));
+ // Overwritten...
+ ASSERT_EQ(0xde, buf[0]);
+ ASSERT_EQ(0xad, buf[1]);
+ ASSERT_EQ(0xbe, buf[2]);
+ ASSERT_EQ(0xef, buf[3]);
+ // Same as before...
+ ASSERT_EQ(0x55, buf[4]);
+ ASSERT_EQ(0x66, buf[5]);
+ ASSERT_EQ(0x77, buf[6]);
+ ASSERT_EQ(0x88, buf[7]);
+ ASSERT_EQ(0x99, buf[8]);
+ ASSERT_EQ(0xaa, buf[9]);
+
+ // Case insensitivity.
+ ASSERT_EQ(6U, inet_nsap_addr("0xaAbBcCdDeEfF", buf, 6));
+ ASSERT_EQ(0xaa, buf[0]);
+ ASSERT_EQ(0xbb, buf[1]);
+ ASSERT_EQ(0xcc, buf[2]);
+ ASSERT_EQ(0xdd, buf[3]);
+ ASSERT_EQ(0xee, buf[4]);
+ ASSERT_EQ(0xff, buf[5]);
+
+ // Punctuation isn't allowed within a byte.
+ ASSERT_EQ(0U, inet_nsap_addr("0x1.122", buf, sizeof(buf)));
+ // Invalid punctuation.
+ ASSERT_EQ(0U, inet_nsap_addr("0x11,22", buf, sizeof(buf)));
+ // Invalid hex digit.
+ ASSERT_EQ(0U, inet_nsap_addr("0x11.g2", buf, sizeof(buf)));
+ ASSERT_EQ(0U, inet_nsap_addr("0x11.2g", buf, sizeof(buf)));
+ // Invalid half-byte.
+ ASSERT_EQ(0U, inet_nsap_addr("0x11.2", buf, sizeof(buf)));
+}
+
+TEST(arpa_inet, inet_nsap_ntoa) {
+ // inet_nsap_ntoa() doesn't seem to be documented anywhere, but it's basically
+ // binary to text for arbitrarily-long byte buffers.
+ // The return value is a pointer to the buffer. No errors are possible.
+ const unsigned char bytes[] = {0x01, 0x00, 0x02, 0x0e, 0xf0, 0x20};
+ char dst[32];
+ ASSERT_EQ(dst, inet_nsap_ntoa(6, bytes, dst));
+ ASSERT_STREQ(dst, "0x01.0002.0EF0.20");
+}
+
+TEST(arpa_inet, inet_nsap_ntoa__nullptr) {
+ // If you don't provide a destination, a static buffer is provided for you.
+ const unsigned char bytes[] = {0x01, 0x00, 0x02, 0x0e, 0xf0, 0x20};
+ ASSERT_STREQ("0x01.0002.0EF0.20", inet_nsap_ntoa(6, bytes, nullptr));
+}
diff --git a/tests/fdtrack_test.cpp b/tests/fdtrack_test.cpp
index 13f1b2e..9fcb402 100644
--- a/tests/fdtrack_test.cpp
+++ b/tests/fdtrack_test.cpp
@@ -57,8 +57,13 @@
}
}
-std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
+std::vector<android_fdtrack_event> FdtrackRun(void (*func)(), bool reenable = true) {
// Each bionic test is run in separate process, so we can safely use a static here.
+ // However, since they're all forked, we need to reenable fdtrack.
+ if (reenable) {
+ android_fdtrack_set_globally_enabled(true);
+ }
+
static std::vector<android_fdtrack_event> events;
events.clear();
@@ -129,6 +134,21 @@
#endif
}
+TEST(fdtrack, fork) {
+#if defined(__BIONIC__)
+ ASSERT_EXIT(
+ []() {
+ static int fd = open("/dev/null", O_WRONLY | O_CLOEXEC);
+ ASSERT_NE(-1, fd);
+
+ auto events = FdtrackRun([]() { close(fd); }, false);
+ ASSERT_EQ(0U, events.size());
+ exit(0);
+ }(),
+ testing::ExitedWithCode(0), "");
+#endif
+}
+
TEST(fdtrack, enable_disable) {
#if defined(__BIONIC__)
static int fd1 = -1;
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index 1dd45b4..9f7e65b 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -1473,16 +1473,40 @@
ASSERT_EQ(-1, sign);
}
+TEST(MATH_TEST, tgamma_NaN) {
+ ASSERT_TRUE(isnan(tgamma(nan(""))));
+ ASSERT_TRUE(isnanf(tgammaf(nanf(""))));
+ ASSERT_TRUE(isnanl(tgammal(nanl(""))));
+}
+
+TEST(MATH_TEST, tgamma_inf) {
+ ASSERT_TRUE(isinf(tgamma(HUGE_VAL)));
+ ASSERT_TRUE(isinff(tgammaf(HUGE_VALF)));
+ ASSERT_TRUE(isinfl(tgammal(HUGE_VALL)));
+}
+
+TEST(MATH_TEST, tgamma_negative) {
+ ASSERT_TRUE(isnan(tgamma(-1.0)));
+ ASSERT_TRUE(isnanf(tgammaf(-1.0f)));
+ ASSERT_TRUE(isnanl(tgammal(-1.0L)));
+}
+
TEST(MATH_TEST, tgamma) {
ASSERT_DOUBLE_EQ(24.0, tgamma(5.0));
+ ASSERT_DOUBLE_EQ(120.0, tgamma(6.0));
+ ASSERT_TRUE(isinf(tgamma(172.0)));
}
TEST(MATH_TEST, tgammaf) {
ASSERT_FLOAT_EQ(24.0f, tgammaf(5.0f));
+ ASSERT_FLOAT_EQ(120.0f, tgammaf(6.0f));
+ ASSERT_TRUE(isinff(tgammaf(172.0f)));
}
TEST(MATH_TEST, tgammal) {
ASSERT_DOUBLE_EQ(24.0L, tgammal(5.0L));
+ ASSERT_DOUBLE_EQ(120.0L, tgammal(6.0L));
+ ASSERT_TRUE(isinf(tgammal(172.0L)));
}
TEST(MATH_TEST, j0) {
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 4b1482a..ec1badc 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -321,6 +321,6 @@
ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
pthread_join(t, nullptr);
#else
- GTEST_LOG_(INFO) << "tests uses functions not in glibc";
+ GTEST_SKIP() << "tests uses functions not in glibc";
#endif
}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 16299cc..b16fe16 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -31,8 +31,6 @@
#include "SignalUtils.h"
#include "utils.h"
-#include "private/bionic_constants.h"
-
using namespace std::chrono_literals;
TEST(time, time) {
@@ -760,22 +758,22 @@
TEST(time, clock_gettime) {
// Try to ensure that our vdso clock_gettime is working.
+ timespec ts0;
timespec ts1;
- ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts1));
timespec ts2;
- ASSERT_EQ(0, syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts2));
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts0));
+ ASSERT_EQ(0, syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts1));
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts2));
- // What's the difference between the two?
- ts2.tv_sec -= ts1.tv_sec;
- ts2.tv_nsec -= ts1.tv_nsec;
- if (ts2.tv_nsec < 0) {
- --ts2.tv_sec;
- ts2.tv_nsec += NS_PER_S;
+ // Check we have a nice monotonic timestamp sandwich.
+ ASSERT_LE(ts0.tv_sec, ts1.tv_sec);
+ if (ts0.tv_sec == ts1.tv_sec) {
+ ASSERT_LE(ts0.tv_nsec, ts1.tv_nsec);
}
-
- // To try to avoid flakiness we'll accept answers within 10,000,000ns (0.01s).
- ASSERT_EQ(0, ts2.tv_sec);
- ASSERT_LT(ts2.tv_nsec, 10'000'000);
+ ASSERT_LE(ts1.tv_sec, ts2.tv_sec);
+ if (ts1.tv_sec == ts2.tv_sec) {
+ ASSERT_LE(ts1.tv_nsec, ts2.tv_nsec);
+ }
}
TEST(time, clock_gettime_CLOCK_REALTIME) {
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 9b4fc4f..d0b5a4a 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -228,14 +228,22 @@
}
TEST(wchar, wcsstr) {
- const wchar_t* haystack = L"matches hello world, not the second hello world";
- const wchar_t* empty_needle = L"";
- const wchar_t* good_needle = L"ll";
- const wchar_t* bad_needle = L"wort";
+ const wchar_t* haystack = L"big daddy/giant haystacks!";
+ const wchar_t* empty_haystack = L"";
- ASSERT_EQ(haystack, wcsstr(haystack, empty_needle));
- ASSERT_EQ(&haystack[10], wcsstr(haystack, good_needle));
- ASSERT_EQ(nullptr, wcsstr(haystack, bad_needle));
+ // The empty needle is a special case.
+ ASSERT_EQ(haystack, wcsstr(haystack, L""));
+ ASSERT_EQ(empty_haystack, wcsstr(empty_haystack, L""));
+
+ ASSERT_EQ(haystack, wcsstr(haystack, L"b"));
+ ASSERT_EQ(haystack, wcsstr(haystack, L"big"));
+ ASSERT_EQ(haystack + 9, wcsstr(haystack, L"/"));
+ ASSERT_EQ(haystack + 9, wcsstr(haystack, L"/giant"));
+ ASSERT_EQ(haystack + 25, wcsstr(haystack, L"!"));
+ ASSERT_EQ(haystack + 19, wcsstr(haystack, L"stacks!"));
+
+ ASSERT_EQ(nullptr, wcsstr(haystack, L"monkey"));
+ ASSERT_EQ(nullptr, wcsstr(empty_haystack, L"monkey"));
}
TEST(wchar, wcsstr_80199) {
@@ -646,6 +654,8 @@
EXPECT_EQ(dst, wcsncpy(dst, src, 6));
dst[6] = L'\0';
EXPECT_STREQ(dst, L"Source");
+ EXPECT_EQ(dst, wcsncpy(dst, L"clobber", 0));
+ EXPECT_STREQ(dst, L"Source");
wmemset(dst, L'x', NUM_WCHARS(sizeof(dst)));
EXPECT_EQ(dst, wcsncpy(dst, src, src_len + 4));
@@ -1024,3 +1034,169 @@
EXPECT_EQ(2, wcwidth(L'ㅜ')); // Korean "crying" emoticon.
EXPECT_EQ(2, wcwidth(L'ㅋ')); // Korean "laughing" emoticon.
}
+
+TEST(wchar, wcswidth) {
+ EXPECT_EQ(2, wcswidth(L"abc", 2));
+ EXPECT_EQ(2, wcswidth(L"ab\t", 2));
+ EXPECT_EQ(-1, wcswidth(L"a\tb", 2));
+}
+
+TEST(wchar, wcslcpy) {
+#if defined(__BIONIC__)
+ wchar_t dst[32];
+ ASSERT_EQ(11U, wcslcpy(dst, L"hello world", 3));
+ ASSERT_STREQ(L"he", dst);
+ ASSERT_EQ(11U, wcslcpy(dst, L"hello world", 32));
+ ASSERT_STREQ(L"hello world", dst);
+#else
+ GTEST_SKIP() << "no wcslcpy in glibc";
+#endif
+}
+
+TEST(wchar, wcscat) {
+ wchar_t dst[32];
+ ASSERT_EQ(dst, wcscat(dst, L"hello"));
+ ASSERT_STREQ(dst, L"hello");
+ ASSERT_EQ(dst, wcscat(dst, L" world"));
+ ASSERT_STREQ(dst, L"hello world");
+}
+
+TEST(wchar, wcscpy) {
+ wchar_t dst[32];
+ ASSERT_EQ(dst, wcscpy(dst, L"hello"));
+ ASSERT_STREQ(dst, L"hello");
+ ASSERT_EQ(dst, wcscpy(dst, L"world"));
+ ASSERT_STREQ(dst, L"world");
+}
+
+TEST(wchar, wcscasecmp) {
+ ASSERT_EQ(0, wcscasecmp(L"hello", L"HELLO"));
+ ASSERT_TRUE(wcscasecmp(L"hello1", L"HELLO2") < 0);
+ ASSERT_TRUE(wcscasecmp(L"hello2", L"HELLO1") > 0);
+ ASSERT_TRUE(wcscasecmp(L"hello", L"HELL") > 0);
+ ASSERT_TRUE(wcscasecmp(L"hell", L"HELLO") < 0);
+}
+
+TEST(wchar, wcscspn) {
+ ASSERT_EQ(0U, wcscspn(L"hello world", L"abcdefghijklmnopqrstuvwxyz"));
+ ASSERT_EQ(5U, wcscspn(L"hello world", L" "));
+ ASSERT_EQ(11U, wcscspn(L"hello world", L"!"));
+}
+
+TEST(wchar, wcsspn) {
+ ASSERT_EQ(0U, wcsspn(L"hello world", L"!"));
+ ASSERT_EQ(5U, wcsspn(L"hello world", L"abcdefghijklmnopqrstuvwxyz"));
+ ASSERT_EQ(11U, wcsspn(L"hello world", L"abcdefghijklmnopqrstuvwxyz "));
+}
+
+TEST(wchar, wcsdup) {
+ wchar_t* s = wcsdup(L"hello");
+ ASSERT_STREQ(s, L"hello");
+ free(s);
+}
+
+TEST(wchar, wcslcat) {
+#if defined(__BIONIC__)
+ wchar_t dst[4] = {};
+ ASSERT_EQ(1U, wcslcat(dst, L"a", 4));
+ ASSERT_EQ(7U, wcslcat(dst, L"bcdefg", 4));
+ ASSERT_STREQ(dst, L"abc");
+#else
+ GTEST_SKIP() << "no wcslcpy in glibc";
+#endif
+}
+
+TEST(wchar, wcsncasecmp) {
+ ASSERT_EQ(0, wcsncasecmp(L"foo", L"bar", 0));
+
+ ASSERT_EQ(0, wcsncasecmp(L"hello1", L"HELLO2", 5));
+ ASSERT_TRUE(wcsncasecmp(L"hello1", L"HELLO2", 6) < 0);
+ ASSERT_TRUE(wcsncasecmp(L"hello2", L"HELLO1", 6) > 0);
+ ASSERT_TRUE(wcsncasecmp(L"hello", L"HELL", 5) > 0);
+ ASSERT_TRUE(wcsncasecmp(L"hell", L"HELLO", 5) < 0);
+}
+
+TEST(wchar, wcsncat) {
+ wchar_t dst[32];
+ ASSERT_EQ(dst, wcsncat(dst, L"hello, world!", 5));
+ ASSERT_STREQ(dst, L"hello");
+ ASSERT_EQ(dst, wcsncat(dst, L"hello, world!", 0));
+ ASSERT_STREQ(dst, L"hello");
+ ASSERT_EQ(dst, wcsncat(dst, L", world!", 8));
+ ASSERT_STREQ(dst, L"hello, world!");
+}
+
+TEST(wchar, wcsncmp) {
+ ASSERT_EQ(0, wcsncmp(L"foo", L"bar", 0));
+ ASSERT_EQ(0, wcsncmp(L"aaaa", L"aaab", 3));
+ ASSERT_TRUE(wcsncmp(L"aaaa", L"aaab", 4) < 0);
+ ASSERT_TRUE(wcsncmp(L"aaab", L"aaaa", 4) > 0);
+}
+
+TEST(wchar, wcsnlen) {
+ ASSERT_EQ(2U, wcsnlen(L"hello", 2));
+ ASSERT_EQ(5U, wcsnlen(L"hello", 5));
+ ASSERT_EQ(5U, wcsnlen(L"hello", 666));
+}
+
+TEST(wchar, wcspbrk) {
+ const wchar_t* s = L"hello, world!";
+ ASSERT_EQ(nullptr, wcspbrk(s, L"-"));
+ ASSERT_EQ(s, wcspbrk(s, L"abch"));
+ ASSERT_EQ(s + 2, wcspbrk(s, L"l"));
+ ASSERT_EQ(s + 5, wcspbrk(s, L",. !"));
+}
+
+TEST(wchar, wcstok) {
+ wchar_t s[] = L"this is\ta\nstring";
+ wchar_t* p;
+ ASSERT_EQ(s, wcstok(s, L"\t\n ", &p));
+ ASSERT_STREQ(s, L"this");
+ ASSERT_STREQ(p, L"is\ta\nstring");
+ ASSERT_EQ(s + 5, wcstok(nullptr, L"\t\n ", &p));
+ ASSERT_STREQ(s + 5, L"is");
+ ASSERT_STREQ(p, L"a\nstring");
+ ASSERT_EQ(s + 8, wcstok(nullptr, L"\t\n ", &p));
+ ASSERT_STREQ(s + 8, L"a");
+ ASSERT_STREQ(p, L"string");
+ ASSERT_EQ(s + 10, wcstok(nullptr, L"\t\n ", &p));
+ ASSERT_STREQ(s + 10, L"string");
+ ASSERT_EQ(nullptr, p);
+}
+
+TEST(wchar, wmemchr) {
+ const wchar_t* s = L"hello, world!";
+ ASSERT_EQ(s, wmemchr(s, L'h', 13));
+ ASSERT_EQ(s + 5, wmemchr(s, L',', 13));
+ ASSERT_EQ(s + 12, wmemchr(s, L'!', 13));
+ ASSERT_EQ(nullptr, wmemchr(s, L'a', 13));
+}
+
+TEST(wchar, wmemcmp) {
+ ASSERT_EQ(0, wmemcmp(L"aaaa", L"aaab", 3));
+ ASSERT_TRUE(wmemcmp(L"aaaa", L"aaab", 4) < 0);
+ ASSERT_TRUE(wmemcmp(L"aaab", L"aaaa", 4) > 0);
+}
+
+TEST(wchar, wmemcpy) {
+ wchar_t dst[32] = {};
+ ASSERT_EQ(dst, wmemcpy(dst, L"hello", 5));
+ ASSERT_STREQ(dst, L"hello");
+}
+
+TEST(wchar, wmemmove) {
+ wchar_t dst[32] = {};
+ ASSERT_EQ(dst, wmemmove(dst, L"hello", 5));
+ ASSERT_STREQ(dst, L"hello");
+}
+
+TEST(wchar, wmemset) {
+ wchar_t dst[4] = {};
+ ASSERT_EQ(dst, wmemset(dst, 0x12345678, 3));
+ ASSERT_EQ(dst[0], wchar_t(0x12345678));
+ ASSERT_EQ(dst[1], wchar_t(0x12345678));
+ ASSERT_EQ(dst[2], wchar_t(0x12345678));
+ ASSERT_EQ(dst[3], wchar_t(0));
+ ASSERT_EQ(dst, wmemset(dst, L'y', 0));
+ ASSERT_EQ(dst[0], wchar_t(0x12345678));
+}