fix union storage hacks (#670)

remove union storage hacks
This commit is contained in:
Arvid Norberg 2016-05-21 21:04:47 -04:00
parent dceee3b065
commit 584d74e2f0
6 changed files with 88 additions and 229 deletions

View File

@ -74,7 +74,6 @@ nobase_include_HEADERS = \
linked_list.hpp \
lsd.hpp \
magnet_uri.hpp \
max.hpp \
natpmp.hpp \
operations.hpp \
packet_buffer.hpp \

View File

@ -76,7 +76,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/max.hpp"
namespace libtorrent
{
@ -262,28 +261,20 @@ namespace libtorrent
void to_string_impl(std::string& out, int indent) const;
std::aligned_union<1
#if TORRENT_COMPLETE_TYPES_REQUIRED
// workaround for msvc-bug.
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
// and sizeof(list<char>) == sizeof(list<entry>)
enum { union_size
= max5<sizeof(std::list<char>)
, sizeof(std::map<std::string, char>)
, sizeof(string_type)
, sizeof(integer_type)
, sizeof(preformatted_type)>::value
};
// for implementations that require complete types, use char and hope
// for the best
, std::list<char>
, std::map<std::string, char>
#else
enum { union_size
= max5<sizeof(list_type)
, sizeof(dictionary_type)
, sizeof(string_type)
, sizeof(integer_type)
, sizeof(preformatted_type)>::value
};
, list_type
, dictionary_type
#endif
integer_type data[(union_size + sizeof(integer_type) - 1)
/ sizeof(integer_type)];
, preformatted_type
, string_type
, integer_type
>::type data;
// the bitfield is used so that the m_type_queried field still fits, so
// that the ABI is the same for debug builds and release builds. It

View File

@ -1,126 +0,0 @@
/*
Copyright (c) 2009-2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_MAX_TYPE
#define TORRENT_MAX_TYPE
namespace libtorrent
{
template<int v1, int v2>
struct min { enum { value = v1<v2?v1:v2 }; };
template<int v1, int v2>
struct max { enum { value = v1>v2?v1:v2 }; };
template<int v1, int v2, int v3>
struct max3
{
enum
{
temp = max<v1,v2>::value,
value = max<temp, v3>::value
};
};
template<int v1, int v2, int v3, int v4>
struct max4
{
enum
{
temp1 = max<v1,v2>::value,
temp2 = max<v3,v4>::value,
value = max<temp1, temp2>::value
};
};
template<int v1, int v2, int v3, int v4, int v5>
struct max5
{
enum
{
temp = max4<v1,v2, v3, v4>::value,
value = max<temp, v5>::value
};
};
template<int v1, int v2, int v3, int v4, int v5, int v6>
struct max6
{
enum
{
temp1 = max<v1,v2>::value,
temp2 = max<v3,v4>::value,
temp3 = max<v5,v6>::value,
value = max3<temp1, temp2, temp3>::value
};
};
template<int v1, int v2, int v3, int v4, int v5, int v6, int v7>
struct max7
{
enum
{
temp1 = max<v1,v2>::value,
temp2 = max<v3,v4>::value,
temp3 = max3<v5,v6,v7>::value,
value = max3<temp1, temp2, temp3>::value
};
};
template<int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8>
struct max8
{
enum
{
temp1 = max<v1,v2>::value,
temp2 = max3<v3,v4,v5>::value,
temp3 = max3<v6,v7,v8>::value,
value = max3<temp1, temp2, temp3>::value
};
};
template<int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9>
struct max9
{
enum
{
temp1 = max3<v1,v2, v3>::value,
temp2 = max3<v4,v5,v6>::value,
temp3 = max3<v7,v8,v9>::value,
value = max3<temp1, temp2, temp3>::value
};
};
}
#endif

View File

@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_SOCKET_TYPE
#define TORRENT_SOCKET_TYPE
#include <type_traits> // for aligned_union
#include "libtorrent/config.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/socks5_stream.hpp"
@ -40,7 +42,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/i2p_stream.hpp"
#include "libtorrent/utp_stream.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/max.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp"
@ -276,7 +277,7 @@ namespace libtorrent
{ TORRENT_SOCKTYPE_FORWARD_RET(get_option(opt, ec), ec) }
template <class S>
void instantiate(io_service& ios, void* userdata = 0)
void instantiate(io_service& ios, void* userdata = nullptr)
{
TORRENT_UNUSED(ios);
TORRENT_ASSERT(&ios == &m_io_service);
@ -285,13 +286,13 @@ namespace libtorrent
template <class S> S* get()
{
if (m_type != socket_type_int_impl<S>::value) return 0;
if (m_type != socket_type_int_impl<S>::value) return nullptr;
return reinterpret_cast<S*>(&m_data);
}
template <class S> S const* get() const
{
if (m_type != socket_type_int_impl<S>::value) return 0;
if (m_type != socket_type_int_impl<S>::value) return nullptr;
return reinterpret_cast<S const*>(&m_data);
}
@ -304,28 +305,22 @@ namespace libtorrent
io_service& m_io_service;
int m_type;
enum { storage_size = max9<
sizeof(tcp::socket)
, sizeof(socks5_stream)
, sizeof(http_stream)
, sizeof(utp_stream)
std::aligned_union<1
, tcp::socket
, socks5_stream
, http_stream
, utp_stream
#if TORRENT_USE_I2P
, sizeof(i2p_stream)
#else
, 0
, i2p_stream
#endif
#ifdef TORRENT_USE_OPENSSL
, sizeof(ssl_stream<tcp::socket>)
, sizeof(ssl_stream<socks5_stream>)
, sizeof(ssl_stream<http_stream>)
, sizeof(ssl_stream<utp_stream>)
#else
, 0, 0, 0, 0
, ssl_stream<tcp::socket>
, ssl_stream<socks5_stream>
, ssl_stream<http_stream>
, ssl_stream<utp_stream>
#endif
>::value
};
boost::aligned_storage<storage_size, 8>::type m_data;
>::type m_data;
};
// returns true if this socket is an SSL socket

View File

@ -190,7 +190,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == int_t);
return *reinterpret_cast<integer_type*>(data);
return *reinterpret_cast<integer_type*>(&data);
}
entry::integer_type const& entry::integer() const
@ -201,7 +201,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == int_t);
return *reinterpret_cast<const integer_type*>(data);
return *reinterpret_cast<const integer_type*>(&data);
}
entry::string_type& entry::string()
@ -213,7 +213,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == string_t);
return *reinterpret_cast<string_type*>(data);
return *reinterpret_cast<string_type*>(&data);
}
entry::string_type const& entry::string() const
@ -224,7 +224,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == string_t);
return *reinterpret_cast<const string_type*>(data);
return *reinterpret_cast<const string_type*>(&data);
}
entry::list_type& entry::list()
@ -236,7 +236,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == list_t);
return *reinterpret_cast<list_type*>(data);
return *reinterpret_cast<list_type*>(&data);
}
entry::list_type const& entry::list() const
@ -247,7 +247,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == list_t);
return *reinterpret_cast<const list_type*>(data);
return *reinterpret_cast<const list_type*>(&data);
}
entry::dictionary_type& entry::dict()
@ -259,7 +259,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == dictionary_t);
return *reinterpret_cast<dictionary_type*>(data);
return *reinterpret_cast<dictionary_type*>(&data);
}
entry::dictionary_type const& entry::dict() const
@ -270,7 +270,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == dictionary_t);
return *reinterpret_cast<const dictionary_type*>(data);
return *reinterpret_cast<const dictionary_type*>(&data);
}
entry::preformatted_type& entry::preformatted()
@ -282,7 +282,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == preformatted_t);
return *reinterpret_cast<preformatted_type*>(data);
return *reinterpret_cast<preformatted_type*>(&data);
}
entry::preformatted_type const& entry::preformatted() const
@ -293,7 +293,7 @@ namespace libtorrent
TORRENT_ASSERT(m_type_queried);
#endif
TORRENT_ASSERT(m_type == preformatted_t);
return *reinterpret_cast<const preformatted_type*>(data);
return *reinterpret_cast<const preformatted_type*>(&data);
}
entry::entry()
@ -340,7 +340,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG
m_type_queried = true;
#endif
new(data) dictionary_type(v);
new(&data) dictionary_type(v);
m_type = dictionary_t;
}
@ -350,7 +350,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG
m_type_queried = true;
#endif
new(data) string_type(v);
new(&data) string_type(v);
m_type = string_t;
}
@ -360,7 +360,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG
m_type_queried = true;
#endif
new(data) list_type(v);
new(&data) list_type(v);
m_type = list_t;
}
@ -370,7 +370,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG
m_type_queried = true;
#endif
new(data) integer_type(v);
new(&data) integer_type(v);
m_type = int_t;
}
@ -380,7 +380,7 @@ namespace libtorrent
#ifdef TORRENT_DEBUG
m_type_queried = true;
#endif
new(data) preformatted_type(v);
new(&data) preformatted_type(v);
m_type = preformatted_t;
}
@ -465,7 +465,7 @@ namespace libtorrent
entry& entry::operator=(preformatted_type const& v)
{
destruct();
new(data) preformatted_type(v);
new(&data) preformatted_type(v);
m_type = preformatted_t;
#ifdef TORRENT_DEBUG
m_type_queried = true;
@ -476,7 +476,7 @@ namespace libtorrent
entry& entry::operator=(dictionary_type const& v)
{
destruct();
new(data) dictionary_type(v);
new(&data) dictionary_type(v);
m_type = dictionary_t;
#ifdef TORRENT_DEBUG
m_type_queried = true;
@ -487,7 +487,7 @@ namespace libtorrent
entry& entry::operator=(string_type const& v)
{
destruct();
new(data) string_type(v);
new(&data) string_type(v);
m_type = string_t;
#ifdef TORRENT_DEBUG
m_type_queried = true;
@ -498,7 +498,7 @@ namespace libtorrent
entry& entry::operator=(list_type const& v)
{
destruct();
new(data) list_type(v);
new(&data) list_type(v);
m_type = list_t;
#ifdef TORRENT_DEBUG
m_type_queried = true;
@ -509,7 +509,7 @@ namespace libtorrent
entry& entry::operator=(integer_type const& v)
{
destruct();
new(data) integer_type(v);
new(&data) integer_type(v);
m_type = int_t;
#ifdef TORRENT_DEBUG
m_type_queried = true;
@ -544,21 +544,21 @@ namespace libtorrent
switch (t)
{
case int_t:
new(data) integer_type;
new (&data) integer_type;
break;
case string_t:
new(data) string_type;
new (&data) string_type;
break;
case list_t:
new(data) list_type;
new (&data) list_type;
break;
case dictionary_t:
new (data) dictionary_type;
new (&data) dictionary_type;
break;
case undefined_t:
break;
case preformatted_t:
new (data) preformatted_type;
new (&data) preformatted_type;
break;
}
m_type = t;
@ -572,22 +572,22 @@ namespace libtorrent
switch (e.type())
{
case int_t:
new(data) integer_type(e.integer());
new (&data) integer_type(e.integer());
break;
case string_t:
new(data) string_type(e.string());
new (&data) string_type(e.string());
break;
case list_t:
new(data) list_type(e.list());
new (&data) list_type(e.list());
break;
case dictionary_t:
new (data) dictionary_type(e.dict());
new (&data) dictionary_type(e.dict());
break;
case undefined_t:
TORRENT_ASSERT(e.type() == undefined_t);
break;
case preformatted_t:
new (data) preformatted_type(e.preformatted());
new (&data) preformatted_type(e.preformatted());
break;
}
m_type = e.type();
@ -601,19 +601,19 @@ namespace libtorrent
switch(m_type)
{
case int_t:
call_destructor(reinterpret_cast<integer_type*>(data));
call_destructor(reinterpret_cast<integer_type*>(&data));
break;
case string_t:
call_destructor(reinterpret_cast<string_type*>(data));
call_destructor(reinterpret_cast<string_type*>(&data));
break;
case list_t:
call_destructor(reinterpret_cast<list_type*>(data));
call_destructor(reinterpret_cast<list_type*>(&data));
break;
case dictionary_t:
call_destructor(reinterpret_cast<dictionary_type*>(data));
call_destructor(reinterpret_cast<dictionary_type*>(&data));
break;
case preformatted_t:
call_destructor(reinterpret_cast<preformatted_type*>(data));
call_destructor(reinterpret_cast<preformatted_type*>(&data));
break;
default:
TORRENT_ASSERT(m_type == undefined_t);
@ -650,24 +650,24 @@ namespace libtorrent
switch (m_type)
{
case int_t:
std::swap(*reinterpret_cast<integer_type*>(data)
, *reinterpret_cast<integer_type*>(e.data));
std::swap(*reinterpret_cast<integer_type*>(&data)
, *reinterpret_cast<integer_type*>(&e.data));
break;
case string_t:
std::swap(*reinterpret_cast<string_type*>(data)
, *reinterpret_cast<string_type*>(e.data));
std::swap(*reinterpret_cast<string_type*>(&data)
, *reinterpret_cast<string_type*>(&e.data));
break;
case list_t:
std::swap(*reinterpret_cast<list_type*>(data)
, *reinterpret_cast<list_type*>(e.data));
std::swap(*reinterpret_cast<list_type*>(&data)
, *reinterpret_cast<list_type*>(&e.data));
break;
case dictionary_t:
std::swap(*reinterpret_cast<dictionary_type*>(data)
, *reinterpret_cast<dictionary_type*>(e.data));
std::swap(*reinterpret_cast<dictionary_type*>(&data)
, *reinterpret_cast<dictionary_type*>(&e.data));
break;
case preformatted_t:
std::swap(*reinterpret_cast<preformatted_type*>(data)
, *reinterpret_cast<preformatted_type*>(e.data));
std::swap(*reinterpret_cast<preformatted_type*>(&data)
, *reinterpret_cast<preformatted_type*>(&e.data));
break;
default:
break;

View File

@ -60,6 +60,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/time.hpp>
#include <libtorrent/aux_/time.hpp> // for aux::time_now
#include <type_traits>
#ifndef TORRENT_DISABLE_LOGGING
#include <cinttypes> // for PRId64 et.al.
#endif
@ -162,24 +164,22 @@ void observer::set_id(node_id const& id)
if (m_algorithm) m_algorithm->resort_results();
}
enum { observer_size = max9<
sizeof(find_data_observer)
, sizeof(announce_observer)
, sizeof(put_data_observer)
, sizeof(direct_observer)
, sizeof(get_item_observer)
, sizeof(get_peers_observer)
, sizeof(obfuscated_get_peers_observer)
, sizeof(null_observer)
, sizeof(traversal_observer)
>::value
};
using observer_storage = std::aligned_union<1
, find_data_observer
, announce_observer
, put_data_observer
, direct_observer
, get_item_observer
, get_peers_observer
, obfuscated_get_peers_observer
, null_observer
, traversal_observer>::type;
rpc_manager::rpc_manager(node_id const& our_id
, dht_settings const& settings
, routing_table& table, udp_socket_interface* sock
, dht_logger* log)
: m_pool_allocator(observer_size, 10)
: m_pool_allocator(sizeof(observer_storage), 10)
, m_sock(sock)
, m_log(log)
, m_settings(settings)
@ -194,7 +194,7 @@ rpc_manager::~rpc_manager()
{
TORRENT_ASSERT(!m_destructing);
m_destructing = true;
for (transactions_t::iterator i = m_transactions.begin()
, end(m_transactions.end()); i != end; ++i)
{
@ -221,7 +221,7 @@ void rpc_manager::free_observer(void* ptr)
#if TORRENT_USE_ASSERTS
size_t rpc_manager::allocation_size() const
{
return observer_size;
return sizeof(observer_storage);
}
#endif
#if TORRENT_USE_INVARIANT_CHECKS