Skip to content

Commit 23ba9d1

Browse files
committed
construct and destruct objects in stack allocations (alloca())
1 parent 2dca174 commit 23ba9d1

File tree

6 files changed

+132
-5
lines changed

6 files changed

+132
-5
lines changed

include/libtorrent/aux_/alloca.hpp

+49-3
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,76 @@ POSSIBILITY OF SUCH DAMAGE.
3535
#include "libtorrent/config.hpp"
3636
#include "libtorrent/aux_/typed_span.hpp"
3737
#include "libtorrent/aux_/numeric_cast.hpp"
38+
#include <iterator> // for iterator_traits
39+
#include <memory> // for addressof
40+
41+
namespace libtorrent { namespace aux {
42+
43+
template<class ForwardIt>
44+
inline void uninitialized_default_construct(ForwardIt first, ForwardIt last)
45+
{
46+
using Value = typename std::iterator_traits<ForwardIt>::value_type;
47+
ForwardIt current = first;
48+
try {
49+
for (; current != last; ++current) {
50+
::new (static_cast<void*>(std::addressof(*current))) Value;
51+
}
52+
} catch (...) {
53+
for (; first != current; ++first) {
54+
first->~Value();
55+
}
56+
throw;
57+
}
58+
}
59+
60+
template <typename T>
61+
struct alloca_destructor
62+
{
63+
span<T> objects;
64+
~alloca_destructor()
65+
{
66+
for (auto& o : objects)
67+
{
68+
TORRENT_UNUSED(o);
69+
o.~T();
70+
}
71+
}
72+
};
73+
74+
}}
3875

3976
#if defined TORRENT_WINDOWS || defined TORRENT_MINGW
4077

4178
#include <malloc.h>
4279
#define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span<t> v; { \
4380
std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast<std::size_t>(n); \
4481
t* TORRENT_ALLOCA_tmp = static_cast<t*>(_alloca(sizeof(t) * TORRENT_ALLOCA_size)); \
45-
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); }
82+
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \
83+
::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \
84+
} \
85+
::libtorrent::aux::alloca_destructor<t> v##_destructor{v};
4686

4787
#elif defined TORRENT_BSD
4888

4989
#include <stdlib.h>
5090
#define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span<t> v; { \
5191
std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast<std::size_t>(n); \
5292
t* TORRENT_ALLOCA_tmp = static_cast<t*>(alloca(sizeof(t) * TORRENT_ALLOCA_size)); \
53-
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); }
93+
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \
94+
::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \
95+
} \
96+
::libtorrent::aux::alloca_destructor<t> v##_destructor{v};
5497

5598
#else
5699

57100
#include <alloca.h>
58101
#define TORRENT_ALLOCA(v, t, n) ::libtorrent::aux::typed_span<t> v; { \
59102
std::size_t TORRENT_ALLOCA_size = ::libtorrent::aux::numeric_cast<std::size_t>(n); \
60103
t* TORRENT_ALLOCA_tmp = static_cast<t*>(alloca(sizeof(t) * TORRENT_ALLOCA_size)); \
61-
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); }
104+
v = ::libtorrent::aux::typed_span<t>(TORRENT_ALLOCA_tmp, TORRENT_ALLOCA_size); \
105+
::libtorrent::aux::uninitialized_default_construct(v.begin(), v.end()); \
106+
} \
107+
::libtorrent::aux::alloca_destructor<t> v##_destructor{v};
62108

63109
#endif
64110

src/bdecode.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ namespace {
102102

103103
struct stack_frame
104104
{
105+
stack_frame() : token(0), state(0) {}
105106
explicit stack_frame(int const t): token(std::uint32_t(t)), state(0) {}
106107
// this is an index into m_tokens
107108
std::uint32_t token:31;

test/Jamfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ test-suite libtorrent :
143143
test_linked_list.cpp
144144
test_stack_allocator.cpp
145145
test_listen_socket.cpp
146-
test_file_progress.cpp ]
146+
test_file_progress.cpp
147+
test_alloca.cpp ]
147148

148149
[ run test_piece_picker.cpp ]
149150

test/Makefile.am

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ test_programs = \
4848
test_direct_dht \
4949
test_ffs \
5050
test_session_params \
51-
test_span
51+
test_span \
52+
test_alloca
5253

5354
if ENABLE_TESTS
5455
check_PROGRAMS = $(test_programs)
@@ -243,6 +244,7 @@ test_direct_dht_SOURCES = test_direct_dht.cpp
243244
test_ffs_SOURCES = test_ffs.cpp
244245
test_session_params_SOURCES = test_session_params.cpp
245246
test_span_SOURCES = test_span.cpp
247+
test_alloca_SOURCES = test_alloca.cpp
246248

247249
LDADD = libtest.la $(top_builddir)/src/libtorrent-rasterbar.la
248250

test/test_alloca.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
3+
Copyright (c) 2017, Arvid Norberg
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions
8+
are met:
9+
10+
* Redistributions of source code must retain the above copyright
11+
notice, this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in
14+
the documentation and/or other materials provided with the distribution.
15+
* Neither the name of the author nor the names of its
16+
contributors may be used to endorse or promote products derived
17+
from this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
POSSIBILITY OF SUCH DAMAGE.
30+
31+
*/
32+
33+
#include "test.hpp"
34+
#include "libtorrent/aux_/alloca.hpp"
35+
36+
using namespace lt;
37+
38+
namespace {
39+
40+
struct A
41+
{
42+
int val = 1337;
43+
};
44+
45+
int destructed = 0;
46+
47+
struct B
48+
{
49+
~B() { ++destructed; }
50+
};
51+
52+
}
53+
54+
TORRENT_TEST(alloca_construct)
55+
{
56+
TORRENT_ALLOCA(vec, A, 13);
57+
58+
TEST_EQUAL(vec.size(), 13);
59+
for (auto const& o : vec)
60+
{
61+
TEST_EQUAL(o.val, 1337);
62+
}
63+
}
64+
65+
TORRENT_TEST(alloca_destruct)
66+
{
67+
{
68+
destructed = 0;
69+
TORRENT_ALLOCA(vec, B, 3);
70+
}
71+
TEST_EQUAL(destructed, 3);
72+
}
73+

test/test_heterogeneous_queue.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE.
3333
#include "test.hpp"
3434
#include "libtorrent/heterogeneous_queue.hpp"
3535

36+
namespace {
37+
3638
struct A
3739
{
3840
int a;
@@ -143,6 +145,8 @@ struct G : A
143145
std::int64_t g;
144146
};
145147

148+
} // anonymous namespace
149+
146150
// test emplace_back of heterogeneous types
147151
// and retrieval of their pointers
148152
TORRENT_TEST(emplace_back)

0 commit comments

Comments
 (0)