diff options
Diffstat (limited to 'tests')
29 files changed, 959 insertions, 166 deletions
diff --git a/tests/Android.bp b/tests/Android.bp index 598865bd7..586ef344e 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -72,6 +72,217 @@ cc_defaults { } // ----------------------------------------------------------------------------- +// Prebuilt shared libraries for use in tests. +// ----------------------------------------------------------------------------- + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-rw_load_segment", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-rw_load_segment.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-rw_load_segment.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-rw_load_segment.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-rw_load_segment.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-unaligned_shdr_offset", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-unaligned_shdr_offset.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-unaligned_shdr_offset.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-unaligned_shdr_offset.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-unaligned_shdr_offset.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-zero_shentsize", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-zero_shentsize.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-zero_shentsize.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-zero_shentsize.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-zero_shentsize.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-zero_shstrndx", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-zero_shstrndx.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-zero_shstrndx.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-zero_shstrndx.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-zero_shstrndx.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-empty_shdr_table", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-empty_shdr_table.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-empty_shdr_table.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-empty_shdr_table.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-empty_shdr_table.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-zero_shdr_table_offset", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-zero_shdr_table_offset.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-zero_shdr_table_offset.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-zero_shdr_table_offset.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-zero_shdr_table_offset.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-zero_shdr_table_content", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-zero_shdr_table_content.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-zero_shdr_table_content.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-zero_shdr_table_content.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-zero_shdr_table_content.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-textrels", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-textrels.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-textrels.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-textrels.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-textrels.so"], + }, + }, +} + +cc_prebuilt_test_library_shared { + name: "libtest_invalid-textrels2", + strip: { + none: true, + }, + check_elf_files: false, + relative_install_path: "bionic-loader-test-libs/prebuilt-elf-files", + arch: { + arm: { + srcs: ["prebuilt-elf-files/arm/libtest_invalid-textrels2.so"], + }, + arm64: { + srcs: ["prebuilt-elf-files/arm64/libtest_invalid-textrels2.so"], + }, + x86: { + srcs: ["prebuilt-elf-files/x86/libtest_invalid-textrels2.so"], + }, + x86_64: { + srcs: ["prebuilt-elf-files/x86_64/libtest_invalid-textrels2.so"], + }, + }, +} + +// ----------------------------------------------------------------------------- // All standard tests. // ----------------------------------------------------------------------------- @@ -211,6 +422,7 @@ cc_test_library { "sys_uio_test.cpp", "sys_un_test.cpp", "sys_vfs_test.cpp", + "sys_wait_test.cpp", "sys_xattr_test.cpp", "system_properties_test.cpp", "system_properties_test2.cpp", @@ -736,15 +948,15 @@ cc_defaults { "libtest_with_dependency_loop", "libtest_with_dependency", "libtest_indirect_thread_local_dtor", - "libtest_invalid-empty_shdr_table.so", - "libtest_invalid-rw_load_segment.so", - "libtest_invalid-unaligned_shdr_offset.so", - "libtest_invalid-zero_shdr_table_content.so", - "libtest_invalid-zero_shdr_table_offset.so", - "libtest_invalid-zero_shentsize.so", - "libtest_invalid-zero_shstrndx.so", - "libtest_invalid-textrels.so", - "libtest_invalid-textrels2.so", + "libtest_invalid-empty_shdr_table", + "libtest_invalid-rw_load_segment", + "libtest_invalid-unaligned_shdr_offset", + "libtest_invalid-zero_shdr_table_content", + "libtest_invalid-zero_shdr_table_offset", + "libtest_invalid-zero_shentsize", + "libtest_invalid-zero_shstrndx", + "libtest_invalid-textrels", + "libtest_invalid-textrels2", "libtest_thread_local_dtor", "libtest_thread_local_dtor2", "preinit_getauxval_test_helper", diff --git a/tests/Android.build.prebuilt.mk b/tests/Android.build.prebuilt.mk deleted file mode 100644 index de8f5e6c5..000000000 --- a/tests/Android.build.prebuilt.mk +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (C) 2016 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. -# - -include $(CLEAR_VARS) -LOCAL_MULTILIB := both -LOCAL_MODULE := $(bionic_tests_module) -LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/prebuilt-elf-files -LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-loader-test-libs/prebuilt-elf-files -LOCAL_MODULE_CLASS := EXECUTABLES - -LOCAL_SRC_FILES_arm := prebuilt-elf-files/arm/$(bionic_tests_module) -LOCAL_SRC_FILES_arm64 := prebuilt-elf-files/arm64/$(bionic_tests_module) -LOCAL_SRC_FILES_x86 := prebuilt-elf-files/x86/$(bionic_tests_module) -LOCAL_SRC_FILES_x86_64 := prebuilt-elf-files/x86_64/$(bionic_tests_module) -include $(BUILD_PREBUILT) -bionic-loader-test-libs-target: $(LOCAL_MODULE) -.PHONY: bionic-loader-test-libs-target diff --git a/tests/Android.mk b/tests/Android.mk index b5571e3f6..5ad4045bd 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -16,43 +16,6 @@ LOCAL_PATH := $(call my-dir) -# TODO(dimitry): replace with define once https://android-review.googlesource.com/247466 is reverted -# https://github.com/google/kati/issues/83 is currently blocking it. - -# Move prebuilt test elf-files to $(TARGET_OUT_NATIVE_TESTS) -bionic_tests_module := libtest_invalid-rw_load_segment.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-unaligned_shdr_offset.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-zero_shentsize.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-zero_shstrndx.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-empty_shdr_table.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-zero_shdr_table_offset.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-zero_shdr_table_content.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-textrels.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -bionic_tests_module := libtest_invalid-textrels2.so -include $(LOCAL_PATH)/Android.build.prebuilt.mk - -ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64)) -build_host := true -else -build_host := false -endif - ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64)) # ----------------------------------------------------------------------------- diff --git a/tests/dirent_test.cpp b/tests/dirent_test.cpp index 378aea41e..56929d138 100644 --- a/tests/dirent_test.cpp +++ b/tests/dirent_test.cpp @@ -113,6 +113,18 @@ TEST(dirent, scandirat_scandirat64) { ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64); } +static int is_version_filter(const dirent* de) { + return !strcmp(de->d_name, "version"); +} + +TEST(dirent, scandir_filter) { + dirent** entries; + errno = 0; + ASSERT_EQ(1, scandir("/proc", &entries, is_version_filter, nullptr)); + ASSERT_STREQ("version", entries[0]->d_name); + free(entries); +} + TEST(dirent, scandir_ENOENT) { dirent** entries; errno = 0; diff --git a/tests/dlext_private.h b/tests/dlext_private.h index b338ae01f..262af4c25 100644 --- a/tests/dlext_private.h +++ b/tests/dlext_private.h @@ -56,10 +56,10 @@ enum { */ ANDROID_NAMESPACE_TYPE_SHARED = 2, - /* This flag instructs linker to enable grey-list workaround for the namespace. + /* This flag instructs linker to enable exempt-list workaround for the namespace. * See http://b/26394120 for details. */ - ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000, + ANDROID_NAMESPACE_TYPE_EXEMPT_LIST_ENABLED = 0x08000000, ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED, diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 4c4a1c3e8..01bf8ab51 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -1228,7 +1228,7 @@ TEST(dlext, ns_unload_between_namespaces_missing_symbol_indirect) { dlerror()); } -TEST(dlext, ns_greylist_enabled) { +TEST(dlext, ns_exempt_list_enabled) { ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); const std::string ns_search_path = GetTestlibRoot() + "/private_namespace_libs"; @@ -1237,7 +1237,7 @@ TEST(dlext, ns_greylist_enabled) { android_create_namespace("namespace", nullptr, ns_search_path.c_str(), - ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED, + ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_EXEMPT_LIST_ENABLED, nullptr, nullptr); @@ -1247,26 +1247,26 @@ TEST(dlext, ns_greylist_enabled) { extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; extinfo.library_namespace = ns; - // An app targeting M can open libnativehelper.so because it's on the greylist. + // An app targeting M can open libnativehelper.so because it's on the exempt-list. android_set_application_target_sdk_version(23); void* handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo); ASSERT_TRUE(handle != nullptr) << dlerror(); - // Check that loader did not load another copy of libdl.so while loading greylisted library. + // Check that loader did not load another copy of libdl.so while loading exempted library. void* dlsym_ptr = dlsym(handle, "dlsym"); ASSERT_TRUE(dlsym_ptr != nullptr) << dlerror(); ASSERT_EQ(&dlsym, dlsym_ptr); dlclose(handle); - // An app targeting N no longer has the greylist. + // An app targeting N no longer has the exempt-list. android_set_application_target_sdk_version(24); handle = android_dlopen_ext("libnativehelper.so", RTLD_NOW, &extinfo); ASSERT_TRUE(handle == nullptr); ASSERT_STREQ("dlopen failed: library \"libnativehelper.so\" not found", dlerror()); } -TEST(dlext, ns_greylist_disabled_by_default) { +TEST(dlext, ns_exempt_list_disabled_by_default) { ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)); const std::string ns_search_path = GetTestlibRoot() + "/private_namespace_libs"; diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index d7b9bae64..35e12eb4a 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -1623,9 +1623,7 @@ TEST(dlext, compat_elf_hash_and_relocation_tables) { #endif // defined(__arm__) TEST(dlfcn, dlopen_invalid_rw_load_segment) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-rw_load_segment.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-rw_load_segment.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); std::string expected_dlerror = std::string("dlopen failed: \"") + libpath + "\": W+E load segments are not allowed"; @@ -1633,9 +1631,7 @@ TEST(dlfcn, dlopen_invalid_rw_load_segment) { } TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-unaligned_shdr_offset.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-unaligned_shdr_offset.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1644,9 +1640,7 @@ TEST(dlfcn, dlopen_invalid_unaligned_shdr_offset) { } TEST(dlfcn, dlopen_invalid_zero_shentsize) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-zero_shentsize.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shentsize.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1655,9 +1649,7 @@ TEST(dlfcn, dlopen_invalid_zero_shentsize) { } TEST(dlfcn, dlopen_invalid_zero_shstrndx) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-zero_shstrndx.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shstrndx.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1666,9 +1658,7 @@ TEST(dlfcn, dlopen_invalid_zero_shstrndx) { } TEST(dlfcn, dlopen_invalid_empty_shdr_table) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-empty_shdr_table.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-empty_shdr_table.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1677,9 +1667,7 @@ TEST(dlfcn, dlopen_invalid_empty_shdr_table) { } TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-zero_shdr_table_offset.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shdr_table_offset.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1688,9 +1676,7 @@ TEST(dlfcn, dlopen_invalid_zero_shdr_table_offset) { } TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-zero_shdr_table_content.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-zero_shdr_table_content.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1699,9 +1685,7 @@ TEST(dlfcn, dlopen_invalid_zero_shdr_table_content) { } TEST(dlfcn, dlopen_invalid_textrels) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-textrels.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-textrels.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); @@ -1710,9 +1694,7 @@ TEST(dlfcn, dlopen_invalid_textrels) { } TEST(dlfcn, dlopen_invalid_textrels2) { - const std::string libpath = GetTestlibRoot() + - "/" + kPrebuiltElfDir + - "/libtest_invalid-textrels2.so"; + const std::string libpath = GetPrebuiltElfDir() + "/libtest_invalid-textrels2.so"; void* handle = dlopen(libpath.c_str(), RTLD_NOW); ASSERT_TRUE(handle == nullptr); diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp index 6907abe9b..3ca0223b2 100644 --- a/tests/fortify_test.cpp +++ b/tests/fortify_test.cpp @@ -204,8 +204,9 @@ TEST_F(DEATHTEST, memchr_fortified2) { foo myfoo; volatile int asize = sizeof(myfoo.a) + 1; memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); - ASSERT_FORTIFY(printf("%s", memchr(myfoo.a, 'a', asize))); - ASSERT_FORTIFY(printf("%s", memchr(static_cast<const void*>(myfoo.a), 'a', asize))); + ASSERT_FORTIFY(printf("%s", static_cast<const char*>(memchr(myfoo.a, 'a', asize)))); + ASSERT_FORTIFY(printf( + "%s", static_cast<const char*>(memchr(static_cast<const void*>(myfoo.a), 'a', asize)))); #else // __BIONIC__ GTEST_SKIP() << "glibc is broken"; #endif // __BIONIC__ @@ -216,8 +217,9 @@ TEST_F(DEATHTEST, memrchr_fortified2) { foo myfoo; volatile int asize = sizeof(myfoo.a) + 1; memcpy(myfoo.a, "0123456789", sizeof(myfoo.a)); - ASSERT_FORTIFY(printf("%s", memrchr(myfoo.a, 'a', asize))); - ASSERT_FORTIFY(printf("%s", memrchr(static_cast<const void*>(myfoo.a), 'a', asize))); + ASSERT_FORTIFY(printf("%s", static_cast<const char*>(memrchr(myfoo.a, 'a', asize)))); + ASSERT_FORTIFY(printf( + "%s", static_cast<const char*>(memrchr(static_cast<const void*>(myfoo.a), 'a', asize)))); #else // __BIONIC__ GTEST_SKIP() << "glibc is broken"; #endif // __BIONIC__ diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp index 99117e45b..bf65720f9 100644 --- a/tests/grp_pwd_test.cpp +++ b/tests/grp_pwd_test.cpp @@ -820,6 +820,24 @@ TEST(grp, getgrent_iterate) { #endif } +TEST(grp, getgrouplist) { +#if defined(__BIONIC__) + // Query the number of groups. + int ngroups = 0; + ASSERT_EQ(-1, getgrouplist("root", 123, nullptr, &ngroups)); + ASSERT_EQ(1, ngroups); + + // Query the specific groups (just the one you pass in on Android). + ngroups = 8; + gid_t groups[ngroups]; + ASSERT_EQ(1, getgrouplist("root", 123, groups, &ngroups)); + ASSERT_EQ(1, ngroups); + ASSERT_EQ(123u, groups[0]); +#else + GTEST_SKIP() << "bionic-only test (groups too unpredictable)"; +#endif +} + #if defined(__BIONIC__) static void TestAidNamePrefix(const std::string& file_path) { std::string file_contents; diff --git a/tests/gtest_globals.cpp b/tests/gtest_globals.cpp index 4160237ab..5b5ede8d4 100644 --- a/tests/gtest_globals.cpp +++ b/tests/gtest_globals.cpp @@ -24,8 +24,9 @@ #include <string> std::string GetTestlibRoot() { - // Calculate ANDROID_DATA assuming the binary is in "$ANDROID_DATA/somedir/binary-dir/binary" - std::string path = android::base::Dirname(android::base::GetExecutablePath()) + "/.."; + // Typically the executable is /data/nativetest[64]/bionic-unit-tests/bionic-unit-tests, and the + // test libraries are in /data/nativetest[64]/bionic-loader-test-libs. + std::string path = android::base::GetExecutableDirectory() + "/.."; std::string out_path; if (!android::base::Realpath(path.c_str(), &out_path)) { diff --git a/tests/gtest_globals.h b/tests/gtest_globals.h index b3c7b102d..1bebb7006 100644 --- a/tests/gtest_globals.h +++ b/tests/gtest_globals.h @@ -19,8 +19,10 @@ #include <string> -constexpr const char* kPrebuiltElfDir = "prebuilt-elf-files"; - std::string GetTestlibRoot(); +inline std::string GetPrebuiltElfDir() { + return GetTestlibRoot() + "/prebuilt-elf-files"; +} + #endif // _BIONIC_TESTS_GTEST_GLOBALS_H diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp index c427282c1..ef4fddd45 100644 --- a/tests/libs/Android.bp +++ b/tests/libs/Android.bp @@ -79,6 +79,22 @@ cc_test_library { shared_libs: ["libtest_elftls_shared_var"], } +cc_test { + name: "thread_exit_cb_helper.cpp", + defaults: ["bionic_testlib_defaults"], + srcs: ["thread_exit_cb_helper.cpp"], + cflags: ["-fno-emulated-tls"], +} + +cc_test { + name: "tls_properties_helper", + defaults: ["bionic_testlib_defaults"], + srcs: ["tls_properties_helper.cpp"], + cflags: ["-fno-emulated-tls"], + shared_libs: ["libtest_elftls_shared_var"], +} + + cc_test_library { name: "libtest_elftls_dynamic_filler_1", defaults: ["bionic_testlib_defaults"], @@ -1268,6 +1284,7 @@ cc_test_library { name: "libtest_check_rtld_next_from_library", defaults: ["bionic_testlib_defaults"], srcs: ["check_rtld_next_from_library.cpp"], + native_coverage: false, } // ----------------------------------------------------------------------------- diff --git a/tests/libs/thread_exit_cb_helper.cpp b/tests/libs/thread_exit_cb_helper.cpp new file mode 100644 index 000000000..8ec1398f1 --- /dev/null +++ b/tests/libs/thread_exit_cb_helper.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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. + */ + +// Prevent tests from being compiled with glibc because thread_properties.h +// only exists in Bionic. +#if defined(__BIONIC__) + +#include <stdio.h> +#include <sys/thread_properties.h> + +// Helper binary for testing thread_exit_cb registration. + +void exit_cb_1() { + printf("exit_cb_1 called "); +} + +void exit_cb_2() { + printf("exit_cb_2 called "); +} + +void exit_cb_3() { + printf("exit_cb_3 called"); +} + +void test_register_thread_exit_cb() { + // Register the exit-cb in reverse order (3,2,1) + // so that they'd be called in 1,2,3 order. + __libc_register_thread_exit_callback(&exit_cb_3); + __libc_register_thread_exit_callback(&exit_cb_2); + __libc_register_thread_exit_callback(&exit_cb_1); +} + +int main() { + test_register_thread_exit_cb(); + return 0; +} +#else +int main() { + return 0; +} +#endif // __BIONIC__ diff --git a/tests/libs/tls_properties_helper.cpp b/tests/libs/tls_properties_helper.cpp new file mode 100644 index 000000000..3f8d11885 --- /dev/null +++ b/tests/libs/tls_properties_helper.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 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. + */ + +// Prevent tests from being compiled with glibc because thread_properties.h +// only exists in Bionic. +#if defined(__BIONIC__) + +#include <sys/thread_properties.h> + +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <unistd.h> // for gettid + +// Helper binary to use TLS-related functions in thread_properties + +// Tests __get_static_tls_bound. +thread_local int local_var; +void test_static_tls_bounds() { + local_var = 123; + void* start_addr = nullptr; + void* end_addr = nullptr; + + __libc_get_static_tls_bounds(reinterpret_cast<void**>(&start_addr), + reinterpret_cast<void**>(&end_addr)); + assert(start_addr != nullptr); + assert(end_addr != nullptr); + + assert(&local_var >= start_addr && &local_var < end_addr); + + printf("done_get_static_tls_bounds\n"); +} + +// Tests iterate_dynamic tls chunks. +// Export a var from the shared so. +__thread char large_tls_var[4 * 1024 * 1024]; +void test_iter_tls() { + void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW); + + int i = 0; + auto cb = [&](void* dtls_begin, void* dtls_end, size_t dso_id, void* arg) { + printf("iterate_cb i = %d\n", i++); + }; + __libc_iterate_dynamic_tls(gettid(), cb, nullptr); + printf("done_iterate_dynamic_tls\n"); +} + +int main() { + test_static_tls_bounds(); + test_iter_tls(); + return 0; +} + +#else +int main() { + return 0; +} +#endif // __BIONIC__ diff --git a/tests/netinet_ether_test.cpp b/tests/netinet_ether_test.cpp index faa3db47f..af020ec93 100644 --- a/tests/netinet_ether_test.cpp +++ b/tests/netinet_ether_test.cpp @@ -34,7 +34,7 @@ TEST(netinet_ether, ether_aton__ether_ntoa) { TEST(netinet_ether, ether_aton_r__ether_ntoa_r) { ether_addr addr; memset(&addr, 0, sizeof(addr)); - ether_addr* a = ether_aton_r("12:34:56:78:9a:bc", &addr); + ether_addr* a = ether_aton_r("12:34:56:78:9a:Bc", &addr); ASSERT_EQ(&addr, a); ASSERT_EQ(0x12, addr.ether_addr_octet[0]); ASSERT_EQ(0x34, addr.ether_addr_octet[1]); @@ -49,3 +49,11 @@ TEST(netinet_ether, ether_aton_r__ether_ntoa_r) { ASSERT_EQ(buf, p); ASSERT_STREQ("12:34:56:78:9a:bc", buf); } + +TEST(netinet_ether, ether_aton_r_failures) { + ether_addr addr; + ASSERT_TRUE(ether_aton_r("12:34:56:78:9a;bc", &addr) == nullptr); + ASSERT_TRUE(ether_aton_r("12:34:56:78:9a:bc ", &addr) == nullptr); + ASSERT_TRUE(ether_aton_r("g2:34:56:78:9a:bc ", &addr) == nullptr); + ASSERT_TRUE(ether_aton_r("1G:34:56:78:9a:bc ", &addr) == nullptr); +} diff --git a/tests/netinet_in_test.cpp b/tests/netinet_in_test.cpp index 260608210..437e18022 100644 --- a/tests/netinet_in_test.cpp +++ b/tests/netinet_in_test.cpp @@ -31,8 +31,15 @@ static constexpr uint32_t be32 = 0x78563412; static constexpr uint64_t be64 = 0xf0debc9a78563412; TEST(netinet_in, bindresvport) { - // This isn't something we can usually test, so just check the symbol's there. + // This isn't something we can usually test (because you need to be root), + // so just check the symbol's there. ASSERT_EQ(-1, bindresvport(-1, nullptr)); + + // Only AF_INET is supported. + sockaddr_in sin = {.sin_family = AF_INET6}; + errno = 0; + ASSERT_EQ(-1, bindresvport(-1, &sin)); + ASSERT_EQ(EPFNOSUPPORT, errno); } TEST(netinet_in, in6addr_any) { diff --git a/tests/pty_test.cpp b/tests/pty_test.cpp index 29f86f16a..d5d8994be 100644 --- a/tests/pty_test.cpp +++ b/tests/pty_test.cpp @@ -28,34 +28,34 @@ #include "utils.h" TEST(pty, openpty) { - int master, slave; + int pty, tty; char name[32]; struct winsize w = { 123, 456, 9999, 999 }; - ASSERT_EQ(0, openpty(&master, &slave, name, nullptr, &w)); - ASSERT_NE(-1, master); - ASSERT_NE(-1, slave); - ASSERT_NE(master, slave); + ASSERT_EQ(0, openpty(&pty, &tty, name, nullptr, &w)); + ASSERT_NE(-1, pty); + ASSERT_NE(-1, tty); + ASSERT_NE(pty, tty); char tty_name[32]; - ASSERT_EQ(0, ttyname_r(slave, tty_name, sizeof(tty_name))); + ASSERT_EQ(0, ttyname_r(tty, tty_name, sizeof(tty_name))); ASSERT_STREQ(tty_name, name); struct winsize w_actual; - ASSERT_EQ(0, ioctl(slave, TIOCGWINSZ, &w_actual)); + ASSERT_EQ(0, ioctl(tty, TIOCGWINSZ, &w_actual)); ASSERT_EQ(w_actual.ws_row, w.ws_row); ASSERT_EQ(w_actual.ws_col, w.ws_col); ASSERT_EQ(w_actual.ws_xpixel, w.ws_xpixel); ASSERT_EQ(w_actual.ws_ypixel, w.ws_ypixel); - close(master); - close(slave); + close(pty); + close(tty); } TEST(pty, forkpty) { pid_t sid = getsid(0); - int master; - pid_t pid = forkpty(&master, nullptr, nullptr, nullptr); + int pty; + pid_t pid = forkpty(&pty, nullptr, nullptr, nullptr); ASSERT_NE(-1, pid); if (pid == 0) { @@ -68,12 +68,12 @@ TEST(pty, forkpty) { AssertChildExited(pid, 0); - close(master); + close(pty); } struct PtyReader_28979140_Arg { int main_cpu_id; - int slave_fd; + int fd; uint32_t data_count; bool finished; std::atomic<bool> matched; @@ -90,7 +90,7 @@ static void PtyReader_28979140(PtyReader_28979140_Arg* arg) { while (counter <= arg->data_count) { char buf[4096]; // Use big buffer to read to hit the bug more easily. size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t)); - ASSERT_TRUE(android::base::ReadFully(arg->slave_fd, buf, to_read)); + ASSERT_TRUE(android::base::ReadFully(arg->fd, buf, to_read)); size_t num_of_value = to_read / sizeof(uint32_t); uint32_t* p = reinterpret_cast<uint32_t*>(buf); while (num_of_value-- > 0) { @@ -99,7 +99,7 @@ static void PtyReader_28979140(PtyReader_28979140_Arg* arg) { } } } - close(arg->slave_fd); + close(arg->fd); arg->finished = true; } @@ -114,16 +114,16 @@ TEST(pty, bug_28979140) { constexpr uint32_t TEST_DATA_COUNT = 2000000; // 1. Open raw pty. - int master; - int slave; - ASSERT_EQ(0, openpty(&master, &slave, nullptr, nullptr, nullptr)); + int pty; + int tty; + ASSERT_EQ(0, openpty(&pty, &tty, nullptr, nullptr, nullptr)); termios tattr; - ASSERT_EQ(0, tcgetattr(slave, &tattr)); + ASSERT_EQ(0, tcgetattr(tty, &tattr)); cfmakeraw(&tattr); - ASSERT_EQ(0, tcsetattr(slave, TCSADRAIN, &tattr)); + ASSERT_EQ(0, tcsetattr(tty, TCSADRAIN, &tattr)); - // 2. Make master thread and slave thread running on different cpus: - // master thread uses first available cpu, and slave thread uses other cpus. + // 2. Make two threads running on different cpus: + // pty thread uses first available cpu, and tty thread uses other cpus. PtyReader_28979140_Arg arg; arg.main_cpu_id = -1; for (int i = 0; i < CPU_SETSIZE; i++) { @@ -134,9 +134,9 @@ TEST(pty, bug_28979140) { } ASSERT_GE(arg.main_cpu_id, 0); - // 3. Create thread for slave reader. + // 3. Create thread for tty reader. pthread_t thread; - arg.slave_fd = slave; + arg.fd = tty; arg.data_count = TEST_DATA_COUNT; arg.matched = true; ASSERT_EQ(0, pthread_create(&thread, nullptr, @@ -147,7 +147,7 @@ TEST(pty, bug_28979140) { CPU_SET(arg.main_cpu_id, &cpus); ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus)); - // 4. Send data to slave. + // 4. Send data to tty reader. // Send a bunch of data at a time, so it is easier to catch the bug that some data isn't seen // by the reader thread on another cpu. uint32_t counter_buf[100]; @@ -156,11 +156,11 @@ TEST(pty, bug_28979140) { for (size_t i = 0; i < sizeof(counter_buf) / sizeof(counter_buf[0]); ++i) { counter_buf[i] = counter++; } - ASSERT_TRUE(android::base::WriteFully(master, &counter_buf, sizeof(counter_buf))); + ASSERT_TRUE(android::base::WriteFully(pty, &counter_buf, sizeof(counter_buf))); ASSERT_TRUE(arg.matched) << "failed at count = " << counter; } ASSERT_EQ(0, pthread_join(thread, nullptr)); ASSERT_TRUE(arg.finished); ASSERT_TRUE(arg.matched); - close(master); + close(pty); } diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp index 9309a7ff5..03e8062d8 100644 --- a/tests/sched_test.cpp +++ b/tests/sched_test.cpp @@ -301,3 +301,7 @@ TEST(sched, sched_getscheduler_sched_setscheduler) { // don't behave as POSIX specifies. http://b/26203902. ASSERT_EQ(0, sched_setscheduler(getpid(), original_policy, &p)); } + +TEST(sched, sched_getaffinity_failure) { + ASSERT_EQ(-1, sched_getaffinity(getpid(), 0, nullptr)); +} diff --git a/tests/search_test.cpp b/tests/search_test.cpp index 1509199c9..8b8359d50 100644 --- a/tests/search_test.cpp +++ b/tests/search_test.cpp @@ -114,6 +114,11 @@ TEST(search, tfind_tsearch_twalk_tdestroy) { ASSERT_EQ(3U, g_free_calls); } +TEST(search, tdestroy_null) { + // It's okay to pass a null node, and your callback will not be called. + tdestroy(nullptr, nullptr); +} + struct pod_node { explicit pod_node(int i) : i(i) {} int i; @@ -285,3 +290,26 @@ TEST(search, hcreate_r_hsearch_r_hdestroy_r) { AssertEntry(e, "a", "B"); hdestroy_r(&h2); } + +TEST(search, hsearch_resizing) { + ASSERT_NE(0, hcreate(1)); + + std::vector<char*> entries; + // Add enough entries to ensure that we've had to resize. + for (char ch = ' '; ch <= '~'; ++ch) { + char* p; + asprintf(&p, "%c", ch); + ENTRY e; + e.data = e.key = p; + ASSERT_TRUE(hsearch(e, ENTER) != nullptr); + entries.push_back(p); + } + + // Check they're all there. + for (auto& p : entries) { + ENTRY* e = hsearch(ENTRY{.key = p, .data = nullptr}, FIND); + AssertEntry(e, p, p); + } + + for (auto& p : entries) free(p); +} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index f6eca05f4..c21c3b8b6 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -371,6 +371,11 @@ TEST(STDIO_TEST, snprintf_n) { #endif } +TEST(STDIO_TEST, snprintf_measure) { + char buf[16]; + ASSERT_EQ(11, snprintf(buf, 0, "Hello %s", "world")); +} + TEST(STDIO_TEST, snprintf_smoke) { char buf[BUFSIZ]; @@ -1155,7 +1160,6 @@ TEST(STDIO_TEST, sscanf_mc) { free(p1); } - TEST(STDIO_TEST, sscanf_mlc) { // This is so useless that clang doesn't even believe it exists... #pragma clang diagnostic push @@ -1189,7 +1193,6 @@ TEST(STDIO_TEST, sscanf_mlc) { #pragma clang diagnostic pop } - TEST(STDIO_TEST, sscanf_ms) { CheckScanfM(sscanf, "hello", "%ms", 1, "hello"); CheckScanfM(sscanf, "hello", "%4ms", 1, "hell"); @@ -2533,6 +2536,16 @@ TEST(STDIO_TEST, puts) { eth.Run([&]() { exit(puts("a b c")); }, 0, "a b c\n"); } +TEST(STDIO_TEST, putchar) { + ExecTestHelper eth; + eth.Run([&]() { exit(putchar('A')); }, 65, "A"); +} + +TEST(STDIO_TEST, putchar_unlocked) { + ExecTestHelper eth; + eth.Run([&]() { exit(putchar('B')); }, 66, "B"); +} + TEST(STDIO_TEST, unlocked) { TemporaryFile tf; @@ -2733,3 +2746,73 @@ TEST(STDIO_TEST, renameat2_flags) { ASSERT_NE(0, RENAME_WHITEOUT); #endif } + +TEST(STDIO_TEST, fdopen_failures) { + FILE* fp; + int fd = open("/proc/version", O_RDONLY); + ASSERT_TRUE(fd != -1); + + // Nonsense mode. + errno = 0; + fp = fdopen(fd, "nonsense"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); + + // Mode that isn't a subset of the fd's actual mode. + errno = 0; + fp = fdopen(fd, "w"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); + + // Can't set append on the underlying fd. + errno = 0; + fp = fdopen(fd, "a"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); + + // Bad fd. + errno = 0; + fp = fdopen(-1, "re"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EBADF, errno); + + close(fd); +} + +TEST(STDIO_TEST, fmemopen_invalid_mode) { + errno = 0; + FILE* fp = fmemopen(nullptr, 16, "nonsense"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); +} + +TEST(STDIO_TEST, fopen_invalid_mode) { + errno = 0; + FILE* fp = fopen("/proc/version", "nonsense"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); +} + +TEST(STDIO_TEST, freopen_invalid_mode) { + FILE* fp = fopen("/proc/version", "re"); + ASSERT_TRUE(fp != nullptr); + + errno = 0; + fp = freopen("/proc/version", "nonsense", fp); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(EINVAL, errno); +} + +TEST(STDIO_TEST, asprintf_smoke) { + char* p = nullptr; + ASSERT_EQ(11, asprintf(&p, "hello %s", "world")); + ASSERT_STREQ("hello world", p); + free(p); +} + +TEST(STDIO_TEST, fopen_ENOENT) { + errno = 0; + FILE* fp = fopen("/proc/does-not-exist", "re"); + ASSERT_TRUE(fp == nullptr); + ASSERT_EQ(ENOENT, errno); +} diff --git a/tests/stdlib_test.cpp b/tests/stdlib_test.cpp index 3f1ec866d..c7b2ad89a 100644 --- a/tests/stdlib_test.cpp +++ b/tests/stdlib_test.cpp @@ -800,10 +800,25 @@ static void CheckStrToInt(T fn(const char* s, char** end, int base)) { ASSERT_EQ(T(0), fn("123", &end_p, 37)); ASSERT_EQ(EINVAL, errno); + // Both leading + or - are always allowed (even for the strtou* family). + ASSERT_EQ(T(-123), fn("-123", &end_p, 10)); + ASSERT_EQ(T(123), fn("+123", &end_p, 10)); + // If we see "0x" *not* followed by a hex digit, we shouldn't swallow the 'x'. ASSERT_EQ(T(0), fn("0xy", &end_p, 16)); ASSERT_EQ('x', *end_p); + // Hexadecimal (both the 0x and the digits) is case-insensitive. + ASSERT_EQ(T(0xab), fn("0xab", &end_p, 0)); + ASSERT_EQ(T(0xab), fn("0Xab", &end_p, 0)); + ASSERT_EQ(T(0xab), fn("0xAB", &end_p, 0)); + ASSERT_EQ(T(0xab), fn("0XAB", &end_p, 0)); + ASSERT_EQ(T(0xab), fn("0xAb", &end_p, 0)); + ASSERT_EQ(T(0xab), fn("0XAb", &end_p, 0)); + + // Octal lives! (Sadly.) + ASSERT_EQ(T(0666), fn("0666", &end_p, 0)); + if (std::numeric_limits<T>::is_signed) { // Minimum (such as -128). std::string min{std::to_string(std::numeric_limits<T>::min())}; @@ -878,6 +893,18 @@ TEST(stdlib, strtoumax_smoke) { CheckStrToInt(strtoumax); } +TEST(stdlib, atoi) { + // Implemented using strtol in bionic, so extensive testing unnecessary. + ASSERT_EQ(123, atoi("123four")); + ASSERT_EQ(0, atoi("hello")); +} + +TEST(stdlib, atol) { + // Implemented using strtol in bionic, so extensive testing unnecessary. + ASSERT_EQ(123L, atol("123four")); + ASSERT_EQ(0L, atol("hello")); +} + TEST(stdlib, abs) { ASSERT_EQ(INT_MAX, abs(-INT_MAX)); ASSERT_EQ(INT_MAX, abs(INT_MAX)); diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 0ed0598f6..22be85241 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -64,6 +64,11 @@ TEST(STRING_TEST, strerror) { ASSERT_STREQ("Unknown error 134", strerror(EHWPOISON + 1)); } +TEST(STRING_TEST, strerror_l) { + // bionic just forwards to strerror(3). + ASSERT_STREQ("Success", strerror_l(0, LC_GLOBAL_LOCALE)); +} + #if defined(__BIONIC__) static void* ConcurrentStrErrorFn(void*) { bool equal = (strcmp("Unknown error 2002", strerror(2002)) == 0); @@ -1538,13 +1543,31 @@ TEST(STRING_TEST, memmem_strstr_empty_needle) { } TEST(STRING_TEST, memmem_smoke) { - const char haystack[] = "big\0daddy\0giant\0haystacks"; - ASSERT_EQ(haystack, memmem(haystack, sizeof(haystack), "", 0)); - ASSERT_EQ(haystack + 3, memmem(haystack, sizeof(haystack), "", 1)); + const char haystack[] = "big\0daddy/giant\0haystacks!"; + + // The current memmem() implementation has special cases for needles of + // lengths 0, 1, 2, 3, and 4, plus a long needle case. We test matches at the + // beginning, middle, and end of the haystack. + + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "", 0)); + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "b", 1)); - ASSERT_EQ(haystack + 1, memmem(haystack, sizeof(haystack), "i", 1)); - ASSERT_EQ(haystack + 4, memmem(haystack, sizeof(haystack), "da", 2)); - ASSERT_EQ(haystack + 8, memmem(haystack, sizeof(haystack), "y\0g", 3)); + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "bi", 2)); + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "big", 3)); + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "big\0", 4)); + ASSERT_EQ(haystack + 0, memmem(haystack, sizeof(haystack), "big\0d", 5)); + + ASSERT_EQ(haystack + 2, memmem(haystack, sizeof(haystack), "g", 1)); + ASSERT_EQ(haystack + 10, memmem(haystack, sizeof(haystack), "gi", 2)); + ASSERT_EQ(haystack + 10, memmem(haystack, sizeof(haystack), "gia", 3)); + ASSERT_EQ(haystack + 10, memmem(haystack, sizeof(haystack), "gian", 4)); + ASSERT_EQ(haystack + 10, memmem(haystack, sizeof(haystack), "giant", 5)); + + ASSERT_EQ(haystack + 25, memmem(haystack, sizeof(haystack), "!", 1)); + ASSERT_EQ(haystack + 24, memmem(haystack, sizeof(haystack), "s!", 2)); + ASSERT_EQ(haystack + 23, memmem(haystack, sizeof(haystack), "ks!", 3)); + ASSERT_EQ(haystack + 22, memmem(haystack, sizeof(haystack), "cks!", 4)); + ASSERT_EQ(haystack + 21, memmem(haystack, sizeof(haystack), "acks!", 5)); } TEST(STRING_TEST, strstr_smoke) { @@ -1589,16 +1612,44 @@ TEST(STRING_TEST, strcoll_smoke) { ASSERT_TRUE(strcoll("aac", "aab") > 0); } +TEST(STRING_TEST, strcoll_l_smoke) { + // bionic just forwards to strcoll(3). + ASSERT_TRUE(strcoll_l("aab", "aac", LC_GLOBAL_LOCALE) < 0); + ASSERT_TRUE(strcoll_l("aab", "aab", LC_GLOBAL_LOCALE) == 0); + ASSERT_TRUE(strcoll_l("aac", "aab", LC_GLOBAL_LOCALE) > 0); +} + TEST(STRING_TEST, strxfrm_smoke) { const char* src1 = "aab"; char dst1[16] = {}; - ASSERT_GT(strxfrm(dst1, src1, sizeof(dst1)), 0U); + // Dry run. + ASSERT_EQ(strxfrm(dst1, src1, 0), 3U); + ASSERT_STREQ(dst1, ""); + // Really do it. + ASSERT_EQ(strxfrm(dst1, src1, sizeof(dst1)), 3U); + const char* src2 = "aac"; char dst2[16] = {}; - ASSERT_GT(strxfrm(dst2, src2, sizeof(dst2)), 0U); + // Dry run. + ASSERT_EQ(strxfrm(dst2, src2, 0), 3U); + ASSERT_STREQ(dst2, ""); + // Really do it. + ASSERT_EQ(strxfrm(dst2, src2, sizeof(dst2)), 3U); + + // The "transform" of two different strings should cause different outputs. ASSERT_TRUE(strcmp(dst1, dst2) < 0); } +TEST(STRING_TEST, strxfrm_l_smoke) { + // bionic just forwards to strxfrm(3), so this is a subset of the + // strxfrm test. + const char* src1 = "aab"; + char dst1[16] = {}; + ASSERT_EQ(strxfrm_l(dst1, src1, 0, LC_GLOBAL_LOCALE), 3U); + ASSERT_STREQ(dst1, ""); + ASSERT_EQ(strxfrm_l(dst1, src1, sizeof(dst1), LC_GLOBAL_LOCALE), 3U); +} + TEST(STRING_TEST, memccpy_smoke) { char dst[32]; diff --git a/tests/sys_procfs_test.cpp b/tests/sys_procfs_test.cpp index 8054869eb..5e0a0b024 100644 --- a/tests/sys_procfs_test.cpp +++ b/tests/sys_procfs_test.cpp @@ -18,7 +18,7 @@ #include <sys/procfs.h> -TEST(sys_procfs, smoke) { +TEST(sys_procfs, types) { elf_greg_t reg; memset(®, 0, sizeof(reg)); @@ -37,3 +37,16 @@ TEST(sys_procfs, smoke) { static_assert(sizeof(prgregset_t) == sizeof(elf_gregset_t), ""); static_assert(sizeof(prfpregset_t) == sizeof(elf_fpregset_t), ""); } + +TEST(sys_procfs, constants) { + // NGREG != ELF_NGREG (https://github.com/android/ndk/issues/1347) + static_assert(sizeof(gregset_t) / sizeof(greg_t) == NGREG); + +#if defined(__arm__) + static_assert(sizeof(user_regs) / sizeof(elf_greg_t) == ELF_NGREG); +#elif defined(__aarch64__) + static_assert(sizeof(user_pt_regs) / sizeof(elf_greg_t) == ELF_NGREG); +#else + static_assert(sizeof(user_regs_struct) / sizeof(elf_greg_t) == ELF_NGREG); +#endif +} diff --git a/tests/sys_thread_properties_test.cpp b/tests/sys_thread_properties_test.cpp new file mode 100644 index 000000000..cf1a6ba63 --- /dev/null +++ b/tests/sys_thread_properties_test.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 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. + */ + +#include <gtest/gtest.h> + +#include "gtest_globals.h" +#include "utils.h" + +TEST(thread_properties_test, iterate_dts) { +#if defined(__BIONIC__) + const char expected_out[] = + "got test_static_tls_bounds\niterate_cb i = 0\ndone_iterate_dynamic_tls\n"; + std::string helper = GetTestLibRoot() + "tls_properties_helper/tls_properties_helper"; + chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607 + + ExecTestHelper eth; + eth.SetArgs({helper.c_str(), nullptr}); + eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out); +#endif +} + +TEST(thread_properties_test, thread_exit_cb) { +#if defined(__BIONIC__) + // tests/libs/thread_exit_cb_helper.cpp + const char expected_out[] = "exit_cb_1 called exit_cb_2 called exit_cb_3 called"; + std::string helper = GetTestLibRoot() + "thread_exit_cb_helper/thread_exit_cb_helper"; + chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607 + + ExecTestHelper eth; + eth.SetArgs({helper.c_str(), nullptr}); + eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, expected_out); + +#endif +} diff --git a/tests/sys_vfs_test.cpp b/tests/sys_vfs_test.cpp index a521967bf..f82f50546 100644 --- a/tests/sys_vfs_test.cpp +++ b/tests/sys_vfs_test.cpp @@ -44,12 +44,26 @@ TEST(sys_vfs, statfs) { Check(sb); } +TEST(sys_vfs, statfs_failure) { + struct statfs sb; + errno = 0; + ASSERT_EQ(-1, statfs("/does-not-exist", &sb)); + ASSERT_EQ(ENOENT, errno); +} + TEST(sys_vfs, statfs64) { struct statfs64 sb; ASSERT_EQ(0, statfs64("/proc", &sb)); Check(sb); } +TEST(sys_vfs, statfs64_failure) { + struct statfs64 sb; + errno = 0; + ASSERT_EQ(-1, statfs64("/does-not-exist", &sb)); + ASSERT_EQ(ENOENT, errno); +} + TEST(sys_vfs, fstatfs) { struct statfs sb; int fd = open("/proc", O_RDONLY); @@ -58,6 +72,13 @@ TEST(sys_vfs, fstatfs) { Check(sb); } +TEST(sys_vfs, fstatfs_failure) { + struct statfs sb; + errno = 0; + ASSERT_EQ(-1, fstatfs(-1, &sb)); + ASSERT_EQ(EBADF, errno); +} + TEST(sys_vfs, fstatfs64) { struct statfs64 sb; int fd = open("/proc", O_RDONLY); @@ -65,3 +86,10 @@ TEST(sys_vfs, fstatfs64) { close(fd); Check(sb); } + +TEST(sys_vfs, fstatfs64_failure) { + struct statfs sb; + errno = 0; + ASSERT_EQ(-1, fstatfs(-1, &sb)); + ASSERT_EQ(EBADF, errno); +} diff --git a/tests/sys_wait_test.cpp b/tests/sys_wait_test.cpp new file mode 100644 index 000000000..c0069721d --- /dev/null +++ b/tests/sys_wait_test.cpp @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include <gtest/gtest.h> + +#include <sys/wait.h> + +TEST(sys_wait, waitid) { + pid_t pid = fork(); + ASSERT_NE(pid, -1); + + if (pid == 0) _exit(66); + + siginfo_t si = {}; + ASSERT_EQ(0, waitid(P_PID, pid, &si, WEXITED)); + ASSERT_EQ(pid, si.si_pid); + ASSERT_EQ(66, si.si_status); + ASSERT_EQ(CLD_EXITED, si.si_code); +} diff --git a/tests/time_test.cpp b/tests/time_test.cpp index 74d691dc9..b1de0a446 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -142,7 +142,7 @@ TEST(time, mktime_10310929) { t.tm_mday = 10; #if !defined(__LP64__) - // 32-bit bionic stupidly had a signed 32-bit time_t. + // 32-bit bionic has a signed 32-bit time_t. ASSERT_EQ(-1, mktime(&t)); ASSERT_EQ(EOVERFLOW, errno); #else @@ -363,6 +363,105 @@ TEST(time, strptime_V_G_g) { EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0); } +TEST(time, strptime_Z) { +#if defined(__BIONIC__) + // glibc doesn't handle %Z at all. + // The BSDs only handle hard-coded "GMT" and "UTC", plus whatever two strings + // are in the global `tzname` (which correspond to the current $TZ). + struct tm tm; + setenv("TZ", "Europe/Berlin", 1); + + // "GMT" always works. + tm = {}; + ASSERT_EQ('\0', *strptime("GMT", "%Z", &tm)); + EXPECT_STREQ("GMT", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(0, tm.tm_gmtoff); + + // As does "UTC". + tm = {}; + ASSERT_EQ('\0', *strptime("UTC", "%Z", &tm)); + EXPECT_STREQ("UTC", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(0, tm.tm_gmtoff); + + // Europe/Berlin is known as "CET" when there's no DST. + tm = {}; + ASSERT_EQ('\0', *strptime("CET", "%Z", &tm)); + EXPECT_STREQ("CET", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(3600, tm.tm_gmtoff); + + // Europe/Berlin is known as "CEST" when there's no DST. + tm = {}; + ASSERT_EQ('\0', *strptime("CEST", "%Z", &tm)); + EXPECT_STREQ("CEST", tm.tm_zone); + EXPECT_EQ(1, tm.tm_isdst); + EXPECT_EQ(3600, tm.tm_gmtoff); + + // And as long as we're in Europe/Berlin, those are the only time zone + // abbreviations that are recognized. + tm = {}; + ASSERT_TRUE(strptime("PDT", "%Z", &tm) == nullptr); +#endif +} + +TEST(time, strptime_z) { + struct tm tm; + setenv("TZ", "Europe/Berlin", 1); + + // "UT" is what RFC822 called UTC. + tm = {}; + ASSERT_EQ('\0', *strptime("UT", "%z", &tm)); + EXPECT_STREQ("UTC", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(0, tm.tm_gmtoff); + // "GMT" is RFC822's other name for UTC. + tm = {}; + ASSERT_EQ('\0', *strptime("GMT", "%z", &tm)); + EXPECT_STREQ("UTC", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(0, tm.tm_gmtoff); + + // "Z" ("Zulu") is a synonym for UTC. + tm = {}; + ASSERT_EQ('\0', *strptime("Z", "%z", &tm)); + EXPECT_STREQ("UTC", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(0, tm.tm_gmtoff); + + // "PST"/"PDT" and the other common US zone abbreviations are all supported. + tm = {}; + ASSERT_EQ('\0', *strptime("PST", "%z", &tm)); + EXPECT_STREQ("PST", tm.tm_zone); + EXPECT_EQ(0, tm.tm_isdst); + EXPECT_EQ(-28800, tm.tm_gmtoff); + tm = {}; + ASSERT_EQ('\0', *strptime("PDT", "%z", &tm)); + EXPECT_STREQ("PDT", tm.tm_zone); + EXPECT_EQ(1, tm.tm_isdst); + EXPECT_EQ(-25200, tm.tm_gmtoff); + + // +-hh + tm = {}; + ASSERT_EQ('\0', *strptime("+01", "%z", &tm)); + EXPECT_EQ(3600, tm.tm_gmtoff); + EXPECT_TRUE(tm.tm_zone == nullptr); + EXPECT_EQ(0, tm.tm_isdst); + // +-hhmm + tm = {}; + ASSERT_EQ('\0', *strptime("+0130", "%z", &tm)); + EXPECT_EQ(5400, tm.tm_gmtoff); + EXPECT_TRUE(tm.tm_zone == nullptr); + EXPECT_EQ(0, tm.tm_isdst); + // +-hh:mm + tm = {}; + ASSERT_EQ('\0', *strptime("+01:30", "%z", &tm)); + EXPECT_EQ(5400, tm.tm_gmtoff); + EXPECT_TRUE(tm.tm_zone == nullptr); + EXPECT_EQ(0, tm.tm_isdst); +} + void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) { itimerspec ts; ts.it_value.tv_sec = value_s; @@ -1008,4 +1107,5 @@ TEST(time, timespec_get) { TEST(time, difftime) { ASSERT_EQ(1.0, difftime(1, 0)); + ASSERT_EQ(-1.0, difftime(0, 1)); } diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp index 6b2856169..43d50f888 100644 --- a/tests/unistd_test.cpp +++ b/tests/unistd_test.cpp @@ -1350,6 +1350,11 @@ TEST(UNISTD_TEST, execve_failure) { ASSERT_EQ(EACCES, errno); } +static void append_llvm_cov_env_var(std::string& env_str) { + if (getenv("LLVM_PROFILE_FILE") != nullptr) + env_str.append("__LLVM_PROFILE_RT_INIT_ONCE=__LLVM_PROFILE_RT_INIT_ONCE\n"); +} + TEST(UNISTD_TEST, execve_args) { // int execve(const char* path, char* argv[], char* envp[]); @@ -1361,7 +1366,12 @@ TEST(UNISTD_TEST, execve_args) { // Test environment variable setting too. eth.SetArgs({"printenv", nullptr}); eth.SetEnv({"A=B", nullptr}); - eth.Run([&]() { execve(BIN_DIR "printenv", eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n"); + + std::string expected_output("A=B\n"); + append_llvm_cov_env_var(expected_output); + + eth.Run([&]() { execve(BIN_DIR "printenv", eth.GetArgs(), eth.GetEnv()); }, 0, + expected_output.c_str()); } TEST(UNISTD_TEST, execl_failure) { @@ -1386,8 +1396,13 @@ TEST(UNISTD_TEST, execle_failure) { TEST(UNISTD_TEST, execle) { ExecTestHelper eth; eth.SetEnv({"A=B", nullptr}); + + std::string expected_output("A=B\n"); + append_llvm_cov_env_var(expected_output); + // int execle(const char* path, const char* arg, ..., char* envp[]); - eth.Run([&]() { execle(BIN_DIR "printenv", "printenv", nullptr, eth.GetEnv()); }, 0, "A=B\n"); + eth.Run([&]() { execle(BIN_DIR "printenv", "printenv", nullptr, eth.GetEnv()); }, 0, + expected_output.c_str()); } TEST(UNISTD_TEST, execv_failure) { @@ -1450,7 +1465,11 @@ TEST(UNISTD_TEST, execvpe) { // Test environment variable setting too. eth.SetArgs({"printenv", nullptr}); eth.SetEnv({"A=B", nullptr}); - eth.Run([&]() { execvpe("printenv", eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n"); + + std::string expected_output("A=B\n"); + append_llvm_cov_env_var(expected_output); + + eth.Run([&]() { execvpe("printenv", eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str()); } TEST(UNISTD_TEST, execvpe_ENOEXEC) { @@ -1538,7 +1557,11 @@ TEST(UNISTD_TEST, fexecve_args) { ASSERT_NE(-1, printenv_fd); eth.SetArgs({"printenv", nullptr}); eth.SetEnv({"A=B", nullptr}); - eth.Run([&]() { fexecve(printenv_fd, eth.GetArgs(), eth.GetEnv()); }, 0, "A=B\n"); + + std::string expected_output("A=B\n"); + append_llvm_cov_env_var(expected_output); + + eth.Run([&]() { fexecve(printenv_fd, eth.GetArgs(), eth.GetEnv()); }, 0, expected_output.c_str()); close(printenv_fd); } diff --git a/tests/utmp_test.cpp b/tests/utmp_test.cpp index 0fa55c74b..6d0d6f127 100644 --- a/tests/utmp_test.cpp +++ b/tests/utmp_test.cpp @@ -24,8 +24,10 @@ TEST(utmp, login_tty) { ASSERT_EQ(-1, login_tty(-1)); } -TEST(utmp, setutent_getutent_endutent) { +TEST(utmp, smoke) { + ASSERT_EQ(-1, utmpname("hello")); setutent(); - getutent(); + ASSERT_EQ(NULL, getutent()); endutent(); + ASSERT_EQ(NULL, pututline(NULL)); } |