From a132cd5434c657aa3ce2f5fe3605b2e6b87f5e46 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 25 Aug 2014 19:41:47 +0400 Subject: [PATCH] More mature solution for #4 --- example/getting_started_library.cpp | 2 +- example/tutorial5/load_all.cpp | 1 + include/boost/plugin/alias.hpp | 14 +++-- .../plugin/detail/aggressive_ptr_cast.hpp | 55 +++++++++++++++++++ .../plugin/detail/posix/library_info.hpp | 1 + .../detail/windows/shared_library_impl.hpp | 3 +- include/boost/plugin/shared_library.hpp | 18 +++++- test/test_library.cpp | 6 +- 8 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 include/boost/plugin/detail/aggressive_ptr_cast.hpp diff --git a/example/getting_started_library.cpp b/example/getting_started_library.cpp index 64f80a7..d70fd27 100644 --- a/example/getting_started_library.cpp +++ b/example/getting_started_library.cpp @@ -49,6 +49,6 @@ int c_variable_name = 1; namespace my_namespace { std::string cpp_function_name(const std::string& param) { return param + " Hello from lib!"; - }; + } } diff --git a/example/tutorial5/load_all.cpp b/example/tutorial5/load_all.cpp index 9523d2a..94baade 100644 --- a/example/tutorial5/load_all.cpp +++ b/example/tutorial5/load_all.cpp @@ -114,6 +114,7 @@ std::size_t plugins_collector::count() const { //[plugcpp_load_all int main(int argc, char* argv[]) { + BOOST_ASSERT(argc == 2); plugins_collector plugins(argv[1]); std::cout << "\n\nUnique plugins " << plugins.count() << ":\n"; diff --git a/include/boost/plugin/alias.hpp b/include/boost/plugin/alias.hpp index 7461b2b..1d4521f 100644 --- a/include/boost/plugin/alias.hpp +++ b/include/boost/plugin/alias.hpp @@ -18,6 +18,7 @@ #include #include +#include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -68,12 +69,15 @@ namespace boost { namespace plugin { * BOOST_PLUGIN_ALIAS(foo::bar, foo_bar_another_alias_name) * \endcode */ -#define BOOST_PLUGIN_ALIAS(FunctionOrVar, AliasName) \ - extern "C" BOOST_SYMBOL_EXPORT const void *AliasName; \ - BOOST_PLUGIN_SECTION("boost_aliases") BOOST_PLUGIN_SELECTANY \ - const void *AliasName = reinterpret_cast(&FunctionOrVar); \ - /**/ +// Note: we can not use `aggressive_ptr_cast` here, because in that case GCC applies +// different permissions to the section and it causes Segmentation fault. +#define BOOST_PLUGIN_ALIAS(FunctionOrVar, AliasName) \ + extern "C" BOOST_PLUGIN_SECTION("boost_aliases") BOOST_PLUGIN_SELECTANY BOOST_SYMBOL_EXPORT \ + const void * const AliasName = reinterpret_cast(reinterpret_cast( \ + &FunctionOrVar \ + )); \ + /**/ /*! diff --git a/include/boost/plugin/detail/aggressive_ptr_cast.hpp b/include/boost/plugin/detail/aggressive_ptr_cast.hpp new file mode 100644 index 0000000..0f6d78d --- /dev/null +++ b/include/boost/plugin/detail/aggressive_ptr_cast.hpp @@ -0,0 +1,55 @@ +// system_error.hpp ----------------------------------------------------------// +// ----------------------------------------------------------------------------- + +// Copyright 2014 Renato Tegon Forti, Antony Polukhin. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/application for documentation. + +// ----------------------------------------------------------------------------- + +// Revision History +// 25-08-2013 dd-mm-yyyy - Initial Release + +// ----------------------------------------------------------------------------- + +#ifndef BOOST_PLUGIN_DETAIL_AGGRESSIVE_PTR_CAST_HPP +#define BOOST_PLUGIN_DETAIL_AGGRESSIVE_PTR_CAST_HPP + +#include +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include // cstdint is not good because it does not define std::uintptr_t + +namespace boost { namespace plugin { namespace detail { + +// GCC warns when reinterpret_cast between function pointer and object pointer occur. +// This method supress the warnings and ensures that such casts are safe. +template +BOOST_FORCEINLINE To aggressive_ptr_cast(From* v) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG( + boost::is_pointer::value, + "`agressive_ptr_cast` function must be used only for pointer casting." + ); + + BOOST_STATIC_ASSERT_MSG( + sizeof(v) == sizeof(To), + "Pointer to function and pointer to object differ in size on your platform." + ); + + return reinterpret_cast( + reinterpret_cast(v) + ); +} + +}}} // boost::plugin::detail + +#endif // BOOST_PLUGIN_DETAIL_AGGRESSIVE_PTR_CAST_HPP + diff --git a/include/boost/plugin/detail/posix/library_info.hpp b/include/boost/plugin/detail/posix/library_info.hpp index 68f885f..570e3b3 100644 --- a/include/boost/plugin/detail/posix/library_info.hpp +++ b/include/boost/plugin/detail/posix/library_info.hpp @@ -48,6 +48,7 @@ public: const char* name_begin = &names[0]; const char* const name_end = name_begin + names.size(); + ret.reserve(header().e_shnum); do { ret.push_back(name_begin); name_begin += ret.back().size() + 1; diff --git a/include/boost/plugin/detail/windows/shared_library_impl.hpp b/include/boost/plugin/detail/windows/shared_library_impl.hpp index 553ea0e..72c7939 100644 --- a/include/boost/plugin/detail/windows/shared_library_impl.hpp +++ b/include/boost/plugin/detail/windows/shared_library_impl.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -182,7 +183,7 @@ public: // at GetProcAddress there is no version for UNICODE. // There can be it and is correct, as in executed // units names of functions are stored in narrow characters. - void* const symbol = reinterpret_cast( + void* const symbol = boost::plugin::detail::aggressive_ptr_cast( boost::detail::winapi::GetProcAddress(handle_, sb.data()) ); if (symbol == NULL) { diff --git a/include/boost/plugin/shared_library.hpp b/include/boost/plugin/shared_library.hpp index b0e04e9..96165cb 100644 --- a/include/boost/plugin/shared_library.hpp +++ b/include/boost/plugin/shared_library.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #if BOOST_OS_WINDOWS # include @@ -351,7 +352,16 @@ public: * */ template - T& get(const boost::string_ref &sb) const { + inline T& get(const boost::string_ref &sb) const { + return *boost::plugin::detail::aggressive_ptr_cast( + get_impl(sb) + ); + } + +private: + // get_impl is required to reduce binary size: it does not depend on a template + // parameter and will be instantiated only once. + void* get_impl(const boost::string_ref &sb) const { boost::system::error_code ec; if (!is_loaded()) { @@ -368,14 +378,16 @@ public: ); } - void* ret = base_t::symbol_addr(sb, ec); + void* const ret = base_t::symbol_addr(sb, ec); if (ec || !ret) { boost::plugin::detail::report_error(ec, "get() failed"); } - return *reinterpret_cast(ret); + return ret; } +public: + /*! * Returns the native handler of the loaded library. * diff --git a/test/test_library.cpp b/test/test_library.cpp index 1a65782..2a3166b 100644 --- a/test/test_library.cpp +++ b/test/test_library.cpp @@ -59,9 +59,9 @@ namespace namespace1 { namespace namespace2 { namespace namespace3 { BOOST_PLUGIN_ALIAS(foo::bar, foo_bar) BOOST_PLUGIN_ALIAS(foo::variable, foo_variable) -BOOST_PLUGIN_ALIAS(namespace1::namespace2::namespace3::do_share, do_share); -BOOST_PLUGIN_ALIAS(namespace1::namespace2::namespace3::info, info); -BOOST_PLUGIN_ALIAS(const_integer_g, const_integer_g_alias); +BOOST_PLUGIN_ALIAS(namespace1::namespace2::namespace3::do_share, do_share) +BOOST_PLUGIN_ALIAS(namespace1::namespace2::namespace3::info, info) +BOOST_PLUGIN_ALIAS(const_integer_g, const_integer_g_alias) int integer_g = 100;