Skip to content

Commit 174d5e4

Browse files
committed
Fixed possible errors in memory allocation greater than 64K.
1 parent 2a1d8fa commit 174d5e4

File tree

3 files changed

+63
-18
lines changed

3 files changed

+63
-18
lines changed

include/libimp/detect_plat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
# define LIBIMP_CC_MSVC_2015 1900
4343
# define LIBIMP_CC_MSVC_2017 1910
4444
# define LIBIMP_CC_MSVC_2019 1920
45+
# define LIBIMP_CC_MSVC_2022 1930
4546
#elif defined(__GNUC__)
4647
# define LIBIMP_CC_GNUC __GNUC__
4748
# if defined(__clang__)

include/libpmr/new.h

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LIBPMR_NAMESPACE_BEG_
2525
class LIBIMP_EXPORT block_collector {
2626
public:
2727
virtual ~block_collector() noexcept = default;
28-
virtual void deallocate(void *p) noexcept = 0;
28+
virtual void recycle(void *p, std::size_t bytes, std::size_t alignment) noexcept = 0;
2929
};
3030

3131
using get_block_collector_t = block_collector *(*)() noexcept;
@@ -60,15 +60,41 @@ constexpr inline std::size_t regular_sizeof() noexcept {
6060
return regular_sizeof_impl(regular_head_size + sizeof(T));
6161
}
6262

63+
/// \brief Use block pools to handle memory less than 64K.
64+
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
65+
class block_resource_base : public block_pool<BlockSize, BlockPoolExpansion> {
66+
public:
67+
void *allocate(std::size_t /*bytes*/, std::size_t /*alignment*/) noexcept {
68+
return block_pool<BlockSize, BlockPoolExpansion>::allocate();
69+
}
70+
71+
void deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/) noexcept {
72+
block_pool<BlockSize, BlockPoolExpansion>::deallocate(p);
73+
}
74+
};
75+
76+
/// \brief Use `new`/`delete` to handle memory larger than 64K.
77+
template <std::size_t BlockSize>
78+
class block_resource_base<BlockSize, 0> : public new_delete_resource {
79+
public:
80+
void *allocate(std::size_t bytes, std::size_t alignment) noexcept {
81+
return new_delete_resource::allocate(regular_head_size + bytes, alignment);
82+
}
83+
84+
void deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept {
85+
new_delete_resource::deallocate(p, regular_head_size + bytes, alignment);
86+
}
87+
};
88+
6389
/// \brief Defines block pool memory resource based on block pool.
6490
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
65-
class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
91+
class block_pool_resource : public block_resource_base<BlockSize, BlockPoolExpansion>
6692
, public block_collector {
6793

68-
using base_t = block_pool<BlockSize, BlockPoolExpansion>;
94+
using base_t = block_resource_base<BlockSize, BlockPoolExpansion>;
6995

70-
void deallocate(void *p) noexcept override {
71-
base_t::deallocate(p);
96+
void recycle(void *p, std::size_t bytes, std::size_t alignment) noexcept override {
97+
base_t::deallocate(p, bytes, alignment);
7298
}
7399

74100
public:
@@ -77,22 +103,20 @@ class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
77103
return &instance;
78104
}
79105

80-
using base_t::base_t;
81-
82-
void *allocate(std::size_t /*bytes*/, std::size_t /*alignment*/ = alignof(std::max_align_t)) noexcept {
83-
void *p = base_t::allocate();
106+
void *allocate(std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept {
107+
void *p = base_t::allocate(bytes, alignment);
84108
*static_cast<get_block_collector_t *>(p) = get;
85109
return static_cast<::LIBIMP::byte *>(p) + regular_head_size;
86110
}
87111

88-
void deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/ = alignof(std::max_align_t)) noexcept {
112+
void deallocate(void *p, std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept {
89113
p = static_cast<::LIBIMP::byte *>(p) - regular_head_size;
90114
auto g = *static_cast<get_block_collector_t *>(p);
91115
if (g == get) {
92-
base_t::deallocate(p);
116+
base_t::deallocate(p, bytes, alignment);
93117
return;
94118
}
95-
g()->deallocate(p);
119+
g()->recycle(p, bytes, alignment);
96120
}
97121
};
98122

@@ -115,9 +139,6 @@ struct regular_resource {
115139
}
116140
};
117141

118-
template <std::size_t N>
119-
struct regular_resource<N, 4> : new_delete_resource {};
120-
121142
/// \brief Creates an object based on the specified type and parameters with block pool resource.
122143
/// \note This function is thread-safe.
123144
template <typename T, typename... A>
@@ -136,11 +157,11 @@ void delete$(T *p) noexcept {
136157
::LIBIMP::destroy(p);
137158
auto *res = regular_resource<regular_sizeof<T>()>::get();
138159
if (res == nullptr) return;
139-
#if defined(LIBIMP_CC_MSVC_2015)
160+
#if (LIBIMP_CC_MSVC > LIBIMP_CC_MSVC_2015)
161+
res->deallocate(p, sizeof(T), alignof(T));
162+
#else
140163
// `alignof` of vs2015 requires that type must be able to be instantiated.
141164
res->deallocate(p, sizeof(T));
142-
#else
143-
res->deallocate(p, sizeof(T), alignof(T));
144165
#endif
145166
}
146167

test/pmr/test_pmr_new.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ class Derived : public Base {
9393
int value_;
9494
};
9595

96+
class Derived64K : public Derived {
97+
public:
98+
using Derived::Derived;
99+
100+
private:
101+
std::array<char, 65536> padding_;
102+
};
103+
96104
} // namespace
97105

98106
TEST(pmr_new, delete$poly) {
@@ -110,6 +118,21 @@ TEST(pmr_new, delete$poly) {
110118
ASSERT_EQ(construct_count__, 0);
111119
}
112120

121+
TEST(pmr_new, delete$poly64k) {
122+
Base *p = pmr::new$<Derived64K>(-1);
123+
ASSERT_NE(p, nullptr);
124+
ASSERT_EQ(p->get(), -1);
125+
ASSERT_EQ(construct_count__, -1);
126+
pmr::delete$(p);
127+
ASSERT_EQ(construct_count__, 0);
128+
129+
Base *q = pmr::new$<Derived64K>((std::numeric_limits<int>::max)());
130+
ASSERT_EQ(q->get(), (std::numeric_limits<int>::max)());
131+
ASSERT_EQ(construct_count__, (std::numeric_limits<int>::max)());
132+
pmr::delete$(q);
133+
ASSERT_EQ(construct_count__, 0);
134+
}
135+
113136
TEST(pmr_new, delete$null) {
114137
Base *p = nullptr;
115138
pmr::delete$(p);

0 commit comments

Comments
 (0)