diff options
Diffstat (limited to 'tests')
24 files changed, 1094 insertions, 198 deletions
diff --git a/tests/Android.build.mk b/tests/Android.build.mk index d4b0396..63729da 100644 --- a/tests/Android.build.mk +++ b/tests/Android.build.mk @@ -15,6 +15,7 @@ # include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(common_additional_dependencies) LOCAL_MODULE := $(module) LOCAL_MODULE_TAGS := $(module_tag) @@ -37,6 +38,10 @@ LOCAL_CLANG := $($(module)_clang_$(build_type)) LOCAL_FORCE_STATIC_EXECUTABLE := $($(module)_force_static_executable) +ifneq ($($(module)_multilib),) + LOCAL_MULTILIB := $($(module)_multilib) +endif + LOCAL_CFLAGS := \ $(common_cflags) \ $($(module)_cflags) \ diff --git a/tests/Android.mk b/tests/Android.mk index 8184bf7..8b0b0a0 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -28,6 +28,8 @@ else build_host := false endif +common_additional_dependencies := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # All standard tests. # ----------------------------------------------------------------------------- @@ -112,6 +114,7 @@ libBionicStandardTests_src_files := \ system_properties_test.cpp \ time_test.cpp \ uchar_test.cpp \ + uniqueptr_test.cpp \ unistd_test.cpp \ wchar_test.cpp \ @@ -133,9 +136,6 @@ libBionicStandardTests_c_includes := \ libBionicStandardTests_ldlibs_host := \ -lrt \ -libBionicStandardTests_whole_static_libraries := \ - libBionicUnwindTest \ - module := libBionicStandardTests module_tag := optional build_type := target @@ -145,36 +145,16 @@ build_type := host include $(LOCAL_PATH)/Android.build.mk # ----------------------------------------------------------------------------- -# Special stack unwinding test library compiled with special flags. -# ----------------------------------------------------------------------------- -libBionicUnwindTest_cflags := \ - $(test_cflags) \ - -fexceptions \ - -fnon-call-exceptions \ - -libBionicUnwindTest_src_files := \ - stack_unwinding_test_impl.c \ - -module := libBionicUnwindTest -module_tag := optional -build_type := target -build_target := STATIC_TEST_LIBRARY -include $(LOCAL_PATH)/Android.build.mk -build_type := host -include $(LOCAL_PATH)/Android.build.mk - -# ----------------------------------------------------------------------------- # Fortify tests. # ----------------------------------------------------------------------------- $(foreach compiler,gcc clang, \ $(foreach test,1 2, \ $(eval fortify$(test)-tests-$(compiler)_cflags := \ $(test_cflags) \ + -Wno-error \ -U_FORTIFY_SOURCE \ -D_FORTIFY_SOURCE=$(test) \ -DTEST_NAME=Fortify$(test)_$(compiler)); \ - $(eval fortify$(test)-tests-$(compiler)_cflags_host := \ - -Wno-error); \ $(eval fortify$(test)-tests-$(compiler)_src_files := \ fortify_test.cpp); \ $(eval fortify_libs += fortify$(test)-tests-$(compiler)); \ @@ -249,6 +229,11 @@ bionic-unit-tests_src_files := \ dlfcn_test.cpp \ bionic-unit-tests_cflags := $(test_cflags) + +bionic-unit-tests_conlyflags := \ + -fexceptions \ + -fnon-call-exceptions \ + bionic-unit-tests_cppflags := $(test_cppflags) bionic-unit-tests_ldflags := \ @@ -256,6 +241,7 @@ bionic-unit-tests_ldflags := \ -Wl,-u,DlSymTestFunction \ bionic-unit-tests_c_includes := \ + bionic/libc \ $(call include-path-for, libpagemap) \ bionic-unit-tests_shared_libraries_target := \ @@ -299,6 +285,7 @@ ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x bionic-unit-tests-glibc_src_files := \ atexit_test.cpp \ + dlfcn_test.cpp \ bionic-unit-tests-glibc_whole_static_libraries := \ libBionicStandardTests \ @@ -306,8 +293,12 @@ bionic-unit-tests-glibc_whole_static_libraries := \ bionic-unit-tests-glibc_ldlibs := \ -lrt -ldl \ +bionic-unit-tests-glibc_c_includes := \ + bionic/libc \ + bionic-unit-tests-glibc_cflags := $(test_cflags) bionic-unit-tests-glibc_cppflags := $(test_cppflags) +bionic-unit-tests-glibc_ldflags := -Wl,--export-dynamic module := bionic-unit-tests-glibc module_tag := optional @@ -356,6 +347,22 @@ bionic-unit-tests-run-on-host: bionic-unit-tests $(TARGET_OUT_EXECUTABLES)/$(LIN $(TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests$(NATIVE_TEST_SUFFIX) $(BIONIC_TEST_FLAGS) endif +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86_64)) +# add target to run lp32 tests +bionic-unit-tests-run-on-host32: bionic-unit-tests_32 $(TARGET_OUT_EXECUTABLES)/$(LINKER) $(TARGET_OUT_EXECUTABLES)/sh + if [ ! -d /system -o ! -d /system/bin ]; then \ + echo "Attempting to create /system/bin"; \ + sudo mkdir -p -m 0777 /system/bin; \ + fi + mkdir -p $(TARGET_OUT_DATA)/local/tmp + cp $(TARGET_OUT_EXECUTABLES)/linker /system/bin + cp $(TARGET_OUT_EXECUTABLES)/sh /system/bin + ANDROID_DATA=$(TARGET_OUT_DATA) \ + ANDROID_ROOT=$(TARGET_OUT) \ + LD_LIBRARY_PATH=$(2ND_TARGET_OUT_SHARED_LIBRARIES) \ + $(2ND_TARGET_OUT_DATA_NATIVE_TESTS)/bionic-unit-tests/bionic-unit-tests32 $(BIONIC_TEST_FLAGS) +endif + endif # linux-x86 include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h index 89a14a6..3ec23b0 100644 --- a/tests/ScopedSignalHandler.h +++ b/tests/ScopedSignalHandler.h @@ -21,9 +21,10 @@ class ScopedSignalHandler { public: - ScopedSignalHandler(int signal_number, void (*handler)(int)) : signal_number_(signal_number) { + ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0) + : signal_number_(signal_number) { sigemptyset(&action_.sa_mask); - action_.sa_flags = 0; + action_.sa_flags = sa_flags; action_.sa_handler = handler; sigaction(signal_number_, &action_, &old_action_); } diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index da63046..7f706c1 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -31,7 +31,7 @@ #define ASSERT_DL_NOTNULL(ptr) \ - ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() + ASSERT_TRUE(ptr != nullptr) << "dlerror: " << dlerror() #define ASSERT_DL_ZERO(i) \ ASSERT_EQ(0, i) << "dlerror: " << dlerror() @@ -46,23 +46,31 @@ typedef int (*fn)(void); #define LIBSIZE 1024*1024 // how much address space to reserve for it #if defined(__LP64__) -#define LIBPATH "%s/nativetest64/libdlext_test_fd/libdlext_test_fd.so" +#define LIBPATH_PREFIX "%s/nativetest64/libdlext_test_fd/" #else -#define LIBPATH "%s/nativetest/libdlext_test_fd/libdlext_test_fd.so" +#define LIBPATH_PREFIX "%s/nativetest/libdlext_test_fd/" #endif +#define LIBPATH LIBPATH_PREFIX "libdlext_test_fd.so" +#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip" + +#define LIBZIP_OFFSET 2*PAGE_SIZE + class DlExtTest : public ::testing::Test { protected: virtual void SetUp() { - handle_ = NULL; + handle_ = nullptr; // verify that we don't have the library loaded already - ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber")); + void* h = dlopen(LIBNAME, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(h == nullptr); + h = dlopen(LIBNAME_NORELRO, RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(h == nullptr); // call dlerror() to swallow the error, and check it was the one we wanted - ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror()); + ASSERT_STREQ("dlopen failed: library \"" LIBNAME_NORELRO "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); } virtual void TearDown() { - if (handle_ != NULL) { + if (handle_ != nullptr) { ASSERT_DL_ZERO(dlclose(handle_)); } } @@ -71,7 +79,7 @@ protected: }; TEST_F(DlExtTest, ExtInfoNull) { - handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL); + handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, nullptr); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); @@ -90,7 +98,7 @@ TEST_F(DlExtTest, ExtInfoNoFlags) { TEST_F(DlExtTest, ExtInfoUseFd) { const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != NULL); + ASSERT_TRUE(android_data != nullptr); char lib_path[PATH_MAX]; snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data); @@ -105,8 +113,64 @@ TEST_F(DlExtTest, ExtInfoUseFd) { EXPECT_EQ(4, f()); } +TEST_F(DlExtTest, ExtInfoUseFdWithOffset) { + const char* android_data = getenv("ANDROID_DATA"); + ASSERT_TRUE(android_data != nullptr); + + char lib_path[PATH_MAX]; + snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); + + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); + extinfo.library_fd_offset = LIBZIP_OFFSET; + + handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo); + ASSERT_DL_NOTNULL(handle_); + + fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber")); + ASSERT_DL_NOTNULL(f); + EXPECT_EQ(4, f()); +} + +TEST_F(DlExtTest, ExtInfoUseFdWithInvalidOffset) { + const char* android_data = getenv("ANDROID_DATA"); + ASSERT_TRUE(android_data != nullptr); + + char lib_path[PATH_MAX]; + snprintf(lib_path, sizeof(lib_path), LIBZIPPATH, android_data); + + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC)); + extinfo.library_fd_offset = 17; + + handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); + ASSERT_TRUE(handle_ == nullptr); + ASSERT_STREQ("dlopen failed: file offset for the library \"libname_placeholder\" is not page-aligned: 17", dlerror()); + + extinfo.library_fd_offset = (5LL<<58) + PAGE_SIZE; + handle_ = android_dlopen_ext("libname_placeholder", RTLD_NOW, &extinfo); + + ASSERT_TRUE(handle_ == nullptr); + // TODO: Better error message when reading with offset > file_size + ASSERT_STREQ("dlopen failed: \"libname_placeholder\" has bad ELF magic", dlerror()); + + close(extinfo.library_fd); +} + +TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) { + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; + extinfo.library_fd_offset = LIBZIP_OFFSET; + + handle_ = android_dlopen_ext("/some/lib/that/does_not_exist", RTLD_NOW, &extinfo); + ASSERT_TRUE(handle_ == nullptr); + ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); +} + TEST_F(DlExtTest, Reserved) { - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -124,7 +188,7 @@ TEST_F(DlExtTest, Reserved) { } TEST_F(DlExtTest, ReservedTooSmall) { - void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -132,11 +196,11 @@ TEST_F(DlExtTest, ReservedTooSmall) { extinfo.reserved_addr = start; extinfo.reserved_size = PAGE_SIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); - EXPECT_EQ(NULL, handle_); + EXPECT_EQ(nullptr, handle_); } TEST_F(DlExtTest, ReservedHint) { - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -154,7 +218,7 @@ TEST_F(DlExtTest, ReservedHint) { } TEST_F(DlExtTest, ReservedHintTooSmall) { - void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; @@ -174,7 +238,7 @@ class DlExtRelroSharingTest : public DlExtTest { protected: virtual void SetUp() { DlExtTest::SetUp(); - void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, + void* start = mmap(nullptr, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); extinfo_.flags = ANDROID_DLEXT_RESERVED_ADDRESS; @@ -183,7 +247,7 @@ protected: extinfo_.relro_fd = -1; const char* android_data = getenv("ANDROID_DATA"); - ASSERT_TRUE(android_data != NULL); + ASSERT_TRUE(android_data != nullptr); snprintf(relro_file_, sizeof(relro_file_), "%s/local/tmp/libdlext_test.relro", android_data); } @@ -204,7 +268,7 @@ protected: extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO; extinfo_.relro_fd = relro_fd; void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_); - if (handle == NULL) { + if (handle == nullptr) { fprintf(stderr, "in child: %s\n", dlerror()); exit(1); } @@ -327,7 +391,7 @@ void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool sha } else { handle = dlopen(lib, RTLD_NOW); } - if (handle == NULL) { + if (handle == nullptr) { fprintf(stderr, "in child: %s\n", dlerror()); exit(1); } diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 457fcd5..e24af13 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -22,6 +22,8 @@ #include <stdio.h> #include <stdint.h> +#include "private/ScopeGuard.h" + #include <string> #define ASSERT_SUBSTR(needle, haystack) \ @@ -87,6 +89,144 @@ TEST(dlfcn, dlopen_noload) { ASSERT_EQ(0, dlclose(handle2)); } +// ifuncs are only supported on intel and arm64 for now +#if defined(__i386__) || defined(__x86_64__) +TEST(dlfcn, ifunc) { + typedef const char* (*fn_ptr)(); + + // ifunc's choice depends on whether IFUNC_CHOICE has a value + // first check the set case + setenv("IFUNC_CHOICE", "set", 1); + void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL); + fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); + fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); + ASSERT_TRUE(foo_ptr != NULL); + ASSERT_TRUE(foo_library_ptr != NULL); + ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0); + ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0); + dlclose(handle); + + // then check the unset case + unsetenv("IFUNC_CHOICE"); + handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != NULL); + foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); + foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); + ASSERT_TRUE(foo_ptr != NULL); + ASSERT_TRUE(foo_library_ptr != NULL); + ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); + ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); + dlclose(handle); +} + +TEST(dlfcn, ifunc_ctor_call) { + typedef const char* (*fn_ptr)(); + + void* handle = dlopen("libtest_ifunc.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + fn_ptr is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_irelative")); + ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); + ASSERT_STREQ("false", is_ctor_called()); + + is_ctor_called = reinterpret_cast<fn_ptr>(dlsym(handle, "is_ctor_called_jump_slot")); + ASSERT_TRUE(is_ctor_called != nullptr) << dlerror(); + ASSERT_STREQ("true", is_ctor_called()); + dlclose(handle); +} +#endif + +TEST(dlfcn, dlopen_check_relocation_dt_needed_order) { + // This is the structure of the test library and + // its dt_needed libraries + // libtest_relo_check_dt_needed_order.so + // | + // +-> libtest_relo_check_dt_needed_order_1.so + // | + // +-> libtest_relo_check_dt_needed_order_2.so + // + // The root library references relo_test_get_answer_lib - which is defined + // in both dt_needed libraries, the correct relocation should + // use the function defined in libtest_relo_check_dt_needed_order_1.so + void* handle = nullptr; + auto guard = make_scope_guard([&]() { + dlclose(handle); + }); + + handle = dlopen("libtest_relo_check_dt_needed_order.so", RTLD_NOW); + ASSERT_TRUE(handle != nullptr) << dlerror(); + + typedef int (*fn_t) (void); + fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "relo_test_get_answer")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + ASSERT_EQ(1, fn()); +} + +TEST(dlfcn, dlopen_check_order) { + // Here is how the test library and its dt_needed + // libraries are arranged + // + // libtest_check_order.so + // | + // +-> libtest_check_order_1_left.so + // | | + // | +-> libtest_check_order_a.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_2_right.so + // | | + // | +-> libtest_check_order_d.so + // | | + // | +-> libtest_check_order_b.so + // | + // +-> libtest_check_order_3_c.so + // + // load order should be (1, 2, 3, a, b, d) + // + // get_answer() is defined in (2, 3, a, b, c) + // get_answer2() is defined in (b, d) + void* sym = dlsym(RTLD_DEFAULT, "dlopen_test_get_answer"); + ASSERT_TRUE(sym == nullptr); + void* handle = dlopen("libtest_check_order.so", RTLD_NOW | RTLD_GLOBAL); + ASSERT_TRUE(handle != nullptr); + typedef int (*fn_t) (void); + fn_t fn, fn2; + fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer")); + ASSERT_TRUE(fn != NULL) << dlerror(); + fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "dlopen_test_get_answer2")); + ASSERT_TRUE(fn2 != NULL) << dlerror(); + + ASSERT_EQ(42, fn()); + ASSERT_EQ(43, fn2()); + dlclose(handle); +} + +// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so -> +// libtest_with_dependency_loop_b.so -> libtest_with_dependency_loop_c.so -> +// libtest_with_dependency_loop_a.so +TEST(dlfcn, dlopen_check_loop) { + void* handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW); +#if defined(__BIONIC__) + ASSERT_TRUE(handle == nullptr); + ASSERT_STREQ("dlopen failed: recursive link to \"libtest_with_dependency_loop_a.so\"", dlerror()); + // This symbol should never be exposed + void* f = dlsym(RTLD_DEFAULT, "dlopen_test_invalid_function"); + ASSERT_TRUE(f == nullptr); + ASSERT_SUBSTR("undefined symbol: dlopen_test_invalid_function", dlerror()); + + // dlopen second time to make sure that the library wasn't loaded even though dlopen returned null. + // This may happen if during cleanup the root library or one of the depended libs were not removed + // from soinfo list. + handle = dlopen("libtest_with_dependency_loop.so", RTLD_NOW | RTLD_NOLOAD); + ASSERT_TRUE(handle == nullptr); + ASSERT_STREQ("dlopen failed: library \"libtest_with_dependency_loop.so\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror()); +#else // glibc allows recursive links + ASSERT_TRUE(handle != nullptr); + dlclose(handle); +#endif +} + TEST(dlfcn, dlopen_failure) { void* self = dlopen("/does/not/exist", RTLD_NOW); ASSERT_TRUE(self == NULL); diff --git a/tests/libs/Android.build.dlext_testzip.mk b/tests/libs/Android.build.dlext_testzip.mk new file mode 100644 index 0000000..d05927e --- /dev/null +++ b/tests/libs/Android.build.dlext_testzip.mk @@ -0,0 +1,41 @@ +# +# 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. +# + +# ----------------------------------------------------------------------------- +# Library used by dlext tests - zipped and aligned +# ----------------------------------------------------------------------------- + +include $(CLEAR_VARS) + +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE := libdlext_test_fd_zipaligned +LOCAL_MODULE_SUFFIX := .zip +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE_PATH := $($(bionic_2nd_arch_prefix)TARGET_OUT_DATA_NATIVE_TESTS)/libdlext_test_fd +LOCAL_2ND_ARCH_VAR_PREFIX := $(bionic_2nd_arch_prefix) + +include $(BUILD_SYSTEM)/base_rules.mk + +my_shared_libs := \ + $($(bionic_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdlext_test_fd.so + +$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE +$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN) + @echo "Zipalign $(PRIVATE_ALIGNMENT): $@" + $(hide) rm -rf $(dir $@) && mkdir -p $(dir $@) + $(hide) cp $^ $(dir $@) + $(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt *.so) + $(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@ diff --git a/tests/libs/Android.build.testlib.mk b/tests/libs/Android.build.testlib.mk new file mode 100644 index 0000000..5b688e4 --- /dev/null +++ b/tests/libs/Android.build.testlib.mk @@ -0,0 +1,22 @@ +# +# 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. +# + +build_target := SHARED_LIBRARY +build_type := host +include $(TEST_PATH)/Android.build.mk +build_type := target +include $(TEST_PATH)/Android.build.mk + diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk index 75df539..af3e070 100644 --- a/tests/libs/Android.mk +++ b/tests/libs/Android.mk @@ -17,6 +17,13 @@ LOCAL_PATH := $(call my-dir) TEST_PATH := $(LOCAL_PATH)/.. +common_cppflags += -std=gnu++11 +common_additional_dependencies := \ + $(LOCAL_PATH)/Android.mk \ + $(LOCAL_PATH)/Android.build.dlext_testzip.mk \ + $(LOCAL_PATH)/Android.build.testlib.mk \ + $(TEST_PATH)/Android.build.mk + # ----------------------------------------------------------------------------- # Library used by dlfcn tests. # ----------------------------------------------------------------------------- @@ -29,9 +36,7 @@ no-elf-hash-table-library_ldflags := \ module := no-elf-hash-table-library module_tag := optional -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk endif # ----------------------------------------------------------------------------- @@ -45,15 +50,13 @@ libdlext_test_ldflags := \ module := libdlext_test module_tag := optional -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # create symlink to libdlext_test.so for symlink test # ----------------------------------------------------------------------------- # Use = instead of := to defer the evaluation of $@ -$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD = \ +$(TARGET_OUT)/lib/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so ifneq ($(TARGET_2ND_ARCH),) @@ -62,6 +65,13 @@ $(TARGET_OUT)/lib64/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so endif +# host symlinks +$(HOST_OUT)/lib64/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ + $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so + +$(HOST_OUT)/lib/libdlext_test.so: PRIVATE_POST_INSTALL_CMD = \ + $(hide) cd $(dir $@) && ln -sf $(notdir $@) libdlext_test_v2.so + # ----------------------------------------------------------------------------- # Library used by dlext tests - without GNU RELRO program header # ----------------------------------------------------------------------------- @@ -91,15 +101,175 @@ build_target := SHARED_LIBRARY include $(TEST_PATH)/Android.build.mk # ----------------------------------------------------------------------------- +# Library used by dlext tests - zipped and aligned +# ----------------------------------------------------------------------------- +include $(CLEAR_VARS) +bionic_2nd_arch_prefix := +include $(LOCAL_PATH)/Android.build.dlext_testzip.mk +ifneq ($(TARGET_2ND_ARCH),) + bionic_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX) + include $(LOCAL_PATH)/Android.build.dlext_testzip.mk +endif + +# ----------------------------------------------------------------------------- # Library used by dlfcn tests # ----------------------------------------------------------------------------- libtest_simple_src_files := \ dlopen_testlib_simple.cpp module := libtest_simple -build_type := target -build_target := SHARED_LIBRARY -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Libraries used by dlfcn tests to verify correct load order: +# libtest_check_order_2_right.so +# ----------------------------------------------------------------------------- +libtest_check_order_2_right_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_2_right_cflags := -D__ANSWER=42 +module := libtest_check_order_2_right +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_a.so +# ----------------------------------------------------------------------------- +libtest_check_order_a_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_a_cflags := -D__ANSWER=1 +module := libtest_check_order_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_b.so +# ----------------------------------------------------------------------------- +libtest_check_order_b_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_b_cflags := -D__ANSWER=2 -D__ANSWER2=43 +module := libtest_check_order_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_c.so +# ----------------------------------------------------------------------------- +libtest_check_order_3_c_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_3_c_cflags := -D__ANSWER=3 +module := libtest_check_order_3_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_d.so +# ----------------------------------------------------------------------------- +libtest_check_order_d_src_files := \ + dlopen_testlib_answer.cpp + +libtest_check_order_d_shared_libraries := libtest_check_order_b +libtest_check_order_d_cflags := -D__ANSWER=4 -D__ANSWER2=4 +module := libtest_check_order_d +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order_left.so +# ----------------------------------------------------------------------------- +libtest_check_order_1_left_src_files := \ + empty.cpp + +libtest_check_order_1_left_shared_libraries := libtest_check_order_a libtest_check_order_b + +module := libtest_check_order_1_left +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_check_order.so +# ----------------------------------------------------------------------------- +libtest_check_order_src_files := \ + empty.cpp + +libtest_check_order_shared_libraries := libtest_check_order_1_left \ + libtest_check_order_2_right libtest_check_order_3_c + +module := libtest_check_order +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library with dependency loop used by dlfcn tests +# +# libtest_with_dependency_loop -> a -> b -> c -> a +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_src_files := dlopen_testlib_invalid.cpp + +libtest_with_dependency_loop_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_a.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_a_src_files := dlopen_testlib_invalid.cpp + +libtest_with_dependency_loop_a_shared_libraries := \ + libtest_with_dependency_loop_b_tmp + +module := libtest_with_dependency_loop_a +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# +# this is temporary placeholder - will be removed +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_tmp_src_files := dlopen_testlib_invalid.cpp +libtest_with_dependency_loop_b_tmp_ldflags := -Wl,-soname=libtest_with_dependency_loop_b.so + +module := libtest_with_dependency_loop_b_tmp +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_b.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_b_src_files := dlopen_testlib_invalid.cpp +libtest_with_dependency_loop_b_shared_libraries := libtest_with_dependency_loop_c + +module := libtest_with_dependency_loop_b +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_with_dependency_loop_c.so +# ----------------------------------------------------------------------------- +libtest_with_dependency_loop_c_src_files := dlopen_testlib_invalid.cpp + +libtest_with_dependency_loop_c_shared_libraries := \ + libtest_with_dependency_loop_a + +module := libtest_with_dependency_loop_c +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# libtest_relo_check_dt_needed_order.so +# | +# +-> libtest_relo_check_dt_needed_order_1.so +# | +# +-> libtest_relo_check_dt_needed_order_2.so +# ----------------------------------------------------------------------------- +libtest_relo_check_dt_needed_order_shared_libraries := \ + libtest_relo_check_dt_needed_order_1 libtest_relo_check_dt_needed_order_2 + +libtest_relo_check_dt_needed_order_src_files := dlopen_testlib_relo_check_dt_needed_order.cpp +libtest_relo_check_dt_needed_order_1_src_files := dlopen_testlib_relo_check_dt_needed_order_1.cpp +libtest_relo_check_dt_needed_order_2_src_files := dlopen_testlib_relo_check_dt_needed_order_2.cpp + +module := libtest_relo_check_dt_needed_order +include $(LOCAL_PATH)/Android.build.testlib.mk +module := libtest_relo_check_dt_needed_order_1 +include $(LOCAL_PATH)/Android.build.testlib.mk +module := libtest_relo_check_dt_needed_order_2 +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with dependency used by dlfcn tests @@ -110,10 +280,33 @@ libtest_with_dependency_src_files := \ libtest_with_dependency_shared_libraries := libdlext_test module := libtest_with_dependency -build_type := target +include $(LOCAL_PATH)/Android.build.testlib.mk + +# ----------------------------------------------------------------------------- +# Library used by ifunc tests +# ----------------------------------------------------------------------------- +libtest_ifunc_src_files := \ + dlopen_testlib_ifunc.c + +libtest_ifunc_clang_host := false +module := libtest_ifunc build_target := SHARED_LIBRARY + +build_type := host include $(TEST_PATH)/Android.build.mk +ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),x86 x86_64)) + ifeq ($(TARGET_ARCH),arm64) + libtest_ifunc_multilib := 64 + # TODO: This is a workaround - remove it once gcc + # removes its Android ifunc checks + libtest_ifunc_cflags := -mglibc + endif + + build_type := target + include $(TEST_PATH)/Android.build.mk +endif + # ----------------------------------------------------------------------------- # Library used by atexit tests # ----------------------------------------------------------------------------- @@ -122,11 +315,7 @@ libtest_atexit_src_files := \ atexit_testlib.cpp module := libtest_atexit -build_target := SHARED_LIBRARY -build_type := target -include $(TEST_PATH)/Android.build.mk -build_type := host -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk # ----------------------------------------------------------------------------- # Library with weak function @@ -135,8 +324,4 @@ libtest_dlsym_weak_func_src_files := \ dlsym_weak_function.cpp module := libtest_dlsym_weak_func -build_target := SHARED_LIBRARY -build_type := target -include $(TEST_PATH)/Android.build.mk -build_type := host -include $(TEST_PATH)/Android.build.mk +include $(LOCAL_PATH)/Android.build.testlib.mk diff --git a/tests/libs/dlopen_testlib_answer.cpp b/tests/libs/dlopen_testlib_answer.cpp new file mode 100644 index 0000000..a4d7504 --- /dev/null +++ b/tests/libs/dlopen_testlib_answer.cpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +extern "C" int dlopen_test_get_answer() { + return __ANSWER; +} + +#ifdef __ANSWER2 +extern "C" int dlopen_test_get_answer2() { + return __ANSWER2; +} +#endif diff --git a/tests/libs/dlopen_testlib_ifunc.c b/tests/libs/dlopen_testlib_ifunc.c new file mode 100644 index 0000000..b68a3dd --- /dev/null +++ b/tests/libs/dlopen_testlib_ifunc.c @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> + +static int g_flag = 0; + +static void __attribute__((constructor)) init_flag() { + g_flag = 1; +} + +static const char* is_ctor_called() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +const char* foo() __attribute__ ((ifunc ("foo_ifunc"))); + +// Static linker creates GLOBAL/IFUNC symbol and JUMP_SLOT relocation type for plt segment +const char* is_ctor_called_jump_slot() __attribute__ ((ifunc("is_ctor_called_ifun"))); + +const char* is_ctor_called_irelative() { + // Call internal ifunc-resolved function with IRELATIVE reloc + return is_ctor_called(); +} + +const char* return_true() { + return "true"; +} + +const char* return_false() { + return "false"; +} + +const char* f1() { + return "unset"; +} + +const char* f2() { + return "set"; +} + +void* is_ctor_called_ifun() { + return g_flag == 0 ? return_false : return_true; +} + +void* foo_ifunc() { + char* choice = getenv("IFUNC_CHOICE"); + return choice == NULL ? f1 : f2; +} + +const char* foo_library() { + return foo(); +} diff --git a/tests/libs/dlopen_testlib_invalid.cpp b/tests/libs/dlopen_testlib_invalid.cpp new file mode 100644 index 0000000..f2039c6 --- /dev/null +++ b/tests/libs/dlopen_testlib_invalid.cpp @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include <stdlib.h> + +// This file is used for libraries that are not supposed to +// be successfully loaded/linked - therefore, this function should +// not be visible via dlsym - (we are going to use this fact in tests) +extern "C" int dlopen_test_invalid_function() { + abort(); +} diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp new file mode 100644 index 0000000..d8fb543 --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order.cpp @@ -0,0 +1,21 @@ +/* + * 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. + */ + +extern "C" int relo_test_get_answer_lib(); + +extern "C" int relo_test_get_answer() { + return relo_test_get_answer_lib(); +} diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp new file mode 100644 index 0000000..4c877d0 --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_1.cpp @@ -0,0 +1,19 @@ +/* + * 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. + */ + +extern "C" int relo_test_get_answer_lib() { + return 1; +} diff --git a/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp new file mode 100644 index 0000000..10288a0 --- /dev/null +++ b/tests/libs/dlopen_testlib_relo_check_dt_needed_order_2.cpp @@ -0,0 +1,19 @@ +/* + * 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. + */ + +extern "C" int relo_test_get_answer_lib() { + return 2; +} diff --git a/tests/libs/dlopen_testlib_simple.cpp b/tests/libs/dlopen_testlib_simple.cpp index afe54b4..bf750b2 100644 --- a/tests/libs/dlopen_testlib_simple.cpp +++ b/tests/libs/dlopen_testlib_simple.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <stdint.h> #include <stdlib.h> uint32_t dlopen_testlib_taxicab_number = 1729; diff --git a/tests/math_test.cpp b/tests/math_test.cpp index b4f5b14..2203db9 100644 --- a/tests/math_test.cpp +++ b/tests/math_test.cpp @@ -53,6 +53,8 @@ template<typename T> inline int test_capture_isinf(const T in) { #include <limits.h> #include <stdint.h> +#include <private/ScopeGuard.h> + float float_subnormal() { union { float f; @@ -760,6 +762,10 @@ TEST(math, erfcl) { } TEST(math, lrint) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); + fesetround(FE_UPWARD); // lrint/lrintf/lrintl obey the rounding mode. ASSERT_EQ(1235, lrint(1234.01)); ASSERT_EQ(1235, lrintf(1234.01f)); @@ -780,6 +786,10 @@ TEST(math, lrint) { } TEST(math, rint) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); + fesetround(FE_UPWARD); // rint/rintf/rintl obey the rounding mode. feclearexcept(FE_ALL_EXCEPT); // rint/rintf/rintl do set the FE_INEXACT flag. ASSERT_EQ(1234.0, rint(1234.0)); @@ -806,6 +816,9 @@ TEST(math, rint) { } TEST(math, nearbyint) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // nearbyint/nearbyintf/nearbyintl obey the rounding mode. feclearexcept(FE_ALL_EXCEPT); // nearbyint/nearbyintf/nearbyintl don't set the FE_INEXACT flag. ASSERT_EQ(1234.0, nearbyint(1234.0)); @@ -832,6 +845,9 @@ TEST(math, nearbyint) { } TEST(math, lround) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // lround ignores the rounding mode. ASSERT_EQ(1234, lround(1234.01)); ASSERT_EQ(1234, lroundf(1234.01f)); @@ -839,6 +855,9 @@ TEST(math, lround) { } TEST(math, llround) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // llround ignores the rounding mode. ASSERT_EQ(1234L, llround(1234.01)); ASSERT_EQ(1234L, llroundf(1234.01f)); @@ -933,6 +952,9 @@ TEST(math, fdiml) { } TEST(math, round) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // round ignores the rounding mode and always rounds away from zero. ASSERT_DOUBLE_EQ(1.0, round(0.5)); ASSERT_DOUBLE_EQ(-1.0, round(-0.5)); @@ -943,6 +965,9 @@ TEST(math, round) { } TEST(math, roundf) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // roundf ignores the rounding mode and always rounds away from zero. ASSERT_FLOAT_EQ(1.0f, roundf(0.5f)); ASSERT_FLOAT_EQ(-1.0f, roundf(-0.5f)); @@ -953,6 +978,9 @@ TEST(math, roundf) { } TEST(math, roundl) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_TOWARDZERO); // roundl ignores the rounding mode and always rounds away from zero. ASSERT_DOUBLE_EQ(1.0L, roundl(0.5L)); ASSERT_DOUBLE_EQ(-1.0L, roundl(-0.5L)); @@ -963,6 +991,9 @@ TEST(math, roundl) { } TEST(math, trunc) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // trunc ignores the rounding mode and always rounds toward zero. ASSERT_DOUBLE_EQ(1.0, trunc(1.5)); ASSERT_DOUBLE_EQ(-1.0, trunc(-1.5)); @@ -973,6 +1004,9 @@ TEST(math, trunc) { } TEST(math, truncf) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // truncf ignores the rounding mode and always rounds toward zero. ASSERT_FLOAT_EQ(1.0f, truncf(1.5f)); ASSERT_FLOAT_EQ(-1.0f, truncf(-1.5f)); @@ -983,6 +1017,9 @@ TEST(math, truncf) { } TEST(math, truncl) { + auto guard = make_scope_guard([]() { + fesetenv(FE_DFL_ENV); + }); fesetround(FE_UPWARD); // truncl ignores the rounding mode and always rounds toward zero. ASSERT_DOUBLE_EQ(1.0L, truncl(1.5L)); ASSERT_DOUBLE_EQ(-1.0L, truncl(-1.5L)); diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index 4a7c6bd..32bb54c 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -869,7 +869,7 @@ TEST(pthread, pthread_attr_getstack__main_thread) { #endif EXPECT_EQ(rl.rlim_cur, stack_size); - auto guard = create_scope_guard([&rl, original_rlim_cur]() { + auto guard = make_scope_guard([&rl, original_rlim_cur]() { rl.rlim_cur = original_rlim_cur; ASSERT_EQ(0, setrlimit(RLIMIT_STACK, &rl)); }); diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp index 89b8088..8fd8b72 100644 --- a/tests/signal_test.cpp +++ b/tests/signal_test.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include <gtest/gtest.h> +#include <signal.h> #include <errno.h> -#include <signal.h> +#include <gtest/gtest.h> #include "ScopedSignalHandler.h" @@ -198,13 +198,19 @@ static void EmptySignalHandler(int) {} static void EmptySignalAction(int, siginfo_t*, void*) {} TEST(signal, sigaction) { + // Both bionic and glibc set SA_RESTORER when talking to the kernel on arm, + // arm64, x86, and x86-64. The version of glibc we're using also doesn't + // define SA_RESTORER, but luckily it's the same value everywhere, and mips + // doesn't use the bit for anything. + static const unsigned sa_restorer = 0x4000000; + // See what's currently set for SIGALRM. struct sigaction original_sa; memset(&original_sa, 0, sizeof(original_sa)); ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa)); ASSERT_TRUE(original_sa.sa_handler == NULL); ASSERT_TRUE(original_sa.sa_sigaction == NULL); - ASSERT_TRUE(original_sa.sa_flags == 0); + ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer); // Set a traditional sa_handler signal handler. struct sigaction sa; @@ -219,7 +225,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_handler == EmptySignalHandler); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_TRUE(sa.sa_flags == SA_ONSTACK); + ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer); // Set a new-style sa_sigaction signal handler. memset(&sa, 0, sizeof(sa)); @@ -233,7 +239,7 @@ TEST(signal, sigaction) { ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction); ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); - ASSERT_TRUE(sa.sa_flags == (SA_ONSTACK | SA_SIGINFO)); + ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer); // Put everything back how it was. ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL)); diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp index 1024f28..3fc45c5 100644 --- a/tests/stack_unwinding_test.cpp +++ b/tests/stack_unwinding_test.cpp @@ -20,18 +20,86 @@ #include <gtest/gtest.h> -extern "C" { - void do_test(); +#include <dlfcn.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <unwind.h> + +#include "ScopedSignalHandler.h" + +#define noinline __attribute__((__noinline__)) +#define __unused __attribute__((__unused__)) + +static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) { + int* count_ptr = reinterpret_cast<int*>(arg); + +#if SHOW_FRAME_LOCATIONS + void* ip = reinterpret_cast<void*>(_Unwind_GetIP(ctx)); + + const char* symbol = "<unknown>"; + int offset = 0; + + Dl_info info; + memset(&info, 0, sizeof(info)); + if (dladdr(ip, &info) != 0) { + symbol = info.dli_sname; + if (info.dli_saddr != nullptr) { + offset = static_cast<int>(reinterpret_cast<char*>(ip) - reinterpret_cast<char*>(info.dli_saddr)); + } + } + + fprintf(stderr, " #%02d %p %s%+d (%s)\n", *count_ptr, ip, symbol, offset, info.dli_fname ? info.dli_fname : "??"); + fflush(stderr); +#endif + + ++*count_ptr; + return _URC_NO_REASON; +} + +static int noinline unwind_one_frame_deeper() { + int count = 0; + _Unwind_Backtrace(FrameCounter, &count); + return count; +} + +TEST(stack_unwinding, easy) { + int count = 0; + _Unwind_Backtrace(FrameCounter, &count); + int deeper_count = unwind_one_frame_deeper(); + ASSERT_EQ(count + 1, deeper_count); +} + +static int killer_count = 0; +static int handler_count = 0; +static int handler_one_deeper_count = 0; + +static void noinline UnwindSignalHandler(int) { + _Unwind_Backtrace(FrameCounter, &handler_count); + ASSERT_GT(handler_count, killer_count); + + handler_one_deeper_count = unwind_one_frame_deeper(); + ASSERT_EQ(handler_count + 1, handler_one_deeper_count); } -// We have to say "DeathTest" here so gtest knows to run this test (which exits) -// in its own process. -TEST(stack_unwinding_DeathTest, unwinding_through_signal_frame) { -// Only our x86 unwinding is good enough. Switch to libunwind? -#if defined(__BIONIC__) && defined(__i386__) - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_EXIT(do_test(), ::testing::ExitedWithCode(42), ""); -#else // __i386__ - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif // __i386__ +TEST(stack_unwinding, unwind_through_signal_frame) { + killer_count = handler_count = handler_one_deeper_count = 0; + ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler); + + _Unwind_Backtrace(FrameCounter, &killer_count); + + ASSERT_EQ(0, kill(getpid(), SIGUSR1)); +} + +// On LP32, the SA_SIGINFO flag gets you __restore_rt instead of __restore. +TEST(stack_unwinding, unwind_through_signal_frame_SA_SIGINFO) { + killer_count = handler_count = handler_one_deeper_count = 0; + ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler, SA_SIGINFO); + + _Unwind_Backtrace(FrameCounter, &killer_count); + + ASSERT_EQ(0, kill(getpid(), SIGUSR1)); } diff --git a/tests/stack_unwinding_test_impl.c b/tests/stack_unwinding_test_impl.c deleted file mode 100644 index 7518a2c..0000000 --- a/tests/stack_unwinding_test_impl.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -/* - * Contributed by: Intel Corporation - */ - -#include <stdio.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <unwind.h> - -#define noinline __attribute__((__noinline__)) -#define unused __attribute__((__unused__)) - -static noinline _Unwind_Reason_Code stop_fn(int a unused, - _Unwind_Action action, - _Unwind_Exception_Class b unused, struct _Unwind_Exception* c unused, - struct _Unwind_Context* d unused, void* e unused) { - if ((action & _UA_END_OF_STACK) != 0) { - // We reached the end of the stack without executing foo_cleanup. Test failed. - abort(); - } - return _URC_NO_REASON; -} - -static void noinline foo_cleanup(char* param unused) { - exit(42); -} - -static void noinline do_crash() { - char* ptr = NULL; - *ptr = 0; // Deliberately cause a SIGSEGV. -} - -static void noinline foo() { - char c1 __attribute__((cleanup(foo_cleanup))) unused; - do_crash(); -} - -// It's SEGSEGV handler. We start forced stack unwinding here. -// If libgcc don't find dso for signal frame stack unwinding will be finished. -// libgcc pass to stop_fn _UA_END_OF_STACK flag. -// Test pass condition: stack unwinding through signal frame and foo1_handler execution. -static void noinline sigsegv_handler(int param unused) { - struct _Unwind_Exception* exception = (struct _Unwind_Exception*) malloc(sizeof(*exception)); - memset(&exception->exception_class, 0, sizeof(exception->exception_class)); - exception->exception_cleanup = 0; - _Unwind_ForcedUnwind(exception, stop_fn, 0); -} - -void do_test() { - signal(SIGSEGV, &sigsegv_handler); - foo(); -} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 8c8c235..bba744a 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -29,6 +29,23 @@ #include "TemporaryFile.h" +TEST(stdio, flockfile_18208568_stderr) { + // Check that we have a _recursive_ mutex for flockfile. + flockfile(stderr); + feof(stderr); // We don't care about the result, but this needs to take the lock. + funlockfile(stderr); +} + +TEST(stdio, flockfile_18208568_regular) { + // We never had a bug for streams other than stdin/stdout/stderr, but test anyway. + FILE* fp = fopen("/dev/null", "w"); + ASSERT_TRUE(fp != NULL); + flockfile(fp); + feof(fp); + funlockfile(fp); + fclose(fp); +} + TEST(stdio, tmpfile_fileno_fprintf_rewind_fgets) { FILE* fp = tmpfile(); ASSERT_TRUE(fp != NULL); @@ -677,3 +694,34 @@ TEST(stdio, fpos_t_and_seek) { fclose(fp); } + +// https://code.google.com/p/android/issues/detail?id=81155 +// http://b/18556607 +TEST(stdio, fread_unbuffered_pathological_performance) { + FILE* fp = fopen("/dev/zero", "r"); + ASSERT_TRUE(fp != NULL); + + // Make this stream unbuffered. + setvbuf(fp, 0, _IONBF, 0); + + char buf[65*1024]; + memset(buf, 0xff, sizeof(buf)); + + time_t t0 = time(NULL); + for (size_t i = 0; i < 1024; ++i) { + fread(buf, 64*1024, 1, fp); + } + time_t t1 = time(NULL); + + fclose(fp); + + // 1024 64KiB reads should have been very quick. + ASSERT_LE(t1 - t0, 1); + + for (size_t i = 0; i < 64*1024; ++i) { + ASSERT_EQ('\0', buf[i]); + } + for (size_t i = 64*1024; i < 65*1024; ++i) { + ASSERT_EQ('\xff', buf[i]); + } +} diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 73c94c6..f1ac9dd 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -173,7 +173,7 @@ struct StringTestState { const size_t MAX_LEN; Character *ptr, *ptr1, *ptr2; size_t n; - int len[ITER + 1]; + size_t len[ITER + 1]; private: Character *glob_ptr, *glob_ptr1, *glob_ptr2; @@ -186,7 +186,7 @@ struct StringTestState { n = 0; len[n++] = 0; for (size_t i = 1; i < ITER; ++i) { - int l = (int) exp(log((double) MAX_LEN) * i / ITER); + size_t l = static_cast<size_t>(exp(log(static_cast<double>(MAX_LEN)) * i / ITER)); if (l != len[n - 1]) { len[n++] = l; } @@ -392,7 +392,7 @@ TEST(string, strchr) { } state.ptr1[state.len[i] - 1] = '\0'; - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i] - 1) { if (seek_char == 0) { @@ -421,7 +421,7 @@ TEST(string, strcmp) { state.ptr1[state.len[i] - 1] = '\0'; state.ptr2[state.len[i] - 1] = '\0'; - int pos = 1 + (random() % (state.MAX_LEN - 1)); + size_t pos = 1 + (random() % (state.MAX_LEN - 1)); int actual; int expected; if (pos >= state.len[i] - 1) { @@ -510,7 +510,7 @@ TEST(string, strlcat) { state.ptr2[state.MAX_LEN - 1] = '\0'; memcpy(state.ptr, state.ptr2, state.MAX_LEN + state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; memset(state.ptr1, '\3', pos); state.ptr1[pos] = '\0'; if (pos < state.len[i]) { @@ -604,7 +604,7 @@ TEST(string, strncmp) { state.ptr1[state.len[i] - 1] = '\0'; state.ptr2[state.len[i] - 1] = '\0'; - int pos = 1 + (random() % (state.MAX_LEN - 1)); + size_t pos = 1 + (random() % (state.MAX_LEN - 1)); int actual; int expected; if (pos >= state.len[i] - 1) { @@ -722,7 +722,7 @@ TEST(string, strrchr) { } state.ptr1[state.len[i] - 1] = '\0'; - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i] - 1) { if (seek_char == 0) { @@ -749,7 +749,7 @@ TEST(string, memchr) { memset(state.ptr1, ~seek_char, state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i]) { expected = NULL; @@ -780,7 +780,7 @@ TEST(string, memrchr) { memset(state.ptr1, ~seek_char, state.len[i]); - int pos = random() % state.MAX_LEN; + size_t pos = random() % state.MAX_LEN; char* expected; if (pos >= state.len[i]) { expected = NULL; diff --git a/tests/time_test.cpp b/tests/time_test.cpp index 241c4a0..97e371c 100644 --- a/tests/time_test.cpp +++ b/tests/time_test.cpp @@ -21,6 +21,7 @@ #include <gtest/gtest.h> #include <pthread.h> #include <signal.h> +#include <stdatomic.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> @@ -171,7 +172,7 @@ TEST(time, timer_create) { ASSERT_EQ(0, timer_delete(timer_id)); } -static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0; +static int timer_create_SIGEV_SIGNAL_signal_handler_invocation_count; static void timer_create_SIGEV_SIGNAL_signal_handler(int signal_number) { ++timer_create_SIGEV_SIGNAL_signal_handler_invocation_count; ASSERT_EQ(SIGUSR1, signal_number); @@ -186,6 +187,7 @@ TEST(time, timer_create_SIGEV_SIGNAL) { timer_t timer_id; ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id)); + timer_create_SIGEV_SIGNAL_signal_handler_invocation_count = 0; ScopedSignalHandler ssh(SIGUSR1, timer_create_SIGEV_SIGNAL_signal_handler); ASSERT_EQ(0, timer_create_SIGEV_SIGNAL_signal_handler_invocation_count); @@ -202,68 +204,94 @@ TEST(time, timer_create_SIGEV_SIGNAL) { } struct Counter { - volatile int value; + private: + atomic_int value; timer_t timer_id; sigevent_t se; + bool timer_valid; - Counter(void (*fn)(sigval_t)) : value(0) { + void Create() { + ASSERT_FALSE(timer_valid); + ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id)); + timer_valid = true; + } + + public: + Counter(void (*fn)(sigval_t)) : value(ATOMIC_VAR_INIT(0)), timer_valid(false) { memset(&se, 0, sizeof(se)); se.sigev_notify = SIGEV_THREAD; se.sigev_notify_function = fn; se.sigev_value.sival_ptr = this; + Create(); } - void Create() { - ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &timer_id)); + void DeleteTimer() { + ASSERT_TRUE(timer_valid); + ASSERT_EQ(0, timer_delete(timer_id)); + timer_valid = false; } ~Counter() { - if (timer_delete(timer_id) != 0) { - abort(); + if (timer_valid) { + DeleteTimer(); } } + int Value() { + return atomic_load(&value); + } + + void SetTime(time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) { + ::SetTime(timer_id, value_s, value_ns, interval_s, interval_ns); + } + + bool ValueUpdated() { + int current_value = atomic_load(&value); + time_t start = time(NULL); + while (current_value == atomic_load(&value) && (time(NULL) - start) < 5) { + } + return current_value != atomic_load(&value); + } + static void CountNotifyFunction(sigval_t value) { Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr); - ++cd->value; + atomic_fetch_add(&cd->value, 1); } static void CountAndDisarmNotifyFunction(sigval_t value) { Counter* cd = reinterpret_cast<Counter*>(value.sival_ptr); - ++cd->value; + atomic_fetch_add(&cd->value, 1); // Setting the initial expiration time to 0 disarms the timer. - SetTime(cd->timer_id, 0, 0, 1, 0); + cd->SetTime(0, 0, 1, 0); } }; TEST(time, timer_settime_0) { Counter counter(Counter::CountAndDisarmNotifyFunction); - counter.Create(); + ASSERT_EQ(0, counter.Value()); - ASSERT_EQ(0, counter.value); - - SetTime(counter.timer_id, 0, 1, 1, 0); + counter.SetTime(0, 1, 1, 0); usleep(500000); // The count should just be 1 because we disarmed the timer the first time it fired. - ASSERT_EQ(1, counter.value); + ASSERT_EQ(1, counter.Value()); } TEST(time, timer_settime_repeats) { Counter counter(Counter::CountNotifyFunction); - counter.Create(); - - ASSERT_EQ(0, counter.value); - - SetTime(counter.timer_id, 0, 1, 0, 10); + ASSERT_EQ(0, counter.Value()); + + counter.SetTime(0, 1, 0, 10); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + counter.DeleteTimer(); + // Add a sleep as other threads may be calling the callback function when the timer is deleted. usleep(500000); - - // The count should just be > 1 because we let the timer repeat. - ASSERT_GT(counter.value, 1); } -static int timer_create_NULL_signal_handler_invocation_count = 0; +static int timer_create_NULL_signal_handler_invocation_count; static void timer_create_NULL_signal_handler(int signal_number) { ++timer_create_NULL_signal_handler_invocation_count; ASSERT_EQ(SIGALRM, signal_number); @@ -274,6 +302,7 @@ TEST(time, timer_create_NULL) { timer_t timer_id; ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, NULL, &timer_id)); + timer_create_NULL_signal_handler_invocation_count = 0; ScopedSignalHandler ssh(SIGALRM, timer_create_NULL_signal_handler); ASSERT_EQ(0, timer_create_NULL_signal_handler_invocation_count); @@ -320,22 +349,59 @@ TEST(time, timer_delete_multiple) { TEST(time, timer_create_multiple) { Counter counter1(Counter::CountNotifyFunction); - counter1.Create(); Counter counter2(Counter::CountNotifyFunction); - counter2.Create(); Counter counter3(Counter::CountNotifyFunction); - counter3.Create(); - ASSERT_EQ(0, counter1.value); - ASSERT_EQ(0, counter2.value); - ASSERT_EQ(0, counter3.value); + ASSERT_EQ(0, counter1.Value()); + ASSERT_EQ(0, counter2.Value()); + ASSERT_EQ(0, counter3.Value()); - SetTime(counter2.timer_id, 0, 1, 0, 0); + counter2.SetTime(0, 1, 0, 0); + usleep(500000); + + EXPECT_EQ(0, counter1.Value()); + EXPECT_EQ(1, counter2.Value()); + EXPECT_EQ(0, counter3.Value()); +} + +// Test to verify that disarming a repeatable timer disables the callbacks. +TEST(time, timer_disarm_terminates) { + Counter counter(Counter::CountNotifyFunction); + ASSERT_EQ(0, counter.Value()); + + counter.SetTime(0, 1, 0, 1); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + + counter.SetTime(0, 0, 0, 0); + // Add a sleep as the kernel may have pending events when the timer is disarmed. + usleep(500000); + int value = counter.Value(); + usleep(500000); + + // Verify the counter has not been incremented. + ASSERT_EQ(value, counter.Value()); +} + +// Test to verify that deleting a repeatable timer disables the callbacks. +TEST(time, timer_delete_terminates) { + Counter counter(Counter::CountNotifyFunction); + ASSERT_EQ(0, counter.Value()); + + counter.SetTime(0, 1, 0, 1); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + ASSERT_TRUE(counter.ValueUpdated()); + + counter.DeleteTimer(); + // Add a sleep as other threads may be calling the callback function when the timer is deleted. + usleep(500000); + int value = counter.Value(); usleep(500000); - EXPECT_EQ(0, counter1.value); - EXPECT_EQ(1, counter2.value); - EXPECT_EQ(0, counter3.value); + // Verify the counter has not been incremented. + ASSERT_EQ(value, counter.Value()); } struct TimerDeleteData { @@ -365,11 +431,11 @@ TEST(time, timer_delete_from_timer_thread) { ASSERT_EQ(0, timer_create(CLOCK_REALTIME, &se, &tdd.timer_id)); itimerspec ts; - ts.it_value.tv_sec = 0; - ts.it_value.tv_nsec = 100; + ts.it_value.tv_sec = 1; + ts.it_value.tv_nsec = 0; ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 0; - ASSERT_EQ(0, timer_settime(tdd.timer_id, TIMER_ABSTIME, &ts, NULL)); + ASSERT_EQ(0, timer_settime(tdd.timer_id, 0, &ts, NULL)); time_t cur_time = time(NULL); while (!tdd.complete && (time(NULL) - cur_time) < 5); diff --git a/tests/uniqueptr_test.cpp b/tests/uniqueptr_test.cpp new file mode 100644 index 0000000..4b6608a --- /dev/null +++ b/tests/uniqueptr_test.cpp @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include <gtest/gtest.h> + +#include <private/UniquePtr.h> + +static int cCount = 0; +struct C { + C() { ++cCount; } + ~C() { --cCount; } +}; + +static bool freed = false; +struct Freer { + void operator() (int* p) { + ASSERT_EQ(123, *p); + free(p); + freed = true; + } +}; + +TEST(UniquePtr, smoke) { + // + // UniquePtr<T> tests... + // + + // Can we free a single object? + { + UniquePtr<C> c(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + C* rawC; + { + UniquePtr<C> c(new C); + ASSERT_TRUE(cCount == 1); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 1); + delete rawC; + // Does reset work? + { + UniquePtr<C> c(new C); + ASSERT_TRUE(cCount == 1); + c.reset(new C); + ASSERT_TRUE(cCount == 1); + } + ASSERT_TRUE(cCount == 0); + + // + // UniquePtr<T[]> tests... + // + + // Can we free an array? + { + UniquePtr<C[]> cs(new C[4]); + ASSERT_TRUE(cCount == 4); + } + ASSERT_TRUE(cCount == 0); + // Does release work? + { + UniquePtr<C[]> c(new C[4]); + ASSERT_TRUE(cCount == 4); + rawC = c.release(); + } + ASSERT_TRUE(cCount == 4); + delete[] rawC; + // Does reset work? + { + UniquePtr<C[]> c(new C[4]); + ASSERT_TRUE(cCount == 4); + c.reset(new C[2]); + ASSERT_TRUE(cCount == 2); + } + ASSERT_TRUE(cCount == 0); + + // + // Custom deleter tests... + // + ASSERT_TRUE(!freed); + { + UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int)))); + *i = 123; + } + ASSERT_TRUE(freed); +} |