/* * 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 #include #include #include #define ASSERT_DL_NOTNULL(ptr) \ ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() #define ASSERT_DL_ZERO(i) \ ASSERT_EQ(0, i) << "dlerror: " << dlerror() typedef int (*fn)(void); #define LIBNAME "libdlext_test.so" #define LIBSIZE 1024*1024 // how much address space to reserve for it class DlExtTest : public ::testing::Test { protected: virtual void SetUp() { handle_ = NULL; // verify that we don't have the library loaded already ASSERT_EQ(NULL, dlsym(RTLD_DEFAULT, "getRandomNumber")); // call dlerror() to swallow the error, and check it was the one we wanted ASSERT_STREQ("undefined symbol: getRandomNumber", dlerror()); } virtual void TearDown() { if (handle_ != NULL) { ASSERT_DL_ZERO(dlclose(handle_)); } } void* handle_; }; TEST_F(DlExtTest, ExtInfoNull) { handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, NULL); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); EXPECT_EQ(4, f()); } TEST_F(DlExtTest, ExtInfoNoFlags) { android_dlextinfo extinfo; extinfo.flags = 0; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); EXPECT_EQ(4, f()); } TEST_F(DlExtTest, Reserved) { void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; extinfo.reserved_addr = start; extinfo.reserved_size = LIBSIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); EXPECT_GE(f, start); EXPECT_LT(reinterpret_cast(f), reinterpret_cast(start) + LIBSIZE); EXPECT_EQ(4, f()); } TEST_F(DlExtTest, ReservedTooSmall) { void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS; extinfo.reserved_addr = start; extinfo.reserved_size = PAGE_SIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); EXPECT_EQ(NULL, handle_); } TEST_F(DlExtTest, ReservedHint) { void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; extinfo.reserved_addr = start; extinfo.reserved_size = LIBSIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); EXPECT_GE(f, start); EXPECT_LT(reinterpret_cast(f), reinterpret_cast(start) + LIBSIZE); EXPECT_EQ(4, f()); } TEST_F(DlExtTest, ReservedHintTooSmall) { void* start = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ASSERT_TRUE(start != MAP_FAILED); android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT; extinfo.reserved_addr = start; extinfo.reserved_size = PAGE_SIZE; handle_ = android_dlopen_ext(LIBNAME, RTLD_NOW, &extinfo); ASSERT_DL_NOTNULL(handle_); fn f = reinterpret_cast(dlsym(handle_, "getRandomNumber")); ASSERT_DL_NOTNULL(f); EXPECT_TRUE(f < start || (reinterpret_cast(f) >= reinterpret_cast(start) + PAGE_SIZE)); EXPECT_EQ(4, f()); }