diff --git a/include/libtorrent/aux_/alloca.hpp b/include/libtorrent/aux_/alloca.hpp index 910b8ac1b..a789e6a8f 100644 --- a/include/libtorrent/aux_/alloca.hpp +++ b/include/libtorrent/aux_/alloca.hpp @@ -35,6 +35,43 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/aux_/typed_span.hpp" #include "libtorrent/aux_/numeric_cast.hpp" +#include // for iterator_traits +#include // for addressof + +namespace libtorrent { namespace aux { + +template +inline void uninitialized_default_construct(ForwardIt first, ForwardIt last) +{ + using Value = typename std::iterator_traits::value_type; + ForwardIt current = first; + try { + for (; current != last; ++current) { + ::new (static_cast(std::addressof(*current))) Value; + } + } catch (...) { + for (; first != current; ++first) { + first->~Value(); + } + throw; + } +} + +template +struct alloca_destructor +{ + span objects; + ~alloca_destructor() + { + for (auto& o : objects) + { + TORRENT_UNUSED(o); + o.~T(); + } + } +}; + +}} #if defined TORRENT_WINDOWS || defined TORRENT_MINGW @@ -42,7 +79,10 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span v; { \ std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast(n); \ t* TORRENT_ALLOCA_tmp = static_cast(_alloca(sizeof(t) * TORRENT_ALLOCA_size)); \ - v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); } + v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \ + ::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \ + } \ + ::libtorrent::aux::alloca_destructor v##_destructor{v}; #elif defined TORRENT_BSD @@ -50,7 +90,10 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span v; { \ std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast(n); \ t* TORRENT_ALLOCA_tmp = static_cast(alloca(sizeof(t) * TORRENT_ALLOCA_size)); \ - v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); } + v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \ + ::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \ + } \ + ::libtorrent::aux::alloca_destructor v##_destructor{v}; #else @@ -58,7 +101,10 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span v; { \ std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast(n); \ t* TORRENT_ALLOCA_tmp = static_cast(alloca(sizeof(t) * TORRENT_ALLOCA_size)); \ - v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); } + v = ::libtorrent::aux::typed_span(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \ + ::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \ + } \ + ::libtorrent::aux::alloca_destructor v##_destructor{v}; #endif diff --git a/src/bdecode.cpp b/src/bdecode.cpp index cd3e39f78..d7ed7ee8a 100644 --- a/src/bdecode.cpp +++ b/src/bdecode.cpp @@ -102,6 +102,7 @@ namespace { struct stack_frame { + stack_frame() : token(0), state(0) {} explicit stack_frame(int const t): token(std::uint32_t(t)), state(0) {} // this is an index into m_tokens std::uint32_t token:31; diff --git a/test/Jamfile b/test/Jamfile index d7cc94c3b..1998bb704 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -143,7 +143,8 @@ test-suite libtorrent : test_linked_list.cpp test_stack_allocator.cpp test_listen_socket.cpp - test_file_progress.cpp ] + test_file_progress.cpp + test_alloca.cpp ] [ run test_piece_picker.cpp ] diff --git a/test/Makefile.am b/test/Makefile.am index 4863e5c34..b0ff25cd1 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -48,7 +48,8 @@ test_programs = \ test_direct_dht \ test_ffs \ test_session_params \ - test_span + test_span \ + test_alloca if ENABLE_TESTS check_PROGRAMS = $(test_programs) @@ -243,6 +244,7 @@ test_direct_dht_SOURCES = test_direct_dht.cpp test_ffs_SOURCES = test_ffs.cpp test_session_params_SOURCES = test_session_params.cpp test_span_SOURCES = test_span.cpp +test_alloca_SOURCES = test_alloca.cpp LDADD = libtest.la $(top_builddir)/src/libtorrent-rasterbar.la diff --git a/test/test_alloca.cpp b/test/test_alloca.cpp new file mode 100644 index 000000000..8c7e814b2 --- /dev/null +++ b/test/test_alloca.cpp @@ -0,0 +1,73 @@ +/* + +Copyright (c) 2017, 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. + +*/ + +#include "test.hpp" +#include "libtorrent/aux_/alloca.hpp" + +using namespace lt; + +namespace { + +struct A +{ + int val = 1337; +}; + +int destructed = 0; + +struct B +{ + ~B() { ++destructed; } +}; + +} + +TORRENT_TEST(alloca_construct) +{ + TORRENT_ALLOCA(vec, A, 13); + + TEST_EQUAL(vec.size(), 13); + for (auto const& o : vec) + { + TEST_EQUAL(o.val, 1337); + } +} + +TORRENT_TEST(alloca_destruct) +{ + { + destructed = 0; + TORRENT_ALLOCA(vec, B, 3); + } + TEST_EQUAL(destructed, 3); +} + diff --git a/test/test_heterogeneous_queue.cpp b/test/test_heterogeneous_queue.cpp index 2b28602a6..7c8e25e01 100644 --- a/test/test_heterogeneous_queue.cpp +++ b/test/test_heterogeneous_queue.cpp @@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "libtorrent/heterogeneous_queue.hpp" +namespace { + struct A { int a; @@ -143,6 +145,8 @@ struct G : A std::int64_t g; }; +} // anonymous namespace + // test emplace_back of heterogeneous types // and retrieval of their pointers TORRENT_TEST(emplace_back)