summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Android.bp92
-rw-r--r--tests/Android.mk22
-rw-r--r--tests/clang_fortify_tests.cpp607
-rw-r--r--tests/dlext_test.cpp10
-rw-r--r--tests/fortify_filecheck_diagnostics_test.cpp323
-rw-r--r--tests/fortify_test.cpp18
-rw-r--r--tests/grp_pwd_test.cpp368
-rw-r--r--tests/leak_test.cpp15
-rw-r--r--tests/libs/Android.bp2
-rw-r--r--tests/libs/segment_gap_outer.lds2
-rw-r--r--tests/make_fortify_compile_test.mk20
-rw-r--r--tests/malloc_test.cpp20
-rw-r--r--tests/pthread_test.cpp304
-rw-r--r--tests/semaphore_test.cpp13
-rw-r--r--tests/stdatomic_test.cpp9
-rw-r--r--tests/stdio_test.cpp83
-rw-r--r--tests/sys_mman_test.cpp61
-rw-r--r--tests/time_test.cpp4
-rwxr-xr-xtests/touch-obj-on-success7
19 files changed, 1481 insertions, 499 deletions
diff --git a/tests/Android.bp b/tests/Android.bp
index db02d751a..aac419c23 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -241,6 +241,15 @@ cc_test_library {
cflags: [
"-fno-emulated-tls",
],
+ // With fuzzer builds, compiler instrumentation generates a reference to the
+ // __sancov_lowest_stack variable, which (for now) is defined by the fuzzer
+ // library as an emutls symbol. The -fno-emulated-tls flag above configures
+ // the compiler to reference an ordinary ELF TLS __sancov_lowest_stack
+ // symbol instead, which isn't defined. Disable the fuzzer for this test
+ // until the platform is switched to ELF TLS.
+ sanitize: {
+ fuzzer: false,
+ },
}
cc_test_library {
@@ -262,6 +271,15 @@ cc_test_library {
cflags: [
"-fno-emulated-tls",
],
+ // With fuzzer builds, compiler instrumentation generates a reference to the
+ // __sancov_lowest_stack variable, which (for now) is defined by the fuzzer
+ // library as an emutls symbol. The -fno-emulated-tls flag above configures
+ // the compiler to reference an ordinary ELF TLS __sancov_lowest_stack
+ // symbol instead, which isn't defined. Disable the fuzzer for this test
+ // until the platform is switched to ELF TLS.
+ sanitize: {
+ fuzzer: false,
+ },
}
// -----------------------------------------------------------------------------
@@ -269,6 +287,18 @@ cc_test_library {
// -----------------------------------------------------------------------------
cc_defaults {
+ name: "bionic_clang_fortify_tests_w_flags",
+ cflags: [
+ "-Wno-builtin-memcpy-chk-size",
+ "-Wno-format-security",
+ "-Wno-format-zero-length",
+ "-Wno-memset-transposed-args",
+ "-Wno-strlcpy-strlcat-size",
+ "-Wno-strncat-size",
+ ],
+}
+
+cc_defaults {
name: "bionic_fortify_tests_defaults",
cflags: [
"-U_FORTIFY_SOURCE",
@@ -287,6 +317,9 @@ cc_defaults {
// unused.
cc_test_library {
name: "fortify_disabled_for_asan",
+ defaults: [
+ "bionic_clang_fortify_tests_w_flags",
+ ],
cflags: [
"-Werror",
"-D_FORTIFY_SOURCE=2",
@@ -294,11 +327,10 @@ cc_test_library {
// enabled. Since the intent is just to build this, we can get away with
// passing this flag on its own.
"-fsanitize=address",
- "-Wno-memset-transposed-args",
],
// Ignore that we don't have ASAN symbols linked in.
allow_undefined_symbols: true,
- srcs: ["fortify_filecheck_diagnostics_test.cpp"],
+ srcs: ["clang_fortify_tests.cpp"],
}
// Ensure we don't use FORTIFY'ed functions with the static analyzer/clang-tidy:
@@ -307,13 +339,15 @@ cc_test_library {
// enabled. The library that results from building this is meant to be unused.
cc_test_library {
name: "fortify_disabled_for_tidy",
+ defaults: [
+ "bionic_clang_fortify_tests_w_flags",
+ ],
cflags: [
"-Werror",
"-D_FORTIFY_SOURCE=2",
"-D__clang_analyzer__",
- "-Wno-memset-transposed-args",
],
- srcs: ["fortify_filecheck_diagnostics_test.cpp"],
+ srcs: ["clang_fortify_tests.cpp"],
}
cc_test_library {
@@ -346,6 +380,53 @@ cc_test_library {
},
}
+cc_defaults {
+ name: "bionic_new_fortify_tests_defaults",
+ defaults: [
+ "bionic_clang_fortify_tests_w_flags",
+ ],
+ cflags: [
+ "-U_FORTIFY_SOURCE",
+ ],
+ srcs: ["clang_fortify_tests.cpp"],
+ target: {
+ host: {
+ clang_cflags: ["-D__clang__"],
+ },
+ },
+}
+
+cc_test_library {
+ name: "libfortify1-new-tests-clang",
+ defaults: [
+ "bionic_new_fortify_tests_defaults",
+ "bionic_tests_defaults",
+ ],
+ cflags: [
+ "-D_FORTIFY_SOURCE=1",
+ "-DTEST_NAME=Fortify1_clang_new",
+ ],
+ shared: {
+ enabled: false,
+ },
+}
+
+cc_test_library {
+ name: "libfortify2-new-tests-clang",
+ defaults: [
+ "bionic_new_fortify_tests_defaults",
+ "bionic_tests_defaults",
+ ],
+ cflags: [
+ "-D_FORTIFY_SOURCE=2",
+ "-DTEST_NAME=Fortify2_clang_new",
+ ],
+ shared: {
+ enabled: false,
+ },
+}
+
+
// -----------------------------------------------------------------------------
// Library of all tests (excluding the dynamic linker tests).
// -----------------------------------------------------------------------------
@@ -356,7 +437,9 @@ cc_test_library {
"libBionicStandardTests",
"libBionicElfTlsTests",
"libfortify1-tests-clang",
+ "libfortify1-new-tests-clang",
"libfortify2-tests-clang",
+ "libfortify2-new-tests-clang",
],
shared: {
enabled: false,
@@ -477,7 +560,6 @@ cc_defaults {
android: {
shared_libs: [
"ld-android",
- "libandroidicu",
"libdl",
"libdl_android",
"libdl_preempt_test_1",
diff --git a/tests/Android.mk b/tests/Android.mk
index 848d2917e..b5571e3f6 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -59,23 +59,11 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x
# Compile time tests.
# -----------------------------------------------------------------------------
-# Some of these are intentionally using = instead of := since we need access to
-# some variables not initialtized until we're in the build system.
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk \
- $(LOCAL_PATH)/touch-obj-on-success
-
-LOCAL_CXX := $(LOCAL_PATH)/touch-obj-on-success \
- $(LLVM_PREBUILTS_PATH)/clang++ \
-
-LOCAL_CLANG := true
-LOCAL_MODULE := bionic-compile-time-tests-clang++
-LOCAL_CPPFLAGS := -Wall -Wno-error
-LOCAL_CPPFLAGS += -fno-color-diagnostics -ferror-limit=10000 -Xclang -verify
-LOCAL_SRC_FILES := fortify_filecheck_diagnostics_test.cpp
-include $(BUILD_STATIC_LIBRARY)
+FORTIFY_LEVEL := 1
+include $(LOCAL_PATH)/make_fortify_compile_test.mk
+
+FORTIFY_LEVEL := 2
+include $(LOCAL_PATH)/make_fortify_compile_test.mk
endif # linux-x86
diff --git a/tests/clang_fortify_tests.cpp b/tests/clang_fortify_tests.cpp
new file mode 100644
index 000000000..1b6b898d5
--- /dev/null
+++ b/tests/clang_fortify_tests.cpp
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __clang__
+#error "Non-clang isn't supported"
+#endif
+
+// Clang compile-time and run-time tests for Bionic's FORTIFY.
+//
+// This file is compiled in two configurations ways to give us a sane set of tests for clang's
+// FORTIFY implementation.
+//
+// One configuration uses clang's diagnostic consumer
+// (https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details)
+// to check diagnostics (e.g. the expected-* comments everywhere).
+//
+// Please note that this test does things like leaking memory. That's WAI.
+
+// Silence all "from 'diagnose_if'" `note`s from anywhere, including headers; they're uninteresting
+// for this test case, and their line numbers may change over time.
+// expected-note@* 0+{{from 'diagnose_if'}}
+//
+// Similarly, there are a few overload tricks we have to emit errors. Ignore any notes from those.
+// expected-note@* 0+{{candidate function}}
+
+#ifndef _FORTIFY_SOURCE
+#error "_FORTIFY_SOURCE must be defined"
+#endif
+
+#include <sys/cdefs.h>
+
+// This is a test specifically of bionic's FORTIFY machinery. Other stdlibs need not apply.
+#ifndef __BIONIC__
+// expected-no-diagnostics
+#else
+
+// As alluded to above, we're going to be doing some obviously very broken things in this file.
+// FORTIFY helpfully flags a lot of it at compile-time, but we want it to *actually* crash, too. So
+// let's wipe out any build-time errors.
+#ifndef COMPILATION_TESTS
+#undef __clang_error_if
+#define __clang_error_if(...)
+#undef __clang_warning_if
+#define __clang_warning_if(...)
+
+// SOMETIMES_CONST allows clang to emit eager diagnostics when we're doing compilation tests, but
+// blocks them otherwise. This is needed for diagnostics emitted with __enable_if.
+#define SOMETIMES_CONST volatile
+#else
+#define SOMETIMES_CONST const
+#endif
+
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#ifndef COMPILATION_TESTS
+#include <gtest/gtest.h>
+#include "BionicDeathTest.h"
+
+#define CONCAT2(x, y) x##y
+#define CONCAT(x, y) CONCAT2(x, y)
+#define FORTIFY_TEST_NAME CONCAT(clang_fortify_test_, _FORTIFY_SOURCE)
+
+namespace {
+struct FORTIFY_TEST_NAME : BionicDeathTest {
+ protected:
+ void SetUp() override {
+ stdin_saved = dup(STDIN_FILENO);
+ if (stdin_saved < 0) err(1, "failed to dup stdin");
+
+ int devnull = open("/dev/null", O_RDONLY);
+ if (devnull < 0) err(1, "failed to open /dev/null");
+
+ if (!dup2(devnull, STDIN_FILENO)) err(1, "failed to overwrite stdin");
+ static_cast<void>(close(devnull));
+
+ BionicDeathTest::SetUp();
+ }
+
+ void TearDown() override {
+ if (stdin_saved == -1) return;
+ if (!dup2(stdin_saved, STDIN_FILENO)) warn("failed to restore stdin");
+
+ static_cast<void>(close(stdin_saved));
+
+ BionicDeathTest::TearDown();
+ }
+
+ private:
+ int stdin_saved = -1;
+};
+} // namespace
+
+template <typename Fn>
+__attribute__((noreturn)) static void ExitAfter(Fn&& f) {
+ f();
+ // No need to tear things down; our parent process should handle that.
+ _exit(0);
+}
+
+// In any case (including failing tests), we always want to die after this.
+#define DIE_WITH(expr, cond, regex) EXPECT_EXIT(ExitAfter([&] { (expr); }), cond, regex)
+
+// EXPECT_NO_DEATH forks so that the test remains alive on a bug, and so that the environment
+// doesn't get modified on no bug. (Environment modification is especially tricky to deal with given
+// the *_STRUCT variants below.)
+#define EXPECT_NO_DEATH(expr) DIE_WITH(expr, testing::ExitedWithCode(0), "")
+#define EXPECT_FORTIFY_DEATH(expr) DIE_WITH(expr, testing::KilledBySignal(SIGABRT), "FORTIFY")
+// Expecting death, but only if we're doing a "strict" struct-checking mode.
+#if _FORTIFY_SOURCE > 1
+#define EXPECT_FORTIFY_DEATH_STRUCT EXPECT_FORTIFY_DEATH
+#else
+#define EXPECT_FORTIFY_DEATH_STRUCT EXPECT_NO_DEATH
+#endif
+
+#define FORTIFY_TEST(test_name) TEST(FORTIFY_TEST_NAME, test_name)
+
+#else // defined(COMPILATION_TESTS)
+
+#define EXPECT_NO_DEATH(expr) expr
+#define EXPECT_FORTIFY_DEATH(expr) expr
+#define EXPECT_FORTIFY_DEATH_STRUCT EXPECT_FORTIFY_DEATH
+#define FORTIFY_TEST(test_name) void test_name()
+#endif
+
+const static int kBogusFD = -1;
+
+FORTIFY_TEST(string) {
+ char small_buffer[8] = {};
+
+ {
+ char large_buffer[sizeof(small_buffer) + 1] = {};
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(memcpy(small_buffer, large_buffer, sizeof(large_buffer)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(memmove(small_buffer, large_buffer, sizeof(large_buffer)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(mempcpy(small_buffer, large_buffer, sizeof(large_buffer)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(memset(small_buffer, 0, sizeof(large_buffer)));
+ // expected-warning@+1{{arguments got flipped?}}
+ EXPECT_NO_DEATH(memset(small_buffer, sizeof(small_buffer), 0));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(bcopy(large_buffer, small_buffer, sizeof(large_buffer)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(bzero(small_buffer, sizeof(large_buffer)));
+ }
+
+ {
+ const char large_string[] = "Hello!!!";
+ static_assert(sizeof(large_string) > sizeof(small_buffer), "");
+
+ // expected-error@+1{{string bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strcpy(small_buffer, large_string));
+ // expected-error@+1{{string bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(stpcpy(small_buffer, large_string));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strncpy(small_buffer, large_string, sizeof(large_string)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(stpncpy(small_buffer, large_string, sizeof(large_string)));
+ // expected-error@+1{{string bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strcat(small_buffer, large_string));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strncat(small_buffer, large_string, sizeof(large_string)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strlcpy(small_buffer, large_string, sizeof(large_string)));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(strlcat(small_buffer, large_string, sizeof(large_string)));
+ }
+
+ {
+ struct {
+ char tiny_buffer[4];
+ char tiny_buffer2[4];
+ } split = {};
+
+ EXPECT_NO_DEATH(memcpy(split.tiny_buffer, &split, sizeof(split)));
+ EXPECT_NO_DEATH(memcpy(split.tiny_buffer, &split, sizeof(split)));
+ EXPECT_NO_DEATH(memmove(split.tiny_buffer, &split, sizeof(split)));
+ EXPECT_NO_DEATH(mempcpy(split.tiny_buffer, &split, sizeof(split)));
+ EXPECT_NO_DEATH(memset(split.tiny_buffer, 0, sizeof(split)));
+
+ EXPECT_NO_DEATH(bcopy(&split, split.tiny_buffer, sizeof(split)));
+ EXPECT_NO_DEATH(bzero(split.tiny_buffer, sizeof(split)));
+
+ const char small_string[] = "Hi!!";
+ static_assert(sizeof(small_string) > sizeof(split.tiny_buffer), "");
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{string bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strcpy(split.tiny_buffer, small_string));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{string bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(stpcpy(split.tiny_buffer, small_string));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{size bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strncpy(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{size bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(stpncpy(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{string bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strcat(split.tiny_buffer, small_string));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{size bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strncat(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{size bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strlcat(split.tiny_buffer, small_string, sizeof(small_string)));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{size bigger than buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(strlcpy(split.tiny_buffer, small_string, sizeof(small_string)));
+ }
+}
+
+FORTIFY_TEST(fcntl) {
+ const char target[] = "/dev/null";
+ int dirfd = 0;
+
+ // These all emit hard errors without diagnose_if, so running them is a bit
+ // more involved.
+#ifdef COMPILATION_TESTS
+ // expected-error@+1{{too many arguments}}
+ open("/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ open64("/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ openat(0, "/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ openat64(0, "/", 0, 0, 0);
+#endif
+
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open(target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open(target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open64(target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open64(target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_TMPFILE));
+
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(open(target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(open64(target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(openat(dirfd, target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(openat64(dirfd, target, O_RDONLY, 0777));
+}
+
+// Since these emit hard errors, it's sort of hard to run them...
+#ifdef COMPILATION_TESTS
+namespace compilation_tests {
+template <typename T>
+static T declval() {
+ __builtin_unreachable();
+}
+
+static void testFormatStrings() {
+ const auto unsigned_value = declval<unsigned long long>();
+ const auto* unknown_string = declval<const char*>();
+ const auto va = *declval<va_list*>();
+
+ {
+ auto some_fd = declval<int>();
+ // expected-warning@+1{{format specifies type 'int'}}
+ dprintf(some_fd, "%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ dprintf(some_fd, unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ vdprintf(1, unknown_string, va);
+ }
+
+ {
+ auto* retval = declval<char*>();
+#if 0
+ // expected-error@+2{{ignoring return value}}
+#endif
+ // expected-warning@+1{{format specifies type 'int'}}
+ asprintf(&retval, "%d", unsigned_value);
+#if 0
+ // expected-error@+2{{ignoring return value}}
+#endif
+ // expected-warning@+1{{format string is not a string literal}}
+ asprintf(&retval, unknown_string, unsigned_value);
+#if 0
+ // expected-error@+2{{ignoring return value}}
+#endif
+ // expected-warning@+1{{format string is not a string literal}}
+ vasprintf(&retval, unknown_string, va);
+ }
+
+ // expected-warning@+1{{format specifies type 'int'}}
+ syslog(0, "%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ syslog(0, unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ vsyslog(0, unknown_string, va);
+
+ {
+ auto* file = declval<FILE*>();
+ // expected-warning@+1{{format specifies type 'int'}}
+ fprintf(file, "%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ fprintf(file, unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ vfprintf(file, unknown_string, va);
+ }
+
+ // expected-warning@+1{{format specifies type 'int'}}
+ printf("%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ printf(unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ vprintf(unknown_string, va);
+
+ {
+ char buf[128];
+ // expected-warning@+1{{format specifies type 'int'}}
+ sprintf(buf, "%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ sprintf(buf, unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ sprintf(buf, unknown_string, va);
+
+ // expected-warning@+1{{format specifies type 'int'}}
+ snprintf(buf, sizeof(buf), "%d", unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ snprintf(buf, sizeof(buf), unknown_string, unsigned_value);
+ // expected-warning@+1{{format string is not a string literal}}
+ vsnprintf(buf, sizeof(buf), unknown_string, va);
+ }
+
+ // FIXME: below are general format string cases where clang should probably try to warn.
+ {
+ char buf[4];
+ sprintf(buf, "%s", "1234");
+ sprintf(buf, "1%s4", "23");
+ sprintf(buf, "%d", 1234);
+
+ // Similar thoughts for strncpy, etc.
+ }
+}
+
+static void testStdlib() {
+ char path_buffer[PATH_MAX - 1];
+ // expected-warning@+2{{ignoring return value of function}}
+ // expected-error@+1{{must be NULL or a pointer to a buffer with >= PATH_MAX bytes}}
+ realpath("/", path_buffer);
+ // expected-warning@+1{{ignoring return value of function}}
+ realpath("/", nullptr);
+
+ // expected-warning@+2{{ignoring return value of function}}
+ // expected-error@+1{{flipped arguments?}}
+ realpath(nullptr, path_buffer);
+
+ // expected-warning@+2{{ignoring return value of function}}
+ // expected-error@+1{{flipped arguments?}}
+ realpath(nullptr, nullptr);
+}
+} // namespace compilation_tests
+#endif
+
+FORTIFY_TEST(poll) {
+ int pipe_fds[2];
+ if (pipe(pipe_fds)) err(1, "pipe failed");
+
+ // after this, pipe_fds[0] should always report RDHUP
+ if (close(pipe_fds[1])) err(1, "close failed");
+
+ struct pollfd poll_fd = { pipe_fds[0], POLLRDHUP, 0 };
+ {
+ struct pollfd few_fds[] = { poll_fd, poll_fd };
+ // expected-error@+1{{fd_count is larger than the given buffer}}
+ EXPECT_FORTIFY_DEATH(poll(few_fds, 3, 0));
+ // expected-error@+1{{fd_count is larger than the given buffer}}
+ EXPECT_FORTIFY_DEATH(ppoll(few_fds, 3, 0, 0));
+ // expected-error@+1{{fd_count is larger than the given buffer}}
+ EXPECT_FORTIFY_DEATH(ppoll64(few_fds, 3, 0, nullptr));
+ }
+
+ {
+ struct {
+ struct pollfd few[2];
+ struct pollfd extra[1];
+ } fds = { { poll_fd, poll_fd }, { poll_fd } };
+ static_assert(sizeof(fds) >= sizeof(struct pollfd) * 3, "");
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{fd_count is larger than the given buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(poll(fds.few, 3, 0));
+
+ struct timespec timeout = {};
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{fd_count is larger than the given buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(ppoll(fds.few, 3, &timeout, 0));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{fd_count is larger than the given buffer}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(ppoll64(fds.few, 3, 0, nullptr));
+ }
+}
+
+FORTIFY_TEST(socket) {
+ {
+ char small_buffer[8];
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(recv(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(recvfrom(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0, 0, 0));
+
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(send(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+ // expected-error@+1{{size bigger than buffer}}
+ EXPECT_FORTIFY_DEATH(sendto(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0, 0, 0));
+ }
+
+ {
+ struct {
+ char tiny_buffer[4];
+ char tiny_buffer2;
+ } split = {};
+
+ EXPECT_NO_DEATH(recv(kBogusFD, split.tiny_buffer, sizeof(split), 0));
+ EXPECT_NO_DEATH(recvfrom(kBogusFD, split.tiny_buffer, sizeof(split), 0, 0, 0));
+ }
+}
+
+FORTIFY_TEST(sys_stat) {
+ // expected-error@+1{{'umask' called with invalid mode}}
+ EXPECT_FORTIFY_DEATH(umask(01777));
+}
+
+FORTIFY_TEST(stdio) {
+ char small_buffer[8] = {};
+ {
+ // expected-error@+1{{size is larger than the destination buffer}}
+ EXPECT_FORTIFY_DEATH(snprintf(small_buffer, sizeof(small_buffer) + 1, ""));
+
+ va_list va;
+ // expected-error@+2{{size is larger than the destination buffer}}
+ // expected-warning@+1{{format string is empty}}
+ EXPECT_FORTIFY_DEATH(vsnprintf(small_buffer, sizeof(small_buffer) + 1, "", va));
+
+ const char *SOMETIMES_CONST format_string = "aaaaaaaaa";
+
+ // expected-error@+1{{format string will always overflow}}
+ EXPECT_FORTIFY_DEATH(sprintf(small_buffer, format_string));
+ }
+
+ // expected-error@+1{{size should not be negative}}
+ EXPECT_FORTIFY_DEATH(fgets(small_buffer, -1, stdin));
+ // expected-error@+1{{size is larger than the destination buffer}}
+ EXPECT_FORTIFY_DEATH(fgets(small_buffer, sizeof(small_buffer) + 1, stdin));
+
+ // expected-error@+1{{size * count overflows}}
+ EXPECT_NO_DEATH(fread(small_buffer, 2, (size_t)-1, stdin));
+ // expected-error@+1{{size * count is too large for the given buffer}}
+ EXPECT_FORTIFY_DEATH(fread(small_buffer, 1, sizeof(small_buffer) + 1, stdin));
+
+ // expected-error@+1{{size * count overflows}}
+ EXPECT_NO_DEATH(fwrite(small_buffer, 2, (size_t)-1, stdout));
+ // expected-error@+1{{size * count is too large for the given buffer}}
+ EXPECT_FORTIFY_DEATH(fwrite(small_buffer, 1, sizeof(small_buffer) + 1, stdout));
+}
+
+FORTIFY_TEST(unistd) {
+ char small_buffer[8];
+
+ // Return value warnings are (sort of) a part of FORTIFY, so we don't ignore them.
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(read(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(pread(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(pread64(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(write(kBogusFD, small_buffer, sizeof(small_buffer) + 1));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(pwrite(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(pwrite64(kBogusFD, small_buffer, sizeof(small_buffer) + 1, 0));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(readlink("/", small_buffer, sizeof(small_buffer) + 1));
+#if 0
+ // expected-error@+2{{ignoring return value of function}}
+#endif
+ // expected-error@+1{{bytes overflows the given object}}
+ EXPECT_FORTIFY_DEATH(getcwd(small_buffer, sizeof(small_buffer) + 1));
+
+ // getcwd allocates and returns a buffer if you pass null to getcwd
+ EXPECT_NO_DEATH(getcwd(nullptr, 0));
+ EXPECT_NO_DEATH(getcwd(nullptr, 4096));
+
+ struct {
+ char tiny_buffer[4];
+ char tiny_buffer2[4];
+ } split;
+
+ EXPECT_NO_DEATH(read(kBogusFD, split.tiny_buffer, sizeof(split)));
+ EXPECT_NO_DEATH(pread(kBogusFD, split.tiny_buffer, sizeof(split), 0));
+ EXPECT_NO_DEATH(pread64(kBogusFD, split.tiny_buffer, sizeof(split), 0));
+ EXPECT_NO_DEATH(write(kBogusFD, split.tiny_buffer, sizeof(split)));
+ EXPECT_NO_DEATH(pwrite(kBogusFD, split.tiny_buffer, sizeof(split), 0));
+ EXPECT_NO_DEATH(pwrite64(kBogusFD, split.tiny_buffer, sizeof(split), 0));
+
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{bytes overflows the given object}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(readlink("/", split.tiny_buffer, sizeof(split)));
+#if _FORTIFY_SOURCE > 1
+ // expected-error@+2{{bytes overflows the given object}}
+#endif
+ EXPECT_FORTIFY_DEATH_STRUCT(getcwd(split.tiny_buffer, sizeof(split)));
+
+ {
+ char* volatile unknown = small_buffer;
+ const size_t count = static_cast<size_t>(SSIZE_MAX) + 1;
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(read(kBogusFD, unknown, count));
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(pread(kBogusFD, unknown, count, 0));
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(pread64(kBogusFD, unknown, count, 0));
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(write(kBogusFD, unknown, count));
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(pwrite(kBogusFD, unknown, count, 0));
+ // expected-error@+1{{'count' must be <= SSIZE_MAX}}
+ EXPECT_FORTIFY_DEATH(pwrite64(kBogusFD, unknown, count, 0));
+ }
+}
+
+#endif // defined(__BIONIC__)
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 67ebf37df..e7274f704 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -29,9 +29,7 @@
#include <android-base/file.h>
#include <android-base/strings.h>
-#include <linux/memfd.h>
#include <sys/mman.h>
-#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/wait.h>
@@ -363,8 +361,10 @@ TEST_F(DlExtTest, ReservedRecursive) {
uint32_t* taxicab_number = reinterpret_cast<uint32_t*>(dlsym(handle_, "dlopen_testlib_taxicab_number"));
ASSERT_DL_NOTNULL(taxicab_number);
- EXPECT_GE(reinterpret_cast<void*>(taxicab_number), start);
- EXPECT_LT(reinterpret_cast<void*>(taxicab_number), reinterpret_cast<char*>(start) + kLibSize);
+ // Untag the pointer so that it can be compared with start, which will be untagged.
+ void* addr = reinterpret_cast<void*>(untag_address(taxicab_number));
+ EXPECT_GE(addr, start);
+ EXPECT_LT(addr, reinterpret_cast<char*>(start) + kLibSize);
EXPECT_EQ(1729U, *taxicab_number);
}
@@ -942,7 +942,7 @@ TEST(dlext, dlopen_ext_use_memfd) {
const std::string lib_path = GetTestlibRoot() + "/libtest_simple.so";
// create memfd
- int memfd = syscall(__NR_memfd_create, "foobar", MFD_CLOEXEC);
+ int memfd = memfd_create("foobar", MFD_CLOEXEC);
if (memfd == -1 && errno == ENOSYS) {
return;
}
diff --git a/tests/fortify_filecheck_diagnostics_test.cpp b/tests/fortify_filecheck_diagnostics_test.cpp
deleted file mode 100644
index ac9853c7f..000000000
--- a/tests/fortify_filecheck_diagnostics_test.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Silence all notes about enable_if-related 'candidates'; they're nice to know
- * about for users, but this test doesn't care.
- */
-// expected-note@* 0+{{candidate function}}
-
-/* Similarly, ignore all "from 'diagnose_if'"s. */
-// expected-note@* 0+{{from 'diagnose_if'}}
-
-
-#undef _FORTIFY_SOURCE
-#define _FORTIFY_SOURCE 2
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-
-#if !defined(__BIONIC__)
-# error "This only works with Bionic."
-#endif
-
-void test_sprintf() {
- char buf[4];
-
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{call to unavailable function 'sprintf': format string will always overflow destination buffer}}
- sprintf(buf, "foobar"); // NOLINT(runtime/printf)
-
- // TODO: clang should emit a warning, but doesn't
- sprintf(buf, "%s", "foobar"); // NOLINT(runtime/printf)
-}
-
-void test_snprintf() {
- char buf[4];
-
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{call to unavailable function 'snprintf': format string will always overflow destination buffer}}
- snprintf(buf, 5, "foobar"); // NOLINT(runtime/printf)
-
- // TODO: clang should emit a warning, but doesn't
- snprintf(buf, 5, "%s", "foobar"); // NOLINT(runtime/printf)
-
- // TODO: clang should emit a warning, but doesn't
- snprintf(buf, 5, " %s ", "foobar"); // NOLINT(runtime/printf)
-
- // TODO: clang should emit a warning, but doesn't
- snprintf(buf, 5, "%d", 100000); // NOLINT(runtime/printf)
-}
-
-void test_memcpy() {
- char buf[4];
-
- // expected-error@+1{{'memcpy' called with size bigger than buffer}}
- memcpy(buf, "foobar", sizeof("foobar") + 100);
-}
-
-void test_memmove() {
- char buf[4];
-
- // expected-error@+1{{'memmove' called with size bigger than buffer}}
- memmove(buf, "foobar", sizeof("foobar"));
-}
-
-void test_memset() {
- char buf[4];
-
- // expected-error@+1{{'memset' called with size bigger than buffer}}
- memset(buf, 0, 6);
-}
-
-void test_strcpy() {
- char buf[4];
-
- // expected-error@+1{{'strcpy' called with string bigger than buffer}}
- strcpy(buf, "foobar"); // NOLINT(runtime/printf)
-
- // expected-error@+1{{'strcpy' called with string bigger than buffer}}
- strcpy(buf, "quux");
-}
-
-void test_stpcpy() {
- char buf[4];
-
- // expected-error@+1{{'stpcpy' called with string bigger than buffer}}
- stpcpy(buf, "foobar");
-
- // expected-error@+1{{'stpcpy' called with string bigger than buffer}}
- stpcpy(buf, "quux");
-}
-
-void test_strncpy() {
- char buf[4];
-
- // TODO: clang should emit a warning, but doesn't
- strncpy(buf, "foobar", sizeof("foobar"));
-}
-
-void test_strcat() {
- char buf[4] = "";
-
- // TODO: clang should emit a warning, but doesn't
- strcat(buf, "foobar"); // NOLINT(runtime/printf)
-}
-
-void test_strncat() {
- char buf[4] = "";
-
- // TODO: clang should emit a warning, but doesn't
- strncat(buf, "foobar", sizeof("foobar"));
-}
-
-void test_vsprintf(const char* fmt, ...) {
- va_list va;
- char buf[4];
- va_start(va, fmt);
-
- // clang should emit a warning, but doesn't
- vsprintf(buf, "foobar", va);
- va_end(va);
-}
-
-void test_vsnprintf(const char* fmt, ...) {
- va_list va;
- char buf[4];
- va_start(va, fmt);
-
- // clang should emit a warning, but doesn't
- vsnprintf(buf, 5, "foobar", va); // NOLINT(runtime/printf)
-
- va_end(va);
-}
-
-void test_fgets() {
- char buf[4];
-
- // expected-error@+1{{in call to 'fgets', size should not be negative}}
- fgets(buf, -1, stdin);
-
- // expected-error@+1{{in call to 'fgets', size is larger than the destination buffer}}
- fgets(buf, 6, stdin);
-}
-
-void test_recvfrom() {
- char buf[4];
- sockaddr_in addr;
-
- // expected-error@+1{{'recvfrom' called with size bigger than buffer}}
- recvfrom(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), nullptr);
-}
-
-void test_recv() {
- char buf[4] = {0};
-
- // expected-error@+1{{'recv' called with size bigger than buffer}}
- recv(0, buf, 6, 0);
-}
-
-void test_umask() {
- // expected-error@+1{{'umask' called with invalid mode}}
- umask(01777);
-}
-
-void test_read() {
- char buf[4];
- // expected-error@+1{{in call to 'read', 'count' bytes overflows the given object}}
- read(0, buf, 6);
-}
-
-void test_open() {
- // expected-error@+1{{'open' called with O_CREAT or O_TMPFILE, but missing mode}}
- open("/dev/null", O_CREAT);
-
- // expected-error@+1{{'open' called with O_CREAT or O_TMPFILE, but missing mode}}
- open("/dev/null", O_TMPFILE);
-
- // expected-error@+1{{call to unavailable function 'open': too many arguments}}
- open("/dev/null", O_CREAT, 0, 0);
-
- // expected-error@+1{{call to unavailable function 'open': too many arguments}}
- open("/dev/null", O_TMPFILE, 0, 0);
-
- // expected-warning@+1{{'open' has superfluous mode bits; missing O_CREAT?}}
- open("/dev/null", O_RDONLY, 0644);
-
- // expected-warning@+1{{'open' has superfluous mode bits; missing O_CREAT?}}
- open("/dev/null", O_DIRECTORY, 0644);
-}
-
-void test_poll() {
- pollfd fds[1];
- // expected-error@+1{{in call to 'poll', fd_count is larger than the given buffer}}
- poll(fds, 2, 0);
-}
-
-void test_ppoll() {
- pollfd fds[1];
- timespec timeout;
- // expected-error@+1{{in call to 'ppoll', fd_count is larger than the given buffer}}
- ppoll(fds, 2, &timeout, nullptr);
-}
-
-void test_ppoll64() {
- pollfd fds[1];
- timespec timeout;
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{in call to 'ppoll64', fd_count is larger than the given buffer}}
- ppoll64(fds, 2, &timeout, nullptr);
-}
-
-void test_fread_overflow() {
- char buf[4];
- // expected-error@+1{{in call to 'fread', size * count overflows}}
- fread(buf, 2, (size_t)-1, stdin);
-}
-
-void test_fread_too_big() {
- char buf[4];
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{in call to 'fread', size * count is too large for the given buffer}}
- fread(buf, 1, 5, stdin);
-}
-
-void test_fwrite_overflow() {
- char buf[4] = {0};
- // expected-error@+1{{in call to 'fwrite', size * count overflows}}
- fwrite(buf, 2, (size_t)-1, stdout);
-}
-
-void test_fwrite_too_big() {
- char buf[4] = {0};
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{in call to 'fwrite', size * count is too large for the given buffer}}
- fwrite(buf, 1, 5, stdout);
-}
-
-void test_getcwd() {
- char buf[4];
- // expected-error@+1{{in call to 'getcwd', 'size' bytes overflows the given object}}
- getcwd(buf, 5);
-}
-
-void test_pwrite64_size() {
- char buf[4] = {0};
- // expected-error@+1{{in call to 'pwrite64', 'count' bytes overflows the given object}}
- pwrite64(STDOUT_FILENO, buf, 5, 0);
-}
-
-void test_pwrite64_too_big_malloc() {
- void *buf = calloc(atoi("5"), 1);
- // expected-error@+1{{in call to 'pwrite64', 'count' must be <= SSIZE_MAX}}
- pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
-}
-
-void test_pwrite64_too_big() {
- char buf[4] = {0};
- // expected-error@+1{{in call to 'pwrite64', 'count' must be <= SSIZE_MAX}}
- pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
-}
-
-void test_write_size() {
- char buf[4] = {0};
- // expected-error@+1{{in call to 'write', 'count' bytes overflows the given object}}
- write(STDOUT_FILENO, buf, 5);
-}
-
-void test_memset_args_flipped() {
- char from[4] = {0};
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-warning@+1{{'memset' will set 0 bytes; maybe the arguments got flipped?}}
- memset(from, sizeof(from), 0);
-}
-
-void test_sendto() {
- char buf[4] = {0};
- sockaddr_in addr;
-
- // expected-error@+1{{'sendto' called with size bigger than buffer}}
- sendto(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_in));
-}
-
-void test_send() {
- char buf[4] = {0};
-
- // expected-error@+1{{'send' called with size bigger than buffer}}
- send(0, buf, 6, 0);
-}
-
-void test_realpath() {
- char buf[4] = {0};
- // NOLINTNEXTLINE(whitespace/line_length)
- // expected-error@+1{{'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes}}
- realpath(".", buf);
-
- // This is fine.
- realpath(".", nullptr);
-
- char bigbuf[PATH_MAX];
- // expected-error@+1{{'realpath': NULL path is never correct; flipped arguments?}}
- realpath(nullptr, bigbuf);
-}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 489b7018d..9a4b781fc 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -926,6 +926,24 @@ TEST(TEST_NAME, strcat_chk_max_int_size) {
ASSERT_EQ('\0', buf[9]);
}
+TEST(TEST_NAME, mempcpy_chk) {
+ const char input_str[] = "abcdefg";
+ size_t input_str_size = strlen(input_str) + 1;
+
+ char buf1[10] = {};
+ char buf2[10] = {};
+
+ __builtin_mempcpy(buf1, input_str, input_str_size);
+ __builtin___mempcpy_chk(buf2, input_str, input_str_size, __bos0(buf2));
+
+ ASSERT_EQ(memcmp(buf1, buf2, sizeof(buf2)), 0);
+
+ void *builtin_ptr = __builtin_mempcpy(buf1, input_str, input_str_size);
+ void *fortify_ptr = __builtin___mempcpy_chk(buf1, input_str, input_str_size, __bos0(buf2));
+
+ ASSERT_EQ(builtin_ptr, fortify_ptr);
+}
+
extern "C" char* __stpcpy_chk(char*, const char*, size_t);
TEST(TEST_NAME, stpcpy_chk_max_int_size) {
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index ebc357c4b..6b49e298e 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -46,6 +46,8 @@ using android::base::ReadFileToString;
using android::base::Split;
using android::base::StartsWith;
+using namespace std::literals;
+
enum uid_type_t {
TYPE_APP,
TYPE_SYSTEM,
@@ -73,11 +75,7 @@ static void check_passwd(const passwd* pwd, const char* username, uid_t uid, uid
EXPECT_STREQ("/", pwd->pw_dir);
}
- if (uid_type == TYPE_VENDOR) {
- EXPECT_STREQ("/vendor/bin/sh", pwd->pw_shell);
- } else {
- EXPECT_STREQ("/system/bin/sh", pwd->pw_shell);
- }
+ EXPECT_STREQ("/bin/sh", pwd->pw_shell);
}
static void check_getpwuid(const char* username, uid_t uid, uid_type_t uid_type,
@@ -130,12 +128,41 @@ static void check_getpwnam_r(const char* username, uid_t uid, uid_type_t uid_typ
static void check_get_passwd(const char* username, uid_t uid, uid_type_t uid_type,
bool check_username = true) {
+ SCOPED_TRACE("username '"s + username + "'");
check_getpwuid(username, uid, uid_type, check_username);
check_getpwnam(username, uid, uid_type, check_username);
check_getpwuid_r(username, uid, uid_type, check_username);
check_getpwnam_r(username, uid, uid_type, check_username);
}
+static void expect_no_passwd_id(uid_t uid) {
+ SCOPED_TRACE("uid '" + std::to_string(uid) + "'");
+ errno = 0;
+ passwd* passwd = nullptr;
+ passwd = getpwuid(uid);
+ EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
+ EXPECT_EQ(ENOENT, errno);
+
+ struct passwd passwd_storage;
+ char buf[512];
+ EXPECT_EQ(ENOENT, getpwuid_r(uid, &passwd_storage, buf, sizeof(buf), &passwd));
+ EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
+}
+
+static void expect_no_passwd_name(const char* username) {
+ SCOPED_TRACE("username '"s + username + "'");
+ errno = 0;
+ passwd* passwd = nullptr;
+ passwd = getpwnam(username);
+ EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
+ EXPECT_EQ(ENOENT, errno);
+
+ struct passwd passwd_storage;
+ char buf[512];
+ EXPECT_EQ(ENOENT, getpwnam_r(username, &passwd_storage, buf, sizeof(buf), &passwd));
+ EXPECT_EQ(nullptr, passwd) << "name = '" << passwd->pw_name << "'";
+}
+
#else // !defined(__BIONIC__)
static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_type_t /* uid_type */,
@@ -147,75 +174,124 @@ static void check_get_passwd(const char* /* username */, uid_t /* uid */, uid_ty
GTEST_SKIP() << "bionic-only test";
}
+static void expect_no_passwd_id(uid_t /* uid */) {
+ GTEST_SKIP() << "bionic-only test";
+}
+
+static void expect_no_passwd_name(const char* /* username */) {
+ GTEST_SKIP() << "bionic-only test";
+}
+
#endif
-TEST(pwd, getpwnam_system_id_root) {
+TEST(pwd, getpwnam_platform_ids) {
check_get_passwd("root", 0, TYPE_SYSTEM);
-}
+ check_get_passwd("daemon", 1, TYPE_SYSTEM);
+ check_get_passwd("bin", 2, TYPE_SYSTEM);
-TEST(pwd, getpwnam_system_id_system) {
check_get_passwd("system", 1000, TYPE_SYSTEM);
-}
-
-TEST(pwd, getpwnam_app_id_radio) {
check_get_passwd("radio", 1001, TYPE_SYSTEM);
-}
-TEST(pwd, getpwnam_oem_id_5000) {
- check_get_passwd("oem_5000", 5000, TYPE_VENDOR, false);
-}
+ check_get_passwd("shell", 2000, TYPE_SYSTEM);
-TEST(pwd, getpwnam_oem_id_5999) {
- check_get_passwd("oem_5999", 5999, TYPE_VENDOR, false);
+ check_get_passwd("nobody", 9999, TYPE_SYSTEM);
}
-TEST(pwd, getpwnam_oem_id_2900) {
+TEST(pwd, getpwnam_oem_ids) {
check_get_passwd("oem_2900", 2900, TYPE_VENDOR, false);
-}
-
-TEST(pwd, getpwnam_oem_id_2999) {
+ check_get_passwd("oem_2945", 2945, TYPE_VENDOR, false);
check_get_passwd("oem_2999", 2999, TYPE_VENDOR, false);
+ check_get_passwd("oem_5000", 5000, TYPE_VENDOR, false);
+ check_get_passwd("oem_5454", 5454, TYPE_VENDOR, false);
+ check_get_passwd("oem_5999", 5999, TYPE_VENDOR, false);
}
-TEST(pwd, getpwnam_app_id_nobody) {
- check_get_passwd("nobody", 9999, TYPE_SYSTEM);
-}
+TEST(pwd, getpwnam_non_exist) {
+ expect_no_passwd_id(999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(1999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(2899); // End of the system reserved range, unallocated.
-TEST(pwd, getpwnam_app_id_u0_a0) {
- check_get_passwd("u0_a0", 10000, TYPE_APP);
-}
+ // These ranges are for GIDs only.
+ expect_no_passwd_id(20000);
+ expect_no_passwd_id(30000);
+ expect_no_passwd_id(40000);
+ expect_no_passwd_id(50000);
-TEST(pwd, getpwnam_app_id_u0_a1234) {
- check_get_passwd("u0_a1234", 11234, TYPE_APP);
+ // These should not be parsed as users, only as groups.
+ expect_no_passwd_name("u0_a9999_cache");
+ expect_no_passwd_name("u0_a9999_ext");
+ expect_no_passwd_name("u0_a9999_ext_cache");
+ expect_no_passwd_name("all_a9999");
}
-// Test the difference between uid and shared gid.
-TEST(pwd, getpwnam_app_id_u0_a49999) {
- check_get_passwd("u0_a49999", 59999, TYPE_APP);
-}
+TEST(pwd, getpwnam_u0_app_ids) {
+ check_get_passwd("u0_a0", 10000, TYPE_APP);
+ check_get_passwd("u0_a1234", 11234, TYPE_APP);
+ check_get_passwd("u0_a9999", 19999, TYPE_APP);
-TEST(pwd, getpwnam_app_id_u0_i1) {
check_get_passwd("u0_i1", 90001, TYPE_APP);
+ check_get_passwd("u0_i4545", 94545, TYPE_APP);
+ check_get_passwd("u0_i9999", 99999, TYPE_APP);
}
-TEST(pwd, getpwnam_app_id_u1_root) {
- check_get_passwd("u1_root", 100000, TYPE_SYSTEM);
+TEST(pwd, getpwnam_app_id_u1_ids) {
+ check_get_passwd("u1_system", 101000, TYPE_SYSTEM);
+ check_get_passwd("u1_radio", 101001, TYPE_SYSTEM);
+
+ check_get_passwd("u1_a0", 110000, TYPE_APP);
+ check_get_passwd("u1_a1234", 111234, TYPE_APP);
+ check_get_passwd("u1_a9999", 119999, TYPE_APP);
+
+ check_get_passwd("u1_i1", 190001, TYPE_APP);
+ check_get_passwd("u1_i4545", 194545, TYPE_APP);
+ check_get_passwd("u1_i9999", 199999, TYPE_APP);
}
-TEST(pwd, getpwnam_app_id_u1_radio) {
- check_get_passwd("u1_radio", 101001, TYPE_SYSTEM);
+TEST(pwd, getpwnam_app_id_u31_ids) {
+ check_get_passwd("u31_system", 3101000, TYPE_SYSTEM);
+ check_get_passwd("u31_radio", 3101001, TYPE_SYSTEM);
+
+ check_get_passwd("u31_a0", 3110000, TYPE_APP);
+ check_get_passwd("u31_a1234", 3111234, TYPE_APP);
+ check_get_passwd("u31_a9999", 3119999, TYPE_APP);
+
+ check_get_passwd("u31_i1", 3190001, TYPE_APP);
+ check_get_passwd("u31_i4545", 3194545, TYPE_APP);
+ check_get_passwd("u31_i9999", 3199999, TYPE_APP);
}
-TEST(pwd, getpwnam_app_id_u1_a0) {
- check_get_passwd("u1_a0", 110000, TYPE_APP);
+TEST(pwd, getpwnam_app_id_not_allowed_platform) {
+ expect_no_passwd_name("u1_root");
+ expect_no_passwd_name("u1_debuggerd");
+
+ expect_no_passwd_name("u31_root");
+ expect_no_passwd_name("u31_debuggerd");
}
-TEST(pwd, getpwnam_app_id_u1_a40000) {
- check_get_passwd("u1_a40000", 150000, TYPE_APP);
+TEST(pwd, getpwuid_app_id_u1_non_exist) {
+ expect_no_passwd_id(100000); // There is no 'root' for secondary users.
+ expect_no_passwd_id(101999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(102900); // The OEM ranges were never allocated to secondary users.
+ expect_no_passwd_id(105000); // The OEM ranges were never allocated to secondary users.
+
+ // These ranges are for GIDs only.
+ expect_no_passwd_id(120000);
+ expect_no_passwd_id(130000);
+ expect_no_passwd_id(140000);
+ expect_no_passwd_id(150000);
}
-TEST(pwd, getpwnam_app_id_u1_i0) {
- check_get_passwd("u1_i0", 190000, TYPE_APP);
+TEST(pwd, getpwuid_app_id_u31_non_exist) {
+ expect_no_passwd_id(3100000); // There is no 'root' for secondary users.
+ expect_no_passwd_id(3101999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(3102900); // The OEM ranges were never allocated to secondary users.
+ expect_no_passwd_id(3105000); // The OEM ranges were never allocated to secondary users.
+
+ // These ranges are for GIDs only.
+ expect_no_passwd_id(3120000);
+ expect_no_passwd_id(3130000);
+ expect_no_passwd_id(3140000);
+ expect_no_passwd_id(3150000);
}
TEST(pwd, getpwnam_r_alignment) {
@@ -302,7 +378,7 @@ TEST(pwd, getpwnam_r_large_enough_suggested_buffer_size) {
#if defined(__BIONIC__)
template <typename T>
-static void expect_ids(const T& ids) {
+static void expect_ids(T ids, bool is_group) {
std::set<typename T::key_type> expected_ids;
// Ensure that all android_ids are iterated through.
for (size_t n = 0; n < android_id_count; ++n) {
@@ -321,10 +397,12 @@ static void expect_ids(const T& ids) {
expect_range(AID_OEM_RESERVED_START, AID_OEM_RESERVED_END);
expect_range(AID_OEM_RESERVED_2_START, AID_OEM_RESERVED_2_END);
expect_range(AID_APP_START, AID_APP_END);
- expect_range(AID_CACHE_GID_START, AID_CACHE_GID_END);
- expect_range(AID_EXT_GID_START, AID_EXT_GID_END);
- expect_range(AID_EXT_CACHE_GID_START, AID_EXT_CACHE_GID_END);
- expect_range(AID_SHARED_GID_START, AID_SHARED_GID_END);
+ if (is_group) {
+ expect_range(AID_CACHE_GID_START, AID_CACHE_GID_END);
+ expect_range(AID_EXT_GID_START, AID_EXT_GID_END);
+ expect_range(AID_EXT_CACHE_GID_START, AID_EXT_CACHE_GID_END);
+ expect_range(AID_SHARED_GID_START, AID_SHARED_GID_END);
+ }
expect_range(AID_ISOLATED_START, AID_ISOLATED_END);
// TODO(73062966): We still don't have a good way to create vendor AIDs in the system or other
@@ -333,6 +411,14 @@ static void expect_ids(const T& ids) {
return;
}
+ auto allow_range = [&ids](uid_t start, uid_t end) {
+ for (size_t n = start; n <= end; ++n) {
+ ids.erase(n);
+ }
+ };
+
+ allow_range(AID_SYSTEM_RESERVED_START, AID_SYSTEM_EXT_RESERVED_END);
+
// Ensure that no other ids were returned.
auto return_differences = [&ids, &expected_ids] {
std::vector<typename T::key_type> missing_from_ids;
@@ -388,7 +474,7 @@ TEST(pwd, getpwent_iterate) {
}
endpwent();
- expect_ids(uids);
+ expect_ids(uids, false);
#else
GTEST_SKIP() << "bionic-only test";
#endif
@@ -453,12 +539,41 @@ static void check_getgrnam_r(const char* group_name, gid_t gid, bool check_group
}
static void check_get_group(const char* group_name, gid_t gid, bool check_groupname = true) {
+ SCOPED_TRACE("groupname '"s + group_name + "'");
check_getgrgid(group_name, gid, check_groupname);
check_getgrnam(group_name, gid, check_groupname);
check_getgrgid_r(group_name, gid, check_groupname);
check_getgrnam_r(group_name, gid, check_groupname);
}
+static void expect_no_group_id(gid_t gid) {
+ SCOPED_TRACE("gid '" + std::to_string(gid) + "'");
+ errno = 0;
+ group* group = nullptr;
+ group = getgrgid(gid);
+ EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
+ EXPECT_EQ(ENOENT, errno);
+
+ struct group group_storage;
+ char buf[512];
+ EXPECT_EQ(ENOENT, getgrgid_r(gid, &group_storage, buf, sizeof(buf), &group));
+ EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
+}
+
+static void expect_no_group_name(const char* groupname) {
+ SCOPED_TRACE("groupname '"s + groupname + "'");
+ errno = 0;
+ group* group = nullptr;
+ group = getgrnam(groupname);
+ EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
+ EXPECT_EQ(ENOENT, errno);
+
+ struct group group_storage;
+ char buf[512];
+ EXPECT_EQ(ENOENT, getgrnam_r(groupname, &group_storage, buf, sizeof(buf), &group));
+ EXPECT_EQ(nullptr, group) << "name = '" << group->gr_name << "'";
+}
+
#else // !defined(__BIONIC__)
static void check_get_group(const char*, gid_t, bool) {
@@ -469,95 +584,144 @@ static void check_get_group(const char*, gid_t) {
GTEST_SKIP() << "bionic-only test";
}
+static void expect_no_group_id(gid_t /* gid */) {
+ GTEST_SKIP() << "bionic-only test";
+}
+
+static void expect_no_group_name(const char* /* groupname */) {
+ GTEST_SKIP() << "bionic-only test";
+}
+
#endif
-TEST(grp, getgrnam_system_id_root) {
+TEST(grp, getgrnam_platform_ids) {
check_get_group("root", 0);
-}
+ check_get_group("daemon", 1);
+ check_get_group("bin", 2);
-TEST(grp, getgrnam_system_id_system) {
check_get_group("system", 1000);
-}
-
-TEST(grp, getgrnam_app_id_radio) {
check_get_group("radio", 1001);
-}
-TEST(grp, getgrnam_oem_id_5000) {
- check_get_group("oem_5000", 5000, false);
-}
+ check_get_group("shell", 2000);
-TEST(grp, getgrnam_oem_id_5999) {
- check_get_group("oem_5999", 5999, false);
+ check_get_group("nobody", 9999);
}
-TEST(grp, getgrnam_oem_id_2900) {
+TEST(grp, getgrnam_oem_ids) {
check_get_group("oem_2900", 2900, false);
-}
-
-TEST(grp, getgrnam_oem_id_2999) {
+ check_get_group("oem_2945", 2945, false);
check_get_group("oem_2999", 2999, false);
+ check_get_group("oem_5000", 5000, false);
+ check_get_group("oem_5454", 5454, false);
+ check_get_group("oem_5999", 5999, false);
}
-TEST(grp, getgrnam_app_id_nobody) {
- check_get_group("nobody", 9999);
+TEST(grp, getgrnam_non_exist) {
+ expect_no_passwd_id(999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(1999); // End of the system reserved range, unallocated.
+ expect_no_passwd_id(2899); // End of the system reserved range, unallocated.
}
-TEST(grp, getgrnam_app_id_u0_a0) {
+TEST(grp, getgrnam_u0_app_ids) {
check_get_group("u0_a0", 10000);
-}
-
-TEST(grp, getgrnam_app_id_u0_a1234) {
check_get_group("u0_a1234", 11234);
-}
-
-TEST(grp, getgrnam_app_id_u0_a9999) {
check_get_group("u0_a9999", 19999);
-}
-TEST(getgrnam, app_id_u0_a0_cache) {
check_get_group("u0_a0_cache", 20000);
-}
-
-TEST(getgrnam, app_id_u0_a1234_cache) {
check_get_group("u0_a1234_cache", 21234);
-}
-
-TEST(getgrnam, app_id_u0_a9999_cache) {
check_get_group("u0_a9999_cache", 29999);
-}
-TEST(getgrnam, app_id_u10_a1234_cache) {
- check_get_group("u10_a1234_cache", 1021234);
-}
+ check_get_group("u0_a0_ext", 30000);
+ check_get_group("u0_a4545_ext", 34545);
+ check_get_group("u0_a9999_ext", 39999);
+
+ check_get_group("u0_a0_ext_cache", 40000);
+ check_get_group("u0_a4545_ext_cache", 44545);
+ check_get_group("u0_a9999_ext_cache", 49999);
-// Test the difference between uid and shared gid.
-TEST(grp, getgrnam_app_id_all_a9999) {
+ check_get_group("all_a0", 50000);
+ check_get_group("all_a4545", 54545);
check_get_group("all_a9999", 59999);
-}
-TEST(grp, getgrnam_app_id_u0_i1) {
check_get_group("u0_i1", 90001);
}
-TEST(grp, getgrnam_app_id_u1_root) {
- check_get_group("u1_root", 100000);
+TEST(grp, getgrnam_u1_app_ids) {
+ check_get_group("u1_system", 101000);
+ check_get_group("u1_radio", 101001);
+
+ check_get_group("u1_a0", 110000);
+ check_get_group("u1_a1234", 111234);
+ check_get_group("u1_a9999", 119999);
+
+ check_get_group("u1_a0_cache", 120000);
+ check_get_group("u1_a1234_cache", 121234);
+ check_get_group("u1_a9999_cache", 129999);
+
+ check_get_group("u1_a0_ext", 130000);
+ check_get_group("u1_a4545_ext", 134545);
+ check_get_group("u1_a9999_ext", 139999);
+
+ check_get_group("u1_a0_ext_cache", 140000);
+ check_get_group("u1_a4545_ext_cache", 144545);
+ check_get_group("u1_a9999_ext_cache", 149999);
+
+ check_get_group("u1_i1", 190001);
}
-TEST(grp, getgrnam_app_id_u1_radio) {
- check_get_group("u1_radio", 101001);
+TEST(grp, getgrnam_u31_app_ids) {
+ check_get_group("u31_system", 3101000);
+ check_get_group("u31_radio", 3101001);
+
+ check_get_group("u31_a0", 3110000);
+ check_get_group("u31_a1234", 3111234);
+ check_get_group("u31_a9999", 3119999);
+
+ check_get_group("u31_a0_cache", 3120000);
+ check_get_group("u31_a1234_cache", 3121234);
+ check_get_group("u31_a9999_cache", 3129999);
+
+ check_get_group("u31_a0_cache", 3120000);
+ check_get_group("u31_a1234_cache", 3121234);
+ check_get_group("u31_a9999_cache", 3129999);
+
+ check_get_group("u31_a0_ext", 3130000);
+ check_get_group("u31_a4545_ext", 3134545);
+ check_get_group("u31_a9999_ext", 3139999);
+
+ check_get_group("u31_a0_ext_cache", 3140000);
+ check_get_group("u31_a4545_ext_cache", 3144545);
+ check_get_group("u31_a9999_ext_cache", 3149999);
+
+ check_get_group("u31_i1", 3190001);
}
-TEST(grp, getgrnam_app_id_u1_a0) {
- check_get_group("u1_a0", 110000);
+TEST(grp, getpgram_app_id_not_allowed_platform) {
+ expect_no_group_name("u1_root");
+ expect_no_group_name("u1_debuggerd");
+
+ expect_no_group_name("u31_root");
+ expect_no_group_name("u31_debuggerd");
}
-TEST(grp, getgrnam_app_id_u1_a40000) {
- check_get_group("u1_a40000", 150000);
+TEST(grp, getgrgid_app_id_u1_non_exist) {
+ expect_no_group_id(100000); // There is no 'root' for secondary users.
+ expect_no_group_id(101999); // End of the system reserved range, unallocated.
+ expect_no_group_id(102900); // The OEM ranges were never allocated to secondary users.
+ expect_no_group_id(105000); // The OEM ranges were never allocated to secondary users.
+
+ // The shared range is shared among users, and therefore doesn't exist for secondary users.
+ expect_no_group_id(150000);
}
-TEST(grp, getgrnam_app_id_u1_i0) {
- check_get_group("u1_i0", 190000);
+TEST(grp, getgrgid_app_id_u31_non_exist) {
+ expect_no_group_id(3100000); // There is no 'root' for secondary users.
+ expect_no_group_id(3101999); // End of the system reserved range, unallocated.
+ expect_no_group_id(3102900); // The OEM ranges were never allocated to secondary users.
+ expect_no_group_id(3105000); // The OEM ranges were never allocated to secondary users.
+
+ // The shared range is shared among users, and therefore doesn't exist for secondary users.
+ expect_no_group_id(3150000);
}
TEST(grp, getgrnam_r_alignment) {
@@ -660,7 +824,7 @@ TEST(grp, getgrent_iterate) {
}
endgrent();
- expect_ids(gids);
+ expect_ids(gids, true);
#else
GTEST_SKIP() << "bionic-only test";
#endif
diff --git a/tests/leak_test.cpp b/tests/leak_test.cpp
index 600520959..3cc1a0a91 100644
--- a/tests/leak_test.cpp
+++ b/tests/leak_test.cpp
@@ -17,6 +17,7 @@
#include <err.h>
#include <inttypes.h>
#include <pthread.h>
+#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
@@ -30,26 +31,28 @@
#include <vector>
#include <android-base/macros.h>
+#include <android-base/threads.h>
#include "utils.h"
using namespace std::chrono_literals;
-static void WaitUntilAllExited(pid_t* pids, size_t pid_count) {
+static void WaitUntilAllThreadsExited(pid_t* tids, size_t tid_count) {
// Wait until all children have exited.
bool alive = true;
while (alive) {
alive = false;
- for (size_t i = 0; i < pid_count; ++i) {
- if (pids[i] != 0) {
- if (kill(pids[i], 0) == 0) {
+ for (size_t i = 0; i < tid_count; ++i) {
+ if (tids[i] != 0) {
+ if (tgkill(getpid(), tids[i], 0) == 0) {
alive = true;
} else {
EXPECT_EQ(errno, ESRCH);
- pids[i] = 0; // Skip in next loop.
+ tids[i] = 0; // Skip in next loop.
}
}
}
+ sched_yield();
}
}
@@ -155,7 +158,7 @@ TEST(pthread_leak, detach) {
pthread_barrier_wait(&barrier);
ASSERT_EQ(pthread_barrier_destroy(&barrier), 0);
- WaitUntilAllExited(tids, arraysize(tids));
+ WaitUntilAllThreadsExited(tids, threads_count);
// A native bridge implementation might need a warm up pass to reach a steady state.
// http://b/37920774.
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 422cd75c0..98d4f25e7 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -29,7 +29,7 @@ cc_defaults {
gtest: false,
sanitize: {
address: false,
- coverage: false,
+ fuzzer: false,
},
stl: "libc++_static",
target: {
diff --git a/tests/libs/segment_gap_outer.lds b/tests/libs/segment_gap_outer.lds
index f326aab26..c2961b2c6 100644
--- a/tests/libs/segment_gap_outer.lds
+++ b/tests/libs/segment_gap_outer.lds
@@ -22,6 +22,6 @@ SECTIONS {
# Place end_of_gap at the end of the gap.
. = 0x1000000;
.bss.end_of_gap : {
- *(.bss.end_of_gap);
+ *(.bss.*end_of_gap*);
}
}
diff --git a/tests/make_fortify_compile_test.mk b/tests/make_fortify_compile_test.mk
new file mode 100644
index 000000000..8270f29d7
--- /dev/null
+++ b/tests/make_fortify_compile_test.mk
@@ -0,0 +1,20 @@
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk \
+ $(LOCAL_PATH)/touch-obj-on-success
+
+LOCAL_CXX := $(LOCAL_PATH)/touch-obj-on-success \
+ $(LLVM_PREBUILTS_PATH)/clang++ \
+
+LOCAL_CLANG := true
+LOCAL_MODULE := bionic-compile-time-tests$(FORTIFY_LEVEL)-clang++
+LOCAL_CPPFLAGS := -Wall -Wno-error
+LOCAL_CPPFLAGS += -fno-color-diagnostics -ferror-limit=10000 -Xclang -verify
+LOCAL_CPPFLAGS += -DCOMPILATION_TESTS=1 -Wformat-nonliteral
+LOCAL_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=$(FORTIFY_LEVEL)
+LOCAL_SRC_FILES := clang_fortify_tests.cpp
+
+include $(BUILD_STATIC_LIBRARY)
+
+FORTIFY_LEVEL :=
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 983592f0a..edcc179ed 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -312,32 +312,48 @@ TEST(malloc, realloc_overflow) {
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
extern "C" void* pvalloc(size_t);
extern "C" void* valloc(size_t);
+#endif
TEST(malloc, pvalloc_std) {
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
size_t pagesize = sysconf(_SC_PAGESIZE);
void* ptr = pvalloc(100);
ASSERT_TRUE(ptr != nullptr);
ASSERT_TRUE((reinterpret_cast<uintptr_t>(ptr) & (pagesize-1)) == 0);
ASSERT_LE(pagesize, malloc_usable_size(ptr));
free(ptr);
+#else
+ GTEST_SKIP() << "pvalloc not supported.";
+#endif
}
TEST(malloc, pvalloc_overflow) {
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
ASSERT_EQ(nullptr, pvalloc(SIZE_MAX));
+#else
+ GTEST_SKIP() << "pvalloc not supported.";
+#endif
}
TEST(malloc, valloc_std) {
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
size_t pagesize = sysconf(_SC_PAGESIZE);
- void* ptr = pvalloc(100);
+ void* ptr = valloc(100);
ASSERT_TRUE(ptr != nullptr);
ASSERT_TRUE((reinterpret_cast<uintptr_t>(ptr) & (pagesize-1)) == 0);
free(ptr);
+#else
+ GTEST_SKIP() << "valloc not supported.";
+#endif
}
TEST(malloc, valloc_overflow) {
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
ASSERT_EQ(nullptr, valloc(SIZE_MAX));
-}
+#else
+ GTEST_SKIP() << "valloc not supported.";
#endif
+}
TEST(malloc, malloc_info) {
#ifdef __BIONIC__
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 0bf8e294b..d8257381c 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -990,6 +990,25 @@ TEST(pthread, pthread_rwlock_reader_wakeup_writer_timedwait_monotonic_np) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_rwlock_reader_wakeup_writer_clockwait) {
+#if defined(__BIONIC__)
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_reader_wakeup_writer([&](pthread_rwlock_t* lock) {
+ return pthread_rwlock_clockwrlock(lock, CLOCK_MONOTONIC, &ts);
+ });
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_reader_wakeup_writer([&](pthread_rwlock_t* lock) {
+ return pthread_rwlock_clockwrlock(lock, CLOCK_REALTIME, &ts);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockwrlock not available";
+#endif // __BIONIC__
+}
+
static void test_pthread_rwlock_writer_wakeup_reader(std::function<int (pthread_rwlock_t*)> lock_function) {
RwlockWakeupHelperArg wakeup_arg;
ASSERT_EQ(0, pthread_rwlock_init(&wakeup_arg.lock, nullptr));
@@ -1038,6 +1057,25 @@ TEST(pthread, pthread_rwlock_writer_wakeup_reader_timedwait_monotonic_np) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_rwlock_writer_wakeup_reader_clockwait) {
+#if defined(__BIONIC__)
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_writer_wakeup_reader([&](pthread_rwlock_t* lock) {
+ return pthread_rwlock_clockrdlock(lock, CLOCK_MONOTONIC, &ts);
+ });
+
+ ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
+ ts.tv_sec += 1;
+ test_pthread_rwlock_writer_wakeup_reader([&](pthread_rwlock_t* lock) {
+ return pthread_rwlock_clockrdlock(lock, CLOCK_REALTIME, &ts);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockrdlock not available";
+#endif // __BIONIC__
+}
+
static void pthread_rwlock_wakeup_timeout_helper(RwlockWakeupHelperArg* arg) {
arg->tid = gettid();
ASSERT_EQ(RwlockWakeupHelperArg::LOCK_INITIALIZED, arg->progress);
@@ -1098,6 +1136,38 @@ TEST(pthread, pthread_rwlock_timedrdlock_monotonic_np_timeout) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_rwlock_clockrdlock_monotonic_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedrdlock_timeout_helper(
+ CLOCK_MONOTONIC, [](pthread_rwlock_t* __rwlock, const timespec* __timeout) {
+ return pthread_rwlock_clockrdlock(__rwlock, CLOCK_MONOTONIC, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockrdlock not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_rwlock_clockrdlock_realtime_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedrdlock_timeout_helper(
+ CLOCK_REALTIME, [](pthread_rwlock_t* __rwlock, const timespec* __timeout) {
+ return pthread_rwlock_clockrdlock(__rwlock, CLOCK_REALTIME, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockrdlock not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_rwlock_clockrdlock_invalid) {
+#if defined(__BIONIC__)
+ pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
+ timespec ts;
+ EXPECT_EQ(EINVAL, pthread_rwlock_clockrdlock(&lock, CLOCK_PROCESS_CPUTIME_ID, &ts));
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockrdlock not available";
+#endif // __BIONIC__
+}
+
static void pthread_rwlock_timedwrlock_timeout_helper(
clockid_t clock, int (*lock_function)(pthread_rwlock_t* __rwlock, const timespec* __timeout)) {
RwlockWakeupHelperArg wakeup_arg;
@@ -1134,6 +1204,38 @@ TEST(pthread, pthread_rwlock_timedwrlock_monotonic_np_timeout) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_rwlock_clockwrlock_monotonic_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedwrlock_timeout_helper(
+ CLOCK_MONOTONIC, [](pthread_rwlock_t* __rwlock, const timespec* __timeout) {
+ return pthread_rwlock_clockwrlock(__rwlock, CLOCK_MONOTONIC, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockwrlock not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_rwlock_clockwrlock_realtime_timeout) {
+#if defined(__BIONIC__)
+ pthread_rwlock_timedwrlock_timeout_helper(
+ CLOCK_REALTIME, [](pthread_rwlock_t* __rwlock, const timespec* __timeout) {
+ return pthread_rwlock_clockwrlock(__rwlock, CLOCK_REALTIME, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockwrlock not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_rwlock_clockwrlock_invalid) {
+#if defined(__BIONIC__)
+ pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
+ timespec ts;
+ EXPECT_EQ(EINVAL, pthread_rwlock_clockwrlock(&lock, CLOCK_PROCESS_CPUTIME_ID, &ts));
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_rwlock_clockrwlock not available";
+#endif // __BIONIC__
+}
+
class RwlockKindTestHelper {
private:
struct ThreadArg {
@@ -1392,16 +1494,43 @@ class pthread_CondWakeupTest : public ::testing::Test {
ASSERT_EQ(0, pthread_condattr_destroy(&attr));
}
- void StartWaitingThread(std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function) {
+ void StartWaitingThread(
+ std::function<int(pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function) {
progress = INITIALIZED;
this->wait_function = wait_function;
- ASSERT_EQ(0, pthread_create(&thread, nullptr, reinterpret_cast<void* (*)(void*)>(WaitThreadFn), this));
+ ASSERT_EQ(0, pthread_create(&thread, nullptr, reinterpret_cast<void* (*)(void*)>(WaitThreadFn),
+ this));
while (progress != WAITING) {
usleep(5000);
}
usleep(5000);
}
+ void RunTimedTest(
+ clockid_t clock,
+ std::function<int(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* timeout)>
+ wait_function) {
+ timespec ts;
+ ASSERT_EQ(0, clock_gettime(clock, &ts));
+ ts.tv_sec += 1;
+
+ StartWaitingThread([&wait_function, &ts](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+ return wait_function(cond, mutex, &ts);
+ });
+
+ progress = SIGNALED;
+ ASSERT_EQ(0, pthread_cond_signal(&cond));
+ }
+
+ void RunTimedTest(clockid_t clock, std::function<int(pthread_cond_t* cond, pthread_mutex_t* mutex,
+ clockid_t clock, const timespec* timeout)>
+ wait_function) {
+ RunTimedTest(clock, [clock, &wait_function](pthread_cond_t* cond, pthread_mutex_t* mutex,
+ const timespec* timeout) {
+ return wait_function(cond, mutex, clock, timeout);
+ });
+ }
+
void TearDown() override {
ASSERT_EQ(0, pthread_join(thread, nullptr));
ASSERT_EQ(FINISHED, progress);
@@ -1442,52 +1571,80 @@ TEST_F(pthread_CondWakeupTest, broadcast_wait) {
TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_REALTIME) {
InitCond(CLOCK_REALTIME);
- timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts));
- ts.tv_sec += 1;
- StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
- return pthread_cond_timedwait(cond, mutex, &ts);
- });
- progress = SIGNALED;
- ASSERT_EQ(0, pthread_cond_signal(&cond));
+ RunTimedTest(CLOCK_REALTIME, pthread_cond_timedwait);
}
TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC) {
InitCond(CLOCK_MONOTONIC);
- timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
- ts.tv_sec += 1;
- StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
- return pthread_cond_timedwait(cond, mutex, &ts);
- });
- progress = SIGNALED;
- ASSERT_EQ(0, pthread_cond_signal(&cond));
+ RunTimedTest(CLOCK_MONOTONIC, pthread_cond_timedwait);
}
TEST_F(pthread_CondWakeupTest, signal_timedwait_CLOCK_MONOTONIC_np) {
#if defined(__BIONIC__)
InitCond(CLOCK_REALTIME);
- timespec ts;
- ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts));
- ts.tv_sec += 1;
- StartWaitingThread([&](pthread_cond_t* cond, pthread_mutex_t* mutex) {
- return pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
- });
- progress = SIGNALED;
- ASSERT_EQ(0, pthread_cond_signal(&cond));
+ RunTimedTest(CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
#else // __BIONIC__
GTEST_SKIP() << "pthread_cond_timedwait_monotonic_np not available";
#endif // __BIONIC__
}
-static void pthread_cond_timedwait_timeout_helper(clockid_t clock,
+TEST_F(pthread_CondWakeupTest, signal_clockwait_monotonic_monotonic) {
+#if defined(__BIONIC__)
+ InitCond(CLOCK_MONOTONIC);
+ RunTimedTest(CLOCK_MONOTONIC, pthread_cond_clockwait);
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
+TEST_F(pthread_CondWakeupTest, signal_clockwait_monotonic_realtime) {
+#if defined(__BIONIC__)
+ InitCond(CLOCK_MONOTONIC);
+ RunTimedTest(CLOCK_REALTIME, pthread_cond_clockwait);
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
+TEST_F(pthread_CondWakeupTest, signal_clockwait_realtime_monotonic) {
+#if defined(__BIONIC__)
+ InitCond(CLOCK_REALTIME);
+ RunTimedTest(CLOCK_MONOTONIC, pthread_cond_clockwait);
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
+TEST_F(pthread_CondWakeupTest, signal_clockwait_realtime_realtime) {
+#if defined(__BIONIC__)
+ InitCond(CLOCK_REALTIME);
+ RunTimedTest(CLOCK_REALTIME, pthread_cond_clockwait);
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
+static void pthread_cond_timedwait_timeout_helper(bool init_monotonic, clockid_t clock,
int (*wait_function)(pthread_cond_t* __cond,
pthread_mutex_t* __mutex,
const timespec* __timeout)) {
pthread_mutex_t mutex;
ASSERT_EQ(0, pthread_mutex_init(&mutex, nullptr));
pthread_cond_t cond;
- ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
+
+ if (init_monotonic) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+
+ ASSERT_EQ(0, pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
+ clockid_t clock;
+ ASSERT_EQ(0, pthread_condattr_getclock(&attr, &clock));
+ ASSERT_EQ(CLOCK_MONOTONIC, clock);
+
+ ASSERT_EQ(0, pthread_cond_init(&cond, &attr));
+ } else {
+ ASSERT_EQ(0, pthread_cond_init(&cond, nullptr));
+ }
ASSERT_EQ(0, pthread_mutex_lock(&mutex));
timespec ts;
@@ -1504,17 +1661,57 @@ static void pthread_cond_timedwait_timeout_helper(clockid_t clock,
}
TEST(pthread, pthread_cond_timedwait_timeout) {
- pthread_cond_timedwait_timeout_helper(CLOCK_REALTIME, pthread_cond_timedwait);
+ pthread_cond_timedwait_timeout_helper(false, CLOCK_REALTIME, pthread_cond_timedwait);
}
TEST(pthread, pthread_cond_timedwait_monotonic_np_timeout) {
#if defined(__BIONIC__)
- pthread_cond_timedwait_timeout_helper(CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
+ pthread_cond_timedwait_timeout_helper(false, CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
+ pthread_cond_timedwait_timeout_helper(true, CLOCK_MONOTONIC, pthread_cond_timedwait_monotonic_np);
#else // __BIONIC__
GTEST_SKIP() << "pthread_cond_timedwait_monotonic_np not available";
#endif // __BIONIC__
}
+TEST(pthread, pthread_cond_clockwait_timeout) {
+#if defined(__BIONIC__)
+ pthread_cond_timedwait_timeout_helper(
+ false, CLOCK_MONOTONIC,
+ [](pthread_cond_t* __cond, pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_cond_clockwait(__cond, __mutex, CLOCK_MONOTONIC, __timeout);
+ });
+ pthread_cond_timedwait_timeout_helper(
+ true, CLOCK_MONOTONIC,
+ [](pthread_cond_t* __cond, pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_cond_clockwait(__cond, __mutex, CLOCK_MONOTONIC, __timeout);
+ });
+ pthread_cond_timedwait_timeout_helper(
+ false, CLOCK_REALTIME,
+ [](pthread_cond_t* __cond, pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_cond_clockwait(__cond, __mutex, CLOCK_REALTIME, __timeout);
+ });
+ pthread_cond_timedwait_timeout_helper(
+ true, CLOCK_REALTIME,
+ [](pthread_cond_t* __cond, pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_cond_clockwait(__cond, __mutex, CLOCK_REALTIME, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_cond_clockwait_invalid) {
+#if defined(__BIONIC__)
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ timespec ts;
+ EXPECT_EQ(EINVAL, pthread_cond_clockwait(&cond, &mutex, CLOCK_PROCESS_CPUTIME_ID, &ts));
+
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_cond_clockwait not available";
+#endif // __BIONIC__
+}
+
TEST(pthread, pthread_attr_getstack__main_thread) {
// This test is only meaningful for the main thread, so make sure we're running on it!
ASSERT_EQ(getpid(), syscall(__NR_gettid));
@@ -2180,6 +2377,21 @@ TEST(pthread, pthread_mutex_timedlock_monotonic_np) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_mutex_clocklock) {
+#if defined(__BIONIC__)
+ pthread_mutex_timedlock_helper(
+ CLOCK_MONOTONIC, [](pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_mutex_clocklock(__mutex, CLOCK_MONOTONIC, __timeout);
+ });
+ pthread_mutex_timedlock_helper(
+ CLOCK_REALTIME, [](pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_mutex_clocklock(__mutex, CLOCK_REALTIME, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_mutex_clocklock not available";
+#endif // __BIONIC__
+}
+
static void pthread_mutex_timedlock_pi_helper(clockid_t clock,
int (*lock_function)(pthread_mutex_t* __mutex,
const timespec* __timeout)) {
@@ -2231,6 +2443,31 @@ TEST(pthread, pthread_mutex_timedlock_monotonic_np_pi) {
#endif // __BIONIC__
}
+TEST(pthread, pthread_mutex_clocklock_pi) {
+#if defined(__BIONIC__)
+ pthread_mutex_timedlock_pi_helper(
+ CLOCK_MONOTONIC, [](pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_mutex_clocklock(__mutex, CLOCK_MONOTONIC, __timeout);
+ });
+ pthread_mutex_timedlock_pi_helper(
+ CLOCK_REALTIME, [](pthread_mutex_t* __mutex, const timespec* __timeout) {
+ return pthread_mutex_clocklock(__mutex, CLOCK_REALTIME, __timeout);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_mutex_clocklock not available";
+#endif // __BIONIC__
+}
+
+TEST(pthread, pthread_mutex_clocklock_invalid) {
+#if defined(__BIONIC__)
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ timespec ts;
+ EXPECT_EQ(EINVAL, pthread_mutex_clocklock(&mutex, CLOCK_PROCESS_CPUTIME_ID, &ts));
+#else // __BIONIC__
+ GTEST_SKIP() << "pthread_mutex_clocklock not available";
+#endif // __BIONIC__
+}
+
TEST(pthread, pthread_mutex_using_destroyed_mutex) {
#if defined(__BIONIC__)
pthread_mutex_t m;
@@ -2247,6 +2484,13 @@ TEST(pthread, pthread_mutex_using_destroyed_mutex) {
"pthread_mutex_timedlock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_timedlock_monotonic_np(&m, &ts), ::testing::KilledBySignal(SIGABRT),
"pthread_mutex_timedlock_monotonic_np called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_MONOTONIC, &ts), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_clocklock called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_REALTIME, &ts), ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_clocklock called on a destroyed mutex");
+ ASSERT_EXIT(pthread_mutex_clocklock(&m, CLOCK_PROCESS_CPUTIME_ID, &ts),
+ ::testing::KilledBySignal(SIGABRT),
+ "pthread_mutex_clocklock called on a destroyed mutex");
ASSERT_EXIT(pthread_mutex_destroy(&m), ::testing::KilledBySignal(SIGABRT),
"pthread_mutex_destroy called on a destroyed mutex");
#else
diff --git a/tests/semaphore_test.cpp b/tests/semaphore_test.cpp
index 7addf6dda..5a23b96bf 100644
--- a/tests/semaphore_test.cpp
+++ b/tests/semaphore_test.cpp
@@ -145,6 +145,19 @@ TEST(semaphore, sem_timedwait_monotonic_np) {
#endif // __BIONIC__
}
+TEST(semaphore, sem_clockwait) {
+#if defined(__BIONIC__)
+ sem_timedwait_helper(CLOCK_MONOTONIC, [](sem_t* __sem, const timespec* __ts) {
+ return sem_clockwait(__sem, CLOCK_MONOTONIC, __ts);
+ });
+ sem_timedwait_helper(CLOCK_REALTIME, [](sem_t* __sem, const timespec* __ts) {
+ return sem_clockwait(__sem, CLOCK_REALTIME, __ts);
+ });
+#else // __BIONIC__
+ GTEST_SKIP() << "sem_clockwait is only supported on bionic";
+#endif // __BIONIC__
+}
+
TEST(semaphore_DeathTest, sem_timedwait_null_timeout) {
sem_t s;
ASSERT_EQ(0, sem_init(&s, 0, 0));
diff --git a/tests/stdatomic_test.cpp b/tests/stdatomic_test.cpp
index d122d2f39..a9665d18e 100644
--- a/tests/stdatomic_test.cpp
+++ b/tests/stdatomic_test.cpp
@@ -15,9 +15,14 @@
*/
#include <gtest/gtest.h>
-// Fool stdatomic.h into not using <atomic>.
-#undef _USING_LIBCXX
+
+#if defined(__ANDROID__)
+#include <bits/stdatomic.h>
+#else
+#undef _USING_LIBCXX //TODO(b/137876753): Remove this
#include <stdatomic.h>
+#endif
+
#include <pthread.h>
#include <stdint.h>
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 01b4dbab7..a0cda1be0 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -19,7 +19,6 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <linux/fs.h>
#include <math.h>
#include <stdio.h>
#include <sys/types.h>
@@ -34,10 +33,18 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/unique_fd.h>
#include "BionicDeathTest.h"
#include "utils.h"
+// This #include is actually a test too. We have to duplicate the
+// definitions of the RENAME_ constants because <linux/fs.h> also contains
+// pollution such as BLOCK_SIZE which conflicts with lots of user code.
+// Important to check that we have matching definitions.
+// There's no _MAX to test that we have all the constants, sadly.
+#include <linux/fs.h>
+
#if defined(NOFORTIFY)
#define STDIO_TEST stdio_nofortify
#define STDIO_DEATHTEST stdio_nofortify_DeathTest
@@ -2610,3 +2617,77 @@ TEST(STDIO_TEST, SEEK_macros) {
// So we'll notice if Linux grows another constant in <linux/fs.h>...
ASSERT_EQ(SEEK_MAX, SEEK_HOLE);
}
+
+TEST(STDIO_TEST, rename) {
+ TemporaryDir td;
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, rename(old_path.c_str(), new_path.c_str()));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+}
+
+TEST(STDIO_TEST, renameat) {
+ TemporaryDir td;
+ android::base::unique_fd dirfd{open(td.path, O_PATH)};
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, renameat(dirfd, "old", dirfd, "new"));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+}
+
+TEST(STDIO_TEST, renameat2) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc doesn't have renameat2 until 2.28";
+#else
+ TemporaryDir td;
+ android::base::unique_fd dirfd{open(td.path, O_PATH)};
+ std::string old_path = td.path + "/old"s;
+ std::string new_path = td.path + "/new"s;
+
+ // Create the file, check it exists.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+ struct stat sb;
+ ASSERT_EQ(0, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(-1, stat(new_path.c_str(), &sb));
+
+ // Rename and check it moved.
+ ASSERT_EQ(0, renameat2(dirfd, "old", dirfd, "new", 0));
+ ASSERT_EQ(-1, stat(old_path.c_str(), &sb));
+ ASSERT_EQ(0, stat(new_path.c_str(), &sb));
+
+ // After this, both "old" and "new" exist.
+ ASSERT_EQ(0, close(creat(old_path.c_str(), 0666)));
+
+ // Rename and check it moved.
+ ASSERT_EQ(-1, renameat2(dirfd, "old", dirfd, "new", RENAME_NOREPLACE));
+ ASSERT_EQ(EEXIST, errno);
+#endif
+}
+
+TEST(STDIO_TEST, renameat2_flags) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "glibc doesn't have renameat2 until 2.28";
+#else
+ ASSERT_NE(0, RENAME_EXCHANGE);
+ ASSERT_NE(0, RENAME_NOREPLACE);
+ ASSERT_NE(0, RENAME_WHITEOUT);
+#endif
+}
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 0b981981c..e403ea5b5 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -230,7 +230,10 @@ TEST(sys_mman, mmap_PTRDIFF_MAX) {
TEST(sys_mman, mremap_PTRDIFF_MAX) {
void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, map);
+
ASSERT_EQ(MAP_FAILED, mremap(map, PAGE_SIZE, kHuge, MREMAP_MAYMOVE));
+
+ ASSERT_EQ(0, munmap(map, PAGE_SIZE));
}
TEST(sys_mman, mmap_bug_27265969) {
@@ -239,3 +242,61 @@ TEST(sys_mman, mmap_bug_27265969) {
// Some kernels had bugs that would cause segfaults here...
__builtin___clear_cache(base, base + (PAGE_SIZE * 2));
}
+
+TEST(sys_mman, mlock) {
+ void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map);
+
+ // Not really anything we can assert about this.
+ mlock(map, PAGE_SIZE);
+
+ ASSERT_EQ(0, munmap(map, PAGE_SIZE));
+}
+
+TEST(sys_mman, mlock2) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "needs glibc 2.27";
+#else
+ void* map = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map);
+
+ // Not really anything we can assert about this.
+ mlock2(map, PAGE_SIZE, MLOCK_ONFAULT);
+
+ ASSERT_EQ(0, munmap(map, PAGE_SIZE));
+#endif
+}
+
+TEST(sys_mman, memfd_create) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "needs glibc 2.27";
+#else
+ // Is the MFD_CLOEXEC flag obeyed?
+ errno = 0;
+ int fd = memfd_create("doesn't matter", 0);
+ if (fd == -1) {
+ ASSERT_EQ(ENOSYS, errno);
+ GTEST_SKIP() << "no memfd_create available";
+ }
+ int f = fcntl(fd, F_GETFD);
+ ASSERT_NE(-1, f);
+ ASSERT_FALSE(f & FD_CLOEXEC);
+ close(fd);
+
+ errno = 0;
+ fd = memfd_create("doesn't matter", MFD_CLOEXEC);
+ f = fcntl(fd, F_GETFD);
+ ASSERT_NE(-1, f);
+ ASSERT_TRUE(f & FD_CLOEXEC);
+
+ // Can we read and write?
+ std::string expected("hello, world!");
+ ASSERT_TRUE(android::base::WriteStringToFd(expected, fd));
+ ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
+ std::string actual;
+ ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
+ ASSERT_EQ(expected, actual);
+
+ close(fd);
+#endif
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index c890358fa..4e1724211 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -748,11 +748,11 @@ TEST(time, clock_getres_unknown) {
}
TEST(time, clock) {
- // clock(3) is hard to test, but a 1s sleep should cost less than 1ms.
+ // clock(3) is hard to test, but a 1s sleep should cost less than 5ms.
clock_t t0 = clock();
sleep(1);
clock_t t1 = clock();
- ASSERT_LT(t1 - t0, CLOCKS_PER_SEC / 1000);
+ ASSERT_LT(t1 - t0, 5 * (CLOCKS_PER_SEC / 1000));
}
static pid_t GetInvalidPid() {
diff --git a/tests/touch-obj-on-success b/tests/touch-obj-on-success
index df08a4968..d8a71ba24 100755
--- a/tests/touch-obj-on-success
+++ b/tests/touch-obj-on-success
@@ -4,5 +4,8 @@
# from that command line and touches it.
"$@"
-obj="$(echo "$@" | grep -oP '\S+\.o\b')"
-touch "${obj}"
+for arg in "$@"; do
+ if [[ "$arg" == *.o ]]; then
+ touch "$arg"
+ fi
+done