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 != nullptr); 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 != nullptr); ASSERT_TRUE(foo_library_ptr != nullptr); 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 != nullptr); foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo")); foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library")); ASSERT_TRUE(foo_ptr != nullptr); ASSERT_TRUE(foo_library_ptr != nullptr); ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0); ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0); dlclose(handle); }
int main() { std::vector<FooPtr> foo_vector; std::set<FooPtr,FooPtrOps> foo_set; // NOT multiset! FooPtr foo_ptr( new Foo( 2 ) ); foo_vector.push_back( foo_ptr ); foo_set.insert( foo_ptr ); foo_ptr.reset( new Foo( 1 ) ); foo_vector.push_back( foo_ptr ); foo_set.insert( foo_ptr ); foo_ptr.reset( new Foo( 3 ) ); foo_vector.push_back( foo_ptr ); foo_set.insert( foo_ptr ); foo_ptr.reset ( new Foo( 2 ) ); foo_vector.push_back( foo_ptr ); foo_set.insert( foo_ptr ); std::cout << "foo_vector:\n"; std::for_each( foo_vector.begin(), foo_vector.end(), FooPtrOps() ); std::cout << "\nfoo_set:\n"; std::for_each( foo_set.begin(), foo_set.end(), FooPtrOps() ); std::cout << "\n"; // Expected output: // // foo_vector: // 2 // 1 // 3 // 2 // // foo_set: // 3 // 2 // 1 // // Destructing a Foo with x=2 // Destructing a Foo with x=1 // Destructing a Foo with x=3 // Destructing a Foo with x=2 return 0; }