MemoryTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright 2013-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/Memory.h>
  17. #include <limits>
  18. #include <memory>
  19. #include <type_traits>
  20. #include <utility>
  21. #include <glog/logging.h>
  22. #include <folly/ConstexprMath.h>
  23. #include <folly/String.h>
  24. #include <folly/memory/Arena.h>
  25. #include <folly/portability/GMock.h>
  26. #include <folly/portability/GTest.h>
  27. using namespace folly;
  28. static constexpr std::size_t kTooBig = folly::constexpr_max(
  29. std::size_t{std::numeric_limits<uint32_t>::max()},
  30. std::size_t{1} << (8 * sizeof(std::size_t) - 14));
  31. TEST(aligned_malloc, examples) {
  32. auto trial = [](size_t align) {
  33. auto const ptr = aligned_malloc(1, align);
  34. return (aligned_free(ptr), uintptr_t(ptr));
  35. };
  36. if (!kIsSanitize) { // asan allocator raises SIGABRT instead
  37. EXPECT_EQ(EINVAL, (trial(2), errno)) << "too small";
  38. EXPECT_EQ(EINVAL, (trial(513), errno)) << "not power of two";
  39. }
  40. EXPECT_EQ(0, trial(512) % 512);
  41. EXPECT_EQ(0, trial(8192) % 8192);
  42. }
  43. TEST(make_unique, compatible_with_std_make_unique) {
  44. // HACK: To enforce that `folly::` is imported here.
  45. to_shared_ptr(std::unique_ptr<std::string>());
  46. using namespace std;
  47. make_unique<string>("hello, world");
  48. }
  49. TEST(to_weak_ptr, example) {
  50. auto s = std::make_shared<int>(17);
  51. EXPECT_EQ(1, s.use_count());
  52. EXPECT_EQ(2, (to_weak_ptr(s).lock(), s.use_count())) << "lvalue";
  53. EXPECT_EQ(3, (to_weak_ptr(decltype(s)(s)).lock(), s.use_count())) << "rvalue";
  54. }
  55. TEST(SysAllocator, equality) {
  56. using Alloc = SysAllocator<float>;
  57. Alloc const a, b;
  58. EXPECT_TRUE(a == b);
  59. EXPECT_FALSE(a != b);
  60. }
  61. TEST(SysAllocator, allocate_unique) {
  62. using Alloc = SysAllocator<float>;
  63. Alloc const alloc;
  64. auto ptr = allocate_unique<float>(alloc, 3.);
  65. EXPECT_EQ(3., *ptr);
  66. }
  67. TEST(SysAllocator, vector) {
  68. using Alloc = SysAllocator<float>;
  69. Alloc const alloc;
  70. std::vector<float, Alloc> nums(alloc);
  71. nums.push_back(3.);
  72. nums.push_back(5.);
  73. EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  74. }
  75. TEST(SysAllocator, bad_alloc) {
  76. using Alloc = SysAllocator<float>;
  77. Alloc const alloc;
  78. std::vector<float, Alloc> nums(alloc);
  79. if (!kIsSanitize) {
  80. EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  81. }
  82. }
  83. TEST(AlignedSysAllocator, equality_fixed) {
  84. using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  85. Alloc const a, b;
  86. EXPECT_TRUE(a == b);
  87. EXPECT_FALSE(a != b);
  88. }
  89. TEST(AlignedSysAllocator, allocate_unique_fixed) {
  90. using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  91. Alloc const alloc;
  92. auto ptr = allocate_unique<float>(alloc, 3.);
  93. EXPECT_EQ(3., *ptr);
  94. EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
  95. }
  96. TEST(AlignedSysAllocator, vector_fixed) {
  97. using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  98. Alloc const alloc;
  99. std::vector<float, Alloc> nums(alloc);
  100. nums.push_back(3.);
  101. nums.push_back(5.);
  102. EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  103. EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
  104. }
  105. TEST(AlignedSysAllocator, bad_alloc_fixed) {
  106. using Alloc = AlignedSysAllocator<float, FixedAlign<1024>>;
  107. Alloc const alloc;
  108. std::vector<float, Alloc> nums(alloc);
  109. if (!kIsSanitize) {
  110. EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  111. }
  112. }
  113. TEST(AlignedSysAllocator, equality_default) {
  114. using Alloc = AlignedSysAllocator<float>;
  115. Alloc const a(1024), b(1024), c(512);
  116. EXPECT_TRUE(a == b);
  117. EXPECT_FALSE(a != b);
  118. EXPECT_FALSE(a == c);
  119. EXPECT_TRUE(a != c);
  120. }
  121. TEST(AlignedSysAllocator, allocate_unique_default) {
  122. using Alloc = AlignedSysAllocator<float>;
  123. Alloc const alloc(1024);
  124. auto ptr = allocate_unique<float>(alloc, 3.);
  125. EXPECT_EQ(3., *ptr);
  126. EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
  127. }
  128. TEST(AlignedSysAllocator, vector_default) {
  129. using Alloc = AlignedSysAllocator<float>;
  130. Alloc const alloc(1024);
  131. std::vector<float, Alloc> nums(alloc);
  132. nums.push_back(3.);
  133. nums.push_back(5.);
  134. EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
  135. EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
  136. }
  137. TEST(AlignedSysAllocator, bad_alloc_default) {
  138. using Alloc = AlignedSysAllocator<float>;
  139. Alloc const alloc(1024);
  140. std::vector<float, Alloc> nums(alloc);
  141. if (!kIsSanitize) {
  142. EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
  143. }
  144. }
  145. TEST(AlignedSysAllocator, converting_constructor) {
  146. using Alloc1 = AlignedSysAllocator<float>;
  147. using Alloc2 = AlignedSysAllocator<double>;
  148. Alloc1 const alloc1(1024);
  149. Alloc2 const alloc2(alloc1);
  150. }
  151. TEST(allocate_sys_buffer, compiles) {
  152. auto buf = allocate_sys_buffer(256);
  153. // Freed at the end of the scope.
  154. }
  155. struct CountedAllocatorStats {
  156. size_t deallocates = 0;
  157. };
  158. template <typename T>
  159. class CountedAllocator : public std::allocator<T> {
  160. private:
  161. CountedAllocatorStats* stats_;
  162. public:
  163. explicit CountedAllocator(CountedAllocatorStats& stats) noexcept
  164. : stats_(&stats) {}
  165. void deallocate(T* p, size_t n) {
  166. std::allocator<T>::deallocate(p, n);
  167. ++stats_->deallocates;
  168. }
  169. };
  170. TEST(allocate_unique, ctor_failure) {
  171. struct CtorThrows {
  172. explicit CtorThrows(bool cond) {
  173. if (cond) {
  174. throw std::runtime_error("nope");
  175. }
  176. }
  177. };
  178. using Alloc = CountedAllocator<CtorThrows>;
  179. using Deleter = allocator_delete<CountedAllocator<CtorThrows>>;
  180. {
  181. CountedAllocatorStats stats;
  182. Alloc const alloc(stats);
  183. EXPECT_EQ(0, stats.deallocates);
  184. std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
  185. ptr = allocate_unique<CtorThrows>(alloc, false);
  186. EXPECT_NE(nullptr, ptr);
  187. EXPECT_EQ(0, stats.deallocates);
  188. ptr = nullptr;
  189. EXPECT_EQ(nullptr, ptr);
  190. EXPECT_EQ(1, stats.deallocates);
  191. }
  192. {
  193. CountedAllocatorStats stats;
  194. Alloc const alloc(stats);
  195. EXPECT_EQ(0, stats.deallocates);
  196. std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
  197. EXPECT_THROW(
  198. ptr = allocate_unique<CtorThrows>(alloc, true), std::runtime_error);
  199. EXPECT_EQ(nullptr, ptr);
  200. EXPECT_EQ(1, stats.deallocates);
  201. }
  202. }
  203. namespace {
  204. template <typename T>
  205. struct TestAlloc1 : SysAllocator<T> {
  206. template <typename U, typename... Args>
  207. void construct(U* p, Args&&... args) {
  208. ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
  209. }
  210. };
  211. template <typename T>
  212. struct TestAlloc2 : TestAlloc1<T> {
  213. template <typename U>
  214. void destroy(U* p) {
  215. p->~U();
  216. }
  217. };
  218. template <typename T>
  219. struct TestAlloc3 : TestAlloc2<T> {
  220. using folly_has_default_object_construct = std::true_type;
  221. };
  222. template <typename T>
  223. struct TestAlloc4 : TestAlloc3<T> {
  224. using folly_has_default_object_destroy = std::true_type;
  225. };
  226. template <typename T>
  227. struct TestAlloc5 : SysAllocator<T> {
  228. using folly_has_default_object_construct = std::true_type;
  229. using folly_has_default_object_destroy = std::false_type;
  230. };
  231. } // namespace
  232. TEST(AllocatorObjectLifecycleTraits, compiles) {
  233. using A = std::allocator<int>;
  234. using S = std::string;
  235. static_assert(
  236. folly::AllocatorHasDefaultObjectConstruct<A, int, int>::value, "");
  237. static_assert(folly::AllocatorHasDefaultObjectConstruct<A, S, S>::value, "");
  238. static_assert(folly::AllocatorHasDefaultObjectDestroy<A, int>::value, "");
  239. static_assert(folly::AllocatorHasDefaultObjectDestroy<A, S>::value, "");
  240. static_assert(
  241. folly::AllocatorHasDefaultObjectConstruct<
  242. folly::AlignedSysAllocator<int>,
  243. int,
  244. int>::value,
  245. "");
  246. static_assert(
  247. folly::AllocatorHasDefaultObjectConstruct<
  248. folly::AlignedSysAllocator<int>,
  249. S,
  250. S>::value,
  251. "");
  252. static_assert(
  253. folly::AllocatorHasDefaultObjectDestroy<
  254. folly::AlignedSysAllocator<int>,
  255. int>::value,
  256. "");
  257. static_assert(
  258. folly::AllocatorHasDefaultObjectDestroy<
  259. folly::AlignedSysAllocator<int>,
  260. S>::value,
  261. "");
  262. static_assert(
  263. !folly::AllocatorHasDefaultObjectConstruct<TestAlloc1<S>, S, S>::value,
  264. "");
  265. static_assert(
  266. folly::AllocatorHasDefaultObjectDestroy<TestAlloc1<S>, S>::value, "");
  267. static_assert(
  268. !folly::AllocatorHasDefaultObjectConstruct<TestAlloc2<S>, S, S>::value,
  269. "");
  270. static_assert(
  271. !folly::AllocatorHasDefaultObjectDestroy<TestAlloc2<S>, S>::value, "");
  272. static_assert(
  273. folly::AllocatorHasDefaultObjectConstruct<TestAlloc3<S>, S, S>::value,
  274. "");
  275. static_assert(
  276. !folly::AllocatorHasDefaultObjectDestroy<TestAlloc3<S>, S>::value, "");
  277. static_assert(
  278. folly::AllocatorHasDefaultObjectConstruct<TestAlloc4<S>, S, S>::value,
  279. "");
  280. static_assert(
  281. folly::AllocatorHasDefaultObjectDestroy<TestAlloc4<S>, S>::value, "");
  282. static_assert(
  283. folly::AllocatorHasDefaultObjectConstruct<TestAlloc5<S>, S, S>::value,
  284. "");
  285. static_assert(
  286. !folly::AllocatorHasDefaultObjectDestroy<TestAlloc5<S>, S>::value, "");
  287. }
  288. template <typename T>
  289. struct ExpectingAlloc {
  290. using value_type = T;
  291. ExpectingAlloc(std::size_t expectedSize, std::size_t expectedCount)
  292. : expectedSize_{expectedSize}, expectedCount_{expectedCount} {}
  293. template <class U>
  294. explicit ExpectingAlloc(ExpectingAlloc<U> const& other) noexcept
  295. : expectedSize_{other.expectedSize_},
  296. expectedCount_{other.expectedCount_} {}
  297. T* allocate(std::size_t n) {
  298. EXPECT_EQ(expectedSize_, sizeof(T));
  299. EXPECT_EQ(expectedSize_, alignof(T));
  300. EXPECT_EQ(expectedCount_, n);
  301. return std::allocator<T>{}.allocate(n);
  302. }
  303. void deallocate(T* p, std::size_t n) {
  304. std::allocator<T>{}.deallocate(p, n);
  305. }
  306. std::size_t expectedSize_;
  307. std::size_t expectedCount_;
  308. };
  309. struct alignas(64) OverAlignedType {
  310. std::array<char, 64> raw_;
  311. };
  312. TEST(allocateOverAligned, notActuallyOver) {
  313. // allocates 6 bytes with alignment 4, should get turned into an
  314. // allocation of 2 elements of something of size and alignment 4
  315. ExpectingAlloc<char> a(4, 2);
  316. auto p = folly::allocateOverAligned<decltype(a), 4>(a, 6);
  317. EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 4), 0);
  318. folly::deallocateOverAligned<decltype(a), 4>(a, p, 6);
  319. EXPECT_EQ((folly::allocationBytesForOverAligned<decltype(a), 4>(6)), 8);
  320. }
  321. TEST(allocateOverAligned, manualOverStdAlloc) {
  322. // allocates 6 bytes with alignment 64 using std::allocator, which will
  323. // result in a call to aligned_malloc underneath. We free one directly
  324. // to check that this is not the padding path
  325. std::allocator<short> a;
  326. auto p = folly::allocateOverAligned<decltype(a), 64>(a, 3);
  327. auto p2 = folly::allocateOverAligned<decltype(a), 64>(a, 3);
  328. EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
  329. folly::deallocateOverAligned<decltype(a), 64>(a, p, 3);
  330. aligned_free(p2);
  331. EXPECT_EQ((folly::allocationBytesForOverAligned<decltype(a), 64>(3)), 6);
  332. }
  333. TEST(allocateOverAligned, manualOverCustomAlloc) {
  334. // allocates 6 byte with alignment 64 using non-standard allocator, which
  335. // will result in an allocation of 64 + alignof(max_align_t) underneath.
  336. ExpectingAlloc<short> a(
  337. alignof(folly::max_align_t), 64 / alignof(folly::max_align_t) + 1);
  338. auto p = folly::allocateOverAligned<decltype(a), 64>(a, 3);
  339. EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
  340. folly::deallocateOverAligned<decltype(a), 64>(a, p, 3);
  341. EXPECT_EQ(
  342. (folly::allocationBytesForOverAligned<decltype(a), 64>(3)),
  343. 64 + alignof(folly::max_align_t));
  344. }
  345. TEST(allocateOverAligned, defaultOverCustomAlloc) {
  346. ExpectingAlloc<OverAlignedType> a(
  347. alignof(folly::max_align_t), 128 / alignof(folly::max_align_t));
  348. auto p = folly::allocateOverAligned(a, 1);
  349. EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
  350. folly::deallocateOverAligned(a, p, 1);
  351. EXPECT_EQ(folly::allocationBytesForOverAligned<decltype(a)>(1), 128);
  352. }