1 // Copyright 2016 Klemens Morgenstern, Antony Polukhin
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 // For more information, see http://www.boost.org
8 
9 #ifndef BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
10 #define BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
11 
12 #include <boost/dll/config.hpp>
13 #ifdef BOOST_HAS_PRAGMA_ONCE
14 # pragma once
15 #endif
16 
17 #include <boost/dll/detail/aggressive_ptr_cast.hpp>
18 #include <boost/dll/detail/get_mem_fn_type.hpp>
19 
20 #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
21 #   include <boost/dll/detail/demangling/msvc.hpp>
22 #else
23 #   include <boost/dll/detail/demangling/itanium.hpp>
24 #endif
25 
26 
27 namespace boost { namespace dll { namespace detail {
28 
29 /*!
30  * This class stores a constructor.
31  *
32  * In some compilers there are several constructors in code, which may include an allocating one.
33  * This can be used if the imported class shall be put on the heap, which is why the class provied both types.
34  */
35 template<typename Signature>
36 struct constructor;
37 
38 template<typename Class, typename ...Args>
39 struct constructor<Class(Args...)> {
40     typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t;
41     typedef Class*(*allocating_t)(Args...);
42 
43 
44     //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead.
45     standard_t standard;
46     //! The allocating constructor.  @warning May differ with the compiler. Use @ref constructor::call_allocating instead.
47     allocating_t allocating;
48 
49     //! Call the standard constructor
call_standardboost::dll::detail::constructor50     void call_standard  (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); }
51 
52     //! Call the deleting destructor
call_allocatingboost::dll::detail::constructor53     Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); }
54 
55 
56     //! True if a allocating constructor could be loaded.
has_allocatingboost::dll::detail::constructor57     bool has_allocating() const { return allocating != nullptr; }
58 
59     //! True if a standard constructor could be loaded.
has_standardboost::dll::detail::constructor60     bool has_standard() const { return standard != nullptr; }
61 
62     //! False if neither the allocating nor the standard constructor is available.
is_emptyboost::dll::detail::constructor63     bool is_empty() const { return (allocating == nullptr) && (standard == nullptr) ; }
64 
65     constructor() = delete;
66     constructor(const constructor &) = default;
67 
constructorboost::dll::detail::constructor68     explicit constructor(standard_t standard, allocating_t allocating = nullptr)
69         : standard(standard)
70         , allocating(allocating)
71     {}
72 };
73 
74 
75 
76 template <typename Class>
77 struct destructor {
78 #if !defined(_WIN32)
79     typedef void(*type)(Class* const);
80 #elif !defined(_WIN64)
81     typedef void(__thiscall * type)(Class* const);
82 #else
83     typedef void(__cdecl * type)(Class* const);
84 #endif
85 
86     typedef type standard_t;
87     typedef type deleting_t;
88 
89     //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead.
90     standard_t standard;
91     //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead.
92     deleting_t deleting;
93 
94     //! Call the standard constructor
call_standardboost::dll::detail::destructor95     void call_standard(Class * const ptr){ standard(ptr); }
96 
97     //! Call the deleting destructor
call_deletingboost::dll::detail::destructor98     void call_deleting(Class * const ptr){ deleting(ptr); }
99 
100     //! True if a deleting destructor could be loaded.
has_deletingboost::dll::detail::destructor101     bool has_deleting() const { return deleting != nullptr; }
102 
103     //! True if a standard destructor could be loaded.
has_standardboost::dll::detail::destructor104     bool has_standard() const { return standard != nullptr; }
105 
106     //! False if neither the deleting nor the standard destructor is available.
is_emptyboost::dll::detail::destructor107     bool is_empty() const { return (deleting == nullptr) && (standard == nullptr) ; }
108     destructor() = delete;
109 
110     //! Copy destructor.
111     destructor(const destructor &) = default;
112 
113     //! Construct it from both the standard destructor and the allocating destructor
destructorboost::dll::detail::destructor114     explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr)
115         : standard(standard)
116         , deleting(deleting)
117     {}
118 };
119 
120 #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
121 template<typename Signature, typename Lib>
load_ctor(Lib & lib,const mangled_storage_impl::ctor_sym & ct)122 constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
123     typedef typename constructor<Signature>::standard_t standard_t;
124     standard_t ctor = lib.template get<standard_t>(ct);
125     return constructor<Signature>(ctor);
126 }
127 
128 template<typename Class, typename Lib>
load_dtor(Lib & lib,const mangled_storage_impl::dtor_sym & dt)129 destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
130     typedef typename destructor<Class>::standard_t standard_t;
131     //@apolukhin That does NOT work this way with MSVC-14 x32 via memcpy. The x64 is different.
132     //standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt);
133     void * buf = &lib.template get<unsigned char>(dt);
134     standard_t dtor;
135     std::memcpy(&dtor, &buf, sizeof(dtor));
136     return destructor<Class>(dtor);
137 }
138 
139 #else
140 
141 template<typename Signature, typename Lib>
load_ctor(Lib & lib,const mangled_storage_impl::ctor_sym & ct)142 constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
143     typedef typename constructor<Signature>::standard_t   stand;
144     typedef typename constructor<Signature>::allocating_t alloc;
145 
146     stand s = nullptr;
147     alloc a = nullptr;
148 
149     //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor
150 
151     if (!ct.C1.empty())
152     {
153         //the only way this works on mingw/win.
154         //For some reason there is always an 0xA in the following poniter, which screws with the this pointer.
155         void *buf = &lib.template get<unsigned char>(ct.C1);
156         std::memcpy(&s, &buf, sizeof(void*));
157     }
158     if (!ct.C3.empty())
159     {
160         void *buf = &lib.template get<unsigned char>(ct.C3);
161         std::memcpy(&a, &buf, sizeof(void*));
162     }
163 
164     return constructor<Signature>(s,a);
165 }
166 
167 template<typename Class, typename Lib>
load_dtor(Lib & lib,const mangled_storage_impl::dtor_sym & dt)168 destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
169     typedef typename destructor<Class>::standard_t stand;
170     typedef typename destructor<Class>::deleting_t delet;
171 
172     stand s = nullptr;
173     delet d = nullptr;
174 
175     //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor
176     if (!dt.D1.empty()) {
177         s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1);
178     }
179 
180     if (!dt.D0.empty()) {
181         d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0);
182     }
183 
184     return destructor<Class>(s,d);
185 
186 }
187 
188 #endif
189 
190 }}} // namespace boost::dll::detail
191 
192 #endif /* BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */
193