diff options
Diffstat (limited to 'src/boost/libs/pool/test')
18 files changed, 1456 insertions, 0 deletions
diff --git a/src/boost/libs/pool/test/Jamfile.v2 b/src/boost/libs/pool/test/Jamfile.v2 new file mode 100644 index 000000000..9e96abcbd --- /dev/null +++ b/src/boost/libs/pool/test/Jamfile.v2 @@ -0,0 +1,49 @@ +#~ Copyright Rene Rivera 2008 +#~ Copyright James E. King III 2018 +#~ Distributed under the Boost Software License, Version 1.0. +#~ (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +project + : requirements + <library>/boost/system//boost_system + <define>BOOST_ALL_NO_LIB=1 + <warnings>all + <toolset>clang:<cxxflags>-Wextra + <toolset>clang:<cxxflags>-Wno-variadic-macros + <toolset>gcc:<cxxflags>-Wextra + <toolset>gcc:<cxxflags>-Wshadow + <toolset>gcc:<cxxflags>-Wno-variadic-macros + <toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS + ; + +import common ; +import os ; +import testing ; + +test-suite pool : + [ run test_simple_seg_storage.cpp : : : <toolset>msvc:<cxxflags>-wd4267 ] + [ run test_pool_alloc.cpp ] + [ run pool_msvc_compiler_bug_test.cpp : : : <toolset>msvc:<cxxflags>-wd4512 ] + [ run test_msvc_mem_leak_detect.cpp ] + [ run test_bug_3349.cpp ] + [ run test_bug_4960.cpp ] + [ run test_bug_1252.cpp : : : + <toolset>clang:<cxxflags>-Wno-c++11-long-long + <toolset>gcc:<cxxflags>-Wno-long-long + <toolset>pathscale:<cxxflags>-Wno-long-long ] + [ run test_bug_2696.cpp ] + [ run test_bug_5526.cpp ] + [ run test_threading.cpp : : : <threading>multi <library>/boost/thread//boost_thread ] + [ compile test_poisoned_macros.cpp ] + ; + +if [ os.environ VALGRIND_OPTS ] +{ +test-suite pool-valgrind : + [ run test_pool_alloc.cpp : : : <define>BOOST_POOL_VALGRIND=1 : test_pool_alloc_valgrind ] + [ run-fail test_valgrind_fail_1.cpp : : : <define>BOOST_POOL_VALGRIND=1 ] + [ run-fail test_valgrind_fail_2.cpp : : : <define>BOOST_POOL_VALGRIND=1 ] + ; +} + diff --git a/src/boost/libs/pool/test/pool_msvc_compiler_bug_test.cpp b/src/boost/libs/pool/test/pool_msvc_compiler_bug_test.cpp new file mode 100644 index 000000000..e188c4701 --- /dev/null +++ b/src/boost/libs/pool/test/pool_msvc_compiler_bug_test.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2008 Jurko Gospodnetic +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// This tests whether the Boost Pool library managed to get a regression and +// hit the MSVC 'variables exported to global namespace' bug again. This bug +// affects at least MSVC 7.1 & 8.0 releases and has been fixed in the MSVC 9.0 +// release. +// +// If the bug exists this test should fail to compile, complaining about an +// ambiguous CRITICAL_SECTION symbol. The bug got fixed by making the boost/ +// /pool/detail/mutex.hpp header reference all Windows API constants using their +// fully qualified names. +// +// To see the bug in action without using any Boost libraries run the +// following program: +// +// namespace One { class Brick; } +// namespace Two +// { +// using namespace One; +// template <class TinyTemplateParam> class TinyClass {}; +// } +// class Brick {}; +// Brick brick; +// int main() {} +// (17.04.2008.) (Jurko) + + +#include "boost/archive/text_iarchive.hpp" +#include "boost/pool/detail/mutex.hpp" +// Including "boost/pool/pool_alloc.hpp" instead of mutex.hpp should work as +// well. + +int main() +{ +} diff --git a/src/boost/libs/pool/test/random_shuffle.hpp b/src/boost/libs/pool/test/random_shuffle.hpp new file mode 100644 index 000000000..1bc545238 --- /dev/null +++ b/src/boost/libs/pool/test/random_shuffle.hpp @@ -0,0 +1,26 @@ +/* Copyright (C) 2016 Edward Diener +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +#ifndef BOOST_POOL_TEST_RANDOM_SHUFFLE_HPP +#define BOOST_POOL_TEST_RANDOM_SHUFFLE_HPP + +#include <cstdlib> +#include <iterator> +#include <algorithm> + +template< class RandomIt > +void pool_test_random_shuffle( RandomIt first, RandomIt last ) +{ + typename std::iterator_traits<RandomIt>::difference_type i, n; + n = last - first; + for (i = n-1; i > 0; --i) { + using std::swap; + swap(first[i], first[std::rand() % (i+1)]); + } +} + +#endif // BOOST_POOL_TEST_RANDOM_SHUFFLE_HPP diff --git a/src/boost/libs/pool/test/test_bug_1252.cpp b/src/boost/libs/pool/test/test_bug_1252.cpp new file mode 100644 index 000000000..18830571e --- /dev/null +++ b/src/boost/libs/pool/test/test_bug_1252.cpp @@ -0,0 +1,66 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// Test of bug #1252 (https://svn.boost.org/trac/boost/ticket/1252) + +#include <boost/pool/pool.hpp> +#include <boost/detail/lightweight_test.hpp> +#include <boost/type_traits/alignment_of.hpp> +#include <cstring> + +struct limited_allocator_new_delete +{ + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes) + { + if(bytes > 1510 * 32) + return 0; + return new (std::nothrow) char[bytes]; + } + static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block) + { + delete [] block; + } +}; + +template <class T> +void test_alignment(T) +{ + unsigned align = boost::alignment_of<T>::value; + boost::pool<> p(sizeof(T)); + unsigned limit = 100000; + for(unsigned i = 0; i < limit; ++i) + { + void* ptr = (p.malloc)(); + BOOST_TEST(reinterpret_cast<std::size_t>(ptr) % align == 0); + // Trample over the memory just to be sure the allocated block is big enough, + // if it's not, we'll trample over the next block as well (and our internal housekeeping). + std::memset(ptr, 0xff, sizeof(T)); + } +} + + +int main() +{ + boost::pool<limited_allocator_new_delete> po(1501); + void* p = (po.malloc)(); + BOOST_TEST(p != 0); + + test_alignment(char(0)); + test_alignment(short(0)); + test_alignment(int(0)); + test_alignment(long(0)); + test_alignment(double(0)); + test_alignment(float(0)); + test_alignment((long double)(0)); +#ifndef BOOST_NO_LONG_LONG + test_alignment((long long)(0)); +#endif + return boost::report_errors(); +} diff --git a/src/boost/libs/pool/test/test_bug_2696.cpp b/src/boost/libs/pool/test/test_bug_2696.cpp new file mode 100644 index 000000000..9b72b3d65 --- /dev/null +++ b/src/boost/libs/pool/test/test_bug_2696.cpp @@ -0,0 +1,66 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// Test of bug #2696 (https://svn.boost.org/trac/boost/ticket/2696) + +#include <boost/pool/pool.hpp> +#include <boost/detail/lightweight_test.hpp> + +struct limited_allocator_new_delete +{ + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes) + { +#ifndef BOOST_POOL_VALGRIND + static const unsigned max_size = sizeof(void*) * 40 + boost::integer::static_lcm<sizeof(size_type), sizeof(void *)>::value + sizeof(size_type); +#else + static const unsigned max_size = sizeof(void*) * 40; +#endif + if(bytes > max_size) + return 0; + return new (std::nothrow) char[bytes]; + } + static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block) + { + delete [] block; + } +}; + +int main() +{ + static const unsigned alloc_size = sizeof(void*); + boost::pool<limited_allocator_new_delete> p1(alloc_size, 10, 40); + for(int i = 1; i <= 40; ++i) + BOOST_TEST((p1.ordered_malloc)(i)); + BOOST_TEST(p1.ordered_malloc(42) == 0); + // + // If the largest block is 40, and we start with 10, we get 10+20+40 elements before + // we actually run out of memory: + // + boost::pool<limited_allocator_new_delete> p2(alloc_size, 10, 40); + for(int i = 1; i <= 70; ++i) + BOOST_TEST((p2.malloc)()); + boost::pool<limited_allocator_new_delete> p2b(alloc_size, 10, 40); + for(int i = 1; i <= 100; ++i) + BOOST_TEST((p2b.ordered_malloc)()); + // + // Try again with no explicit upper limit: + // + boost::pool<limited_allocator_new_delete> p3(alloc_size); + for(int i = 1; i <= 40; ++i) + BOOST_TEST((p3.ordered_malloc)(i)); + BOOST_TEST(p3.ordered_malloc(42) == 0); + boost::pool<limited_allocator_new_delete> p4(alloc_size, 10); + for(int i = 1; i <= 100; ++i) + BOOST_TEST((p4.ordered_malloc)()); + boost::pool<limited_allocator_new_delete> p5(alloc_size, 10); + for(int i = 1; i <= 100; ++i) + BOOST_TEST((p5.malloc)()); + return boost::report_errors(); +} diff --git a/src/boost/libs/pool/test/test_bug_3349.cpp b/src/boost/libs/pool/test/test_bug_3349.cpp new file mode 100644 index 000000000..57269d0f8 --- /dev/null +++ b/src/boost/libs/pool/test/test_bug_3349.cpp @@ -0,0 +1,27 @@ +/* Copyright (C) 2011 Kwan Ting Chan + * Based from bug report submitted by Xiaohan Wang + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +// Test of bug #3349 (https://svn.boost.org/trac/boost/ticket/3349) + +#include <boost/pool/pool.hpp> + +#include <boost/core/lightweight_test.hpp> + +int main() +{ + boost::pool<> p(256, 4); + + void* pBlock1 = p.ordered_malloc( 1 ); + void* pBlock2 = p.ordered_malloc( 4 ); + (void)pBlock2; // warning suppression + + p.ordered_free( pBlock1 ); + + BOOST_TEST(p.release_memory()); + return boost::report_errors(); +} diff --git a/src/boost/libs/pool/test/test_bug_4960.cpp b/src/boost/libs/pool/test/test_bug_4960.cpp new file mode 100644 index 000000000..e95f714ec --- /dev/null +++ b/src/boost/libs/pool/test/test_bug_4960.cpp @@ -0,0 +1,45 @@ +/* Copyright (C) 2011 Kwan Ting Chan + * Based from bug report submitted by Xiaohan Wang + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +// Test of bug #4960 (https://svn.boost.org/trac/boost/ticket/4960) + +#include <boost/pool/pool_alloc.hpp> +#include <vector> +#include <iostream> + +typedef std::vector<int, boost::pool_allocator<int> > EventVector; +typedef std::vector<EventVector, boost::pool_allocator<EventVector> > IndexVector; + +int main() +{ + IndexVector iv; + int limit = 100; + for (int i = 0; i < limit; ++i) + { + iv.push_back(EventVector()); + for(int j = 0; j < limit; ++j) + iv.back().push_back(j); + } + + boost::pool<boost::default_user_allocator_new_delete> po(4); + for(int i = 0; i < limit; ++i) + { + void* p = po.ordered_malloc(0); + po.ordered_free(p, 0); + } + + boost::pool_allocator<int> al; + for(int i = 0; i < limit; ++i) + { + int* p = al.allocate(0); + al.deallocate(p, 0); + } + + std::cout << "it works\n"; + return 0; +} diff --git a/src/boost/libs/pool/test/test_bug_5526.cpp b/src/boost/libs/pool/test/test_bug_5526.cpp new file mode 100644 index 000000000..a23994a54 --- /dev/null +++ b/src/boost/libs/pool/test/test_bug_5526.cpp @@ -0,0 +1,36 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// Test of bug #5526 (https://svn.boost.org/trac/boost/ticket/5526) + +#include <boost/smart_ptr/scoped_ptr.hpp> +#include <boost/pool/pool.hpp> +#include <boost/pool/singleton_pool.hpp> +#include <boost/assert.hpp> + +struct bad +{ + bad() + { + buf = static_cast<int*>(boost::singleton_pool<int, sizeof(int)>::malloc()); + *buf = 0x1234; + } + ~bad() + { + BOOST_ASSERT(*buf == 0x1234); + boost::singleton_pool<int, sizeof(int)>::free(buf); + } + int* buf; +}; + +boost::scoped_ptr<bad> aptr; + +int main() +{ + aptr.reset(new bad()); + return 0; +} diff --git a/src/boost/libs/pool/test/test_msvc_mem_leak_detect.cpp b/src/boost/libs/pool/test/test_msvc_mem_leak_detect.cpp new file mode 100644 index 000000000..3a80f168d --- /dev/null +++ b/src/boost/libs/pool/test/test_msvc_mem_leak_detect.cpp @@ -0,0 +1,50 @@ +/* Copyright (C) 2011 Kwan Ting Chan + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +// Test of bug #4346 (https://svn.boost.org/trac/boost/ticket/4346) + +#ifdef _MSC_VER +#define _CRTDBG_MAP_ALLOC +#include <stdlib.h> +#include <crtdbg.h> +#endif + +#include <boost/pool/poolfwd.hpp> +#include <boost/pool/simple_segregated_storage.hpp> +#include <boost/pool/pool.hpp> +#include <boost/pool/pool_alloc.hpp> +#include <boost/pool/singleton_pool.hpp> +#include <boost/pool/object_pool.hpp> + +#include <vector> + +struct Foo {}; + +int main() +{ + { + boost::pool<> p(sizeof(int)); + (p.malloc)(); + } + + { + boost::object_pool<Foo> p; + (p.malloc)(); + } + + { + (boost::singleton_pool<Foo, sizeof(int)>::malloc)(); + } + boost::singleton_pool<Foo, sizeof(int)>::purge_memory(); + + { + std::vector<int, boost::pool_allocator<int> > v; + v.push_back(8); + } + boost::singleton_pool<boost::pool_allocator_tag, + sizeof(int)>::release_memory(); +} diff --git a/src/boost/libs/pool/test/test_poisoned_macros.cpp b/src/boost/libs/pool/test/test_poisoned_macros.cpp new file mode 100644 index 000000000..072122c2f --- /dev/null +++ b/src/boost/libs/pool/test/test_poisoned_macros.cpp @@ -0,0 +1,50 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// +// Verify that if malloc/free are macros that everything still works OK: +// + +#include <functional> +#include <new> +#include <cstddef> +#include <cstdlib> +#include <exception> +#include <algorithm> +#include <boost/limits.hpp> +#include <iostream> +#include <locale> + +namespace std{ + + void* undefined_poisoned_symbol1(unsigned x); + void undefined_poisoned_symbol2(void* x); + +} + +#define malloc(x) undefined_poisoned_symbol1(x) +#define free(x) undefined_poisoned_symbol2(x) + +#include <boost/pool/pool.hpp> +#include <boost/pool/object_pool.hpp> +#include <boost/pool/pool_alloc.hpp> +#include <boost/pool/singleton_pool.hpp> + +template class boost::object_pool<int, boost::default_user_allocator_new_delete>; +template class boost::object_pool<int, boost::default_user_allocator_malloc_free>; + +template class boost::pool<boost::default_user_allocator_new_delete>; +template class boost::pool<boost::default_user_allocator_malloc_free>; + +template class boost::pool_allocator<int, boost::default_user_allocator_new_delete>; +template class boost::pool_allocator<int, boost::default_user_allocator_malloc_free>; +template class boost::fast_pool_allocator<int, boost::default_user_allocator_new_delete>; +template class boost::fast_pool_allocator<int, boost::default_user_allocator_malloc_free>; + +template class boost::simple_segregated_storage<unsigned>; + +template class boost::singleton_pool<int, 32>; diff --git a/src/boost/libs/pool/test/test_pool_alloc.cpp b/src/boost/libs/pool/test/test_pool_alloc.cpp new file mode 100644 index 000000000..b0b50eabe --- /dev/null +++ b/src/boost/libs/pool/test/test_pool_alloc.cpp @@ -0,0 +1,291 @@ +/* Copyright (C) 2000, 2001 Stephen Cleary + * Copyright (C) 2011 Kwan Ting Chan + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "random_shuffle.hpp" +#include <boost/pool/pool_alloc.hpp> +#include <boost/pool/object_pool.hpp> + +#include <boost/detail/lightweight_test.hpp> + +#include <algorithm> +#include <deque> +#include <list> +#include <set> +#include <stdexcept> +#include <vector> + +#include <cstdlib> +#include <ctime> + +// Each "tester" object below checks into and out of the "cdtor_checker", +// which will check for any problems related to the construction/destruction of +// "tester" objects. +class cdtor_checker +{ +private: + // Each constructed object registers its "this" pointer into "objs" + std::set<void*> objs; + +public: + // True iff all objects that have checked in have checked out + bool ok() const { return objs.empty(); } + + ~cdtor_checker() + { + BOOST_TEST(ok()); + } + + void check_in(void * const This) + { + BOOST_TEST(objs.find(This) == objs.end()); + objs.insert(This); + } + + void check_out(void * const This) + { + BOOST_TEST(objs.find(This) != objs.end()); + objs.erase(This); + } +}; +static cdtor_checker mem; + +struct tester +{ + tester(bool throw_except = false) + { + if(throw_except) + { + throw std::logic_error("Deliberate constructor exception"); + } + + mem.check_in(this); + } + + tester(const tester &) + { + mem.check_in(this); + } + + ~tester() + { + mem.check_out(this); + } +}; + +// This is a wrapper around a UserAllocator. It just registers alloc/dealloc +// to/from the system memory. It's used to make sure pool's are allocating +// and deallocating system memory properly. +// Do NOT use this class with static or singleton pools. +template <typename UserAllocator> +struct TrackAlloc +{ + typedef typename UserAllocator::size_type size_type; + typedef typename UserAllocator::difference_type difference_type; + + static std::set<char *> allocated_blocks; + + static char * malloc(const size_type bytes) + { + char * const ret = UserAllocator::malloc(bytes); + allocated_blocks.insert(ret); + return ret; + } + + static void free(char * const block) + { + BOOST_TEST(allocated_blocks.find(block) != allocated_blocks.end()); + allocated_blocks.erase(block); + UserAllocator::free(block); + } + + static bool ok() + { + return allocated_blocks.empty(); + } +}; +template <typename UserAllocator> +std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks; + +typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc; + +void test() +{ + { + // Do nothing pool + boost::object_pool<tester> pool; + } + + { + // Construct several tester objects. Don't delete them (i.e., + // test pool's garbage collection). + boost::object_pool<tester> pool; + for(int i=0; i < 10; ++i) + { + pool.construct(); + } + } + + { + // Construct several tester objects. Delete some of them. + boost::object_pool<tester> pool; + std::vector<tester *> v; + for(int i=0; i < 10; ++i) + { + v.push_back(pool.construct()); + } + pool_test_random_shuffle(v.begin(), v.end()); + for(int j=0; j < 5; ++j) + { + pool.destroy(v[j]); + } + } + + { + // Test how pool reacts with constructors that throw exceptions. + // Shouldn't have any memory leaks. + boost::object_pool<tester> pool; + for(int i=0; i < 5; ++i) + { + pool.construct(); + } + for(int j=0; j < 5; ++j) + { + try + { + // The following constructions will raise an exception. + pool.construct(true); + } + catch(const std::logic_error &) {} + } + } +} + +void test_alloc() +{ + { + // Allocate several tester objects. Delete one. + std::vector<tester, boost::pool_allocator<tester> > l; + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + } + + { + // Allocate several tester objects. Delete two. + std::deque<tester, boost::pool_allocator<tester> > l; + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + l.pop_front(); + } + + { + // Allocate several tester objects. Delete two. + std::list<tester, boost::fast_pool_allocator<tester> > l; + // lists rebind their allocators, so dumping is useless + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + l.pop_front(); + } + + tester * tmp; + { + // Create a memory leak on purpose. (Allocator doesn't have + // garbage collection) + // (Note: memory leak) + boost::pool_allocator<tester> a; + tmp = a.allocate(1, 0); + new (tmp) tester(); + } + if(mem.ok()) + { + BOOST_ERROR("Pool allocator cleaned up itself"); + } + // Remove memory checker entry (to avoid error later) and + // clean up memory leak + tmp->~tester(); + boost::pool_allocator<tester>::deallocate(tmp, 1); + + // test allocating zero elements + { + boost::pool_allocator<tester> alloc; + tester* ip = alloc.allocate(0); + alloc.deallocate(ip, 0); + } +} + +void test_mem_usage() +{ + typedef boost::pool<track_alloc> pool_type; + + { + // Constructor should do nothing; no memory allocation + pool_type pool(sizeof(int)); + BOOST_TEST(track_alloc::ok()); + BOOST_TEST(!pool.release_memory()); + BOOST_TEST(!pool.purge_memory()); + + // Should allocate from system + pool.free(pool.malloc()); + BOOST_TEST(!track_alloc::ok()); + + // Ask pool to give up memory it's not using; this should succeed + BOOST_TEST(pool.release_memory()); + BOOST_TEST(track_alloc::ok()); + + // Should allocate from system again + pool.malloc(); // loses the pointer to the returned chunk (*A*) + + // Ask pool to give up memory it's not using; this should fail + BOOST_TEST(!pool.release_memory()); + + // Force pool to give up memory it's not using; this should succeed + // This will clean up the memory leak from (*A*) + BOOST_TEST(pool.purge_memory()); + BOOST_TEST(track_alloc::ok()); + + // Should allocate from system again + pool.malloc(); // loses the pointer to the returned chunk (*B*) + + // pool's destructor should purge the memory + // This will clean up the memory leak from (*B*) + } + + BOOST_TEST(track_alloc::ok()); +} + +void test_void() +{ + typedef boost::pool_allocator<void> void_allocator; + typedef boost::fast_pool_allocator<void> fast_void_allocator; + + typedef void_allocator::rebind<int>::other int_allocator; + typedef fast_void_allocator::rebind<int>::other fast_int_allocator; + + std::vector<int, int_allocator> v1; + std::vector<int, fast_int_allocator> v2; +} + +int main() +{ + std::srand(static_cast<unsigned>(std::time(0))); + + test(); + test_alloc(); + test_mem_usage(); + test_void(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/pool/test/test_simple_seg_storage.cpp b/src/boost/libs/pool/test/test_simple_seg_storage.cpp new file mode 100644 index 000000000..67a33e002 --- /dev/null +++ b/src/boost/libs/pool/test/test_simple_seg_storage.cpp @@ -0,0 +1,304 @@ +/* Copyright (C) 2011 Kwan Ting Chan + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "test_simple_seg_storage.hpp" +#include "track_allocator.hpp" +#include "random_shuffle.hpp" + +#include <boost/pool/simple_segregated_storage.hpp> +#include <boost/assert.hpp> +#include <boost/integer/common_factor_ct.hpp> +#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600) +#pragma warning(push) +#pragma warning(disable: 4244) +// ..\..\boost/random/uniform_int_distribution.hpp(171) : +// warning C4127: conditional expression is constant +#pragma warning(disable: 4127) +#endif +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/variate_generator.hpp> +#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600) +#pragma warning(pop) +#endif + +#include <boost/core/lightweight_test.hpp> + +#include <algorithm> +#include <functional> +#include <set> +#include <vector> + +#include <cstddef> +#include <cstdlib> +#include <ctime> + +#ifdef BOOST_MSVC +#pragma warning(disable:4267) +#endif + +// "A free list is ordered if repeated calls to malloc() will result in a +// constantly-increasing sequence of values, as determined by std::less<void*>" +// Return: true if in constantly-increasing order, false otherwise +bool check_is_order(const std::vector<void*>& vs) +{ + if(vs.size() < 2) { return true; } + + void *lower, *higher; + std::vector<void*>::const_iterator ci = vs.begin(); + lower = *(ci++); + while(ci != vs.end()) + { + higher = *(ci++); + if(!std::less<void*>()(lower, higher)) { return false; } + } + + return true; +} + +// Return: number of chunks malloc'd from store +std::size_t test_is_order(test_simp_seg_store& store) +{ + std::vector<void*> vpv; + std::size_t nchunk = 0; + // Pre: !empty() + while(!store.empty()) + { + void* const first = store.get_first(); + void* const pv = store.malloc(); + // "Takes the first available chunk from the free list + // and returns it" + BOOST_TEST(first == pv); + + vpv.push_back(pv); + ++nchunk; + } + BOOST_TEST(check_is_order(vpv)); + + return nchunk; +} + +boost::mt19937 gen; + +int main() +{ + std::srand(static_cast<unsigned>(std::time(0))); + gen.seed(static_cast<boost::uint32_t>(std::time(0))); + + /* Store::segregate(block, sz, partition_sz, end) */ + std::size_t partition_sz + = boost::integer::static_lcm<sizeof(void*), sizeof(int)>::value; + boost::uniform_int<> dist(partition_sz, 10000); + boost::variate_generator<boost::mt19937&, + boost::uniform_int<> > die(gen, dist); + std::size_t block_size = die(); + // Pre: npartition_sz >= sizeof(void*) + // npartition_sz = sizeof(void*) * i, for some integer i + // nsz >= npartition_sz + // block is properly aligned for an array of object of + // size npartition_sz and array of void * + BOOST_ASSERT(partition_sz >= sizeof(void*)); + BOOST_ASSERT(partition_sz % sizeof(void*) == 0); + BOOST_ASSERT(block_size >= partition_sz); + { + char* const pc = track_allocator::malloc(block_size); + // (Test) Pre: block of memory is valid + BOOST_ASSERT(pc); + int endadd = 0; + void* const pvret = test_simp_seg_store::segregate(pc, block_size, + partition_sz, &endadd); + + // The first chunk "is always equal to block" + BOOST_TEST(pvret == pc); + + void* cur = test_simp_seg_store::get_nextof(static_cast<int*>(pvret)); + void* last = pvret; + std::size_t nchunk = 1; + while(cur != &endadd) + { + ++nchunk; + + // Memory of each chunk does not overlap + // The free list constructed is actually from the given block + // The "interleaved free list is ordered" + BOOST_TEST(std::less_equal<void*>()(static_cast<char*>(last) + + partition_sz, cur)); + BOOST_TEST(std::less_equal<void*>()(static_cast<char*>(cur) + + partition_sz, pc + block_size)); + + last = cur; + cur = test_simp_seg_store::get_nextof(static_cast<int*>(cur)); + } + // "The last chunk is set to point to end" + // "Partitioning into as many partition_sz-sized chunks as possible" + BOOST_TEST(nchunk == block_size/partition_sz); + } + + /* t.add_block(block, sz, partition_sz), t.malloc() */ + { + // Default constructor of simple_segregated_storage do nothing + test_simp_seg_store tstore; + // Post: empty() + BOOST_TEST(tstore.empty()); + + char* const pc = track_allocator::malloc(block_size); + tstore.add_block(pc, block_size, partition_sz); + + // The first chunk "is always equal to block" + BOOST_TEST(tstore.get_first() == pc); + + // Empty before add_block() => "is ordered after" + std::size_t nchunk = test_is_order(tstore); + // "Partitioning into as many partition_sz-sized chunks as possible" + BOOST_TEST(nchunk == block_size/partition_sz); + + BOOST_ASSERT(partition_sz <= 23); + test_simp_seg_store tstore2; + char* const pc2 = track_allocator::malloc(88); + tstore2.add_block(pc2, 24, partition_sz); + tstore2.add_block(pc2 + 64, 24, partition_sz); + tstore2.add_block(pc2 + 32, 24, partition_sz); + tstore2.add_block(track_allocator::malloc(23), 23, partition_sz); + std::size_t nchunk_ref = (3*(24/partition_sz)) + (23/partition_sz); + for(nchunk = 0; !tstore2.empty(); tstore2.malloc(), ++nchunk) {} + // add_block() merges new free list to existing + BOOST_TEST(nchunk == nchunk_ref); + } + + /* t.free(chunk) */ + { + test_simp_seg_store tstore; + char* const pc = track_allocator::malloc(partition_sz); + tstore.add_block(pc, partition_sz, partition_sz); + void* pv = tstore.malloc(); + BOOST_TEST(tstore.empty()); + tstore.free(pv); + } + + /* t.add_ordered_block(block, sz, partition_sz) */ + { + { + char* const pc = track_allocator::malloc(6 * partition_sz); + std::vector<void*> vpv; + vpv.push_back(pc); + vpv.push_back(pc + (2 * partition_sz)); + vpv.push_back(pc + (4 * partition_sz)); + + do + { + test_simp_seg_store tstore; + tstore.add_ordered_block(vpv[0], 2*partition_sz, partition_sz); + tstore.add_ordered_block(vpv[1], 2*partition_sz, partition_sz); + tstore.add_ordered_block(vpv[2], 2*partition_sz, partition_sz); + // "Order-preserving" + test_is_order(tstore); + } while(std::next_permutation(vpv.begin(), vpv.end())); + } + + { + test_simp_seg_store tstore; + char* const pc = track_allocator::malloc(6 * partition_sz); + tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz); + tstore.add_ordered_block(pc + (4 * partition_sz), + (2 * partition_sz), partition_sz); + // "Order-preserving" + test_is_order(tstore); + } + + { + test_simp_seg_store tstore; + char* const pc = track_allocator::malloc(6 * partition_sz); + tstore.add_ordered_block(pc + (4 * partition_sz), + (2 * partition_sz), partition_sz); + tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz); + // "Order-preserving" + test_is_order(tstore); + } + } + + /* t.ordered_free(chunk) */ + { + char* const pc = track_allocator::malloc(6 * partition_sz); + + test_simp_seg_store tstore; + tstore.add_block(pc, 6 * partition_sz, partition_sz); + + std::vector<void*> vpv; + for(std::size_t i=0; i < 6; ++i) { vpv.push_back(tstore.malloc()); } + BOOST_ASSERT(tstore.empty()); + pool_test_random_shuffle(vpv.begin(), vpv.end()); + + for(std::size_t i=0; i < 6; ++i) + { + tstore.ordered_free(vpv[i]); + } + // "Order-preserving" + test_is_order(tstore); + } + + /* t.malloc_n(n, partition_sz) */ + { + { + char* const pc = track_allocator::malloc(12 * partition_sz); + test_simp_seg_store tstore; + tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz); + tstore.add_ordered_block(pc + (3 * partition_sz), + 3 * partition_sz, partition_sz); + tstore.add_ordered_block(pc + (7 * partition_sz), + 5 * partition_sz, partition_sz); + + void* pvret = tstore.malloc_n(6, partition_sz); + BOOST_TEST(pvret == 0); + + pvret = tstore.malloc_n(0, partition_sz); + // There's no prohibition against asking for zero elements + BOOST_TEST(pvret == 0); + + pvret = tstore.malloc_n(3, partition_sz); + // Implicit assumption that contiguous sequence found is the first + // available while traversing from the start of the free list + BOOST_TEST(pvret == pc + (3 * partition_sz)); + + pvret = tstore.malloc_n(4, partition_sz); + BOOST_TEST(pvret == pc + (7 * partition_sz)); + + // There should still be two contiguous + // and one non-contiguous chunk left + std::size_t nchunks = 0; + while(!tstore.empty()) + { + tstore.malloc(); + ++nchunks; + } + BOOST_TEST(nchunks == 3); + } + + { + char* const pc = track_allocator::malloc(12 * partition_sz); + test_simp_seg_store tstore; + tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz); + tstore.add_ordered_block(pc + (3 * partition_sz), + 3 * partition_sz, partition_sz); + tstore.add_ordered_block(pc + (7 * partition_sz), + 5 * partition_sz, partition_sz); + + tstore.malloc_n(3, partition_sz); + // "Order-preserving" + test_is_order(tstore); + } + } + + for(std::set<char*>::iterator itr + = track_allocator::allocated_blocks.begin(); + itr != track_allocator::allocated_blocks.end(); + ++itr) + { + delete [] *itr; + } + track_allocator::allocated_blocks.clear(); + return boost::report_errors(); +} diff --git a/src/boost/libs/pool/test/test_simple_seg_storage.hpp b/src/boost/libs/pool/test/test_simple_seg_storage.hpp new file mode 100644 index 000000000..548921bb9 --- /dev/null +++ b/src/boost/libs/pool/test/test_simple_seg_storage.hpp @@ -0,0 +1,173 @@ +/* Copyright (C) 2000, 2001 Stephen Cleary +* Copyright (C) 2011 Kwan Ting Chan +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +#ifndef BOOST_POOL_TEST_SIMP_SEG_STORE_HPP +#define BOOST_POOL_TEST_SIMP_SEG_STORE_HPP + +#include <boost/pool/simple_segregated_storage.hpp> +#include <boost/assert.hpp> + +#include <boost/detail/lightweight_test.hpp> + +#include <functional> +#include <set> +#include <utility> +#include <vector> + +#include <cstddef> + +class test_simp_seg_store : public boost::simple_segregated_storage<std::size_t> +{ +private: + // ::first is the address of the start of the added block, + // ::second is the size in bytes of the added block + std::vector<std::pair<void*, std::size_t> > allocated_blocks; + size_type np_sz; + std::set<void*> allocated_chunks; + + void set_partition_size(const size_type sz) + { + if(allocated_blocks.empty()) + { + np_sz = sz; + } + else + { + BOOST_ASSERT(np_sz == sz); + } + } + + // Return: true if chunk is from added blocks, false otherwise + bool is_inside_allocated_blocks(void* const chunk) const + { + typedef std::vector<std::pair<void*, std::size_t> >::const_iterator + VPIter; + for(VPIter iter = allocated_blocks.begin(); + iter != allocated_blocks.end(); + ++iter) + { + if( std::less_equal<void*>()(iter->first, chunk) + && std::less_equal<void*>()(static_cast<char*>(chunk) + np_sz, + static_cast<char*>(iter->first) + iter->second) ) + { + return true; + } + } + + return false; + } + + void check_in(void* const chunk) + { + // Check that the newly allocated chunk has not already previously + // been allocated, and that the memory does not overlap with + // previously allocated chunks + for(std::set<void*>::const_iterator iter = allocated_chunks.begin(); + iter != allocated_chunks.end(); + ++iter) + { + BOOST_TEST( std::less_equal<void*>()(static_cast<char*>(chunk) + + np_sz, *iter) + || std::less_equal<void*>()(static_cast<char*>(*iter) + + np_sz, chunk) ); + } + + allocated_chunks.insert(chunk); + } + + void check_out(void* const chunk) + { + BOOST_TEST(allocated_chunks.erase(chunk) == 1); + } + +public: + test_simp_seg_store() + : np_sz(0) {} + + void* get_first() { return first; } + static void*& get_nextof(void* const ptr) { return nextof(ptr); } + + // (Test) Pre: npartition_sz of all added block is the same + // different blocks of memory does not overlap + void add_block(void* const block, + const size_type nsz, const size_type npartition_sz) + { + set_partition_size(npartition_sz); + allocated_blocks.push_back( + std::pair<void*, std::size_t>(block, nsz) ); + boost::simple_segregated_storage<std::size_t>::add_block( + block, nsz, npartition_sz ); + // Post: !empty() + BOOST_TEST(!empty()); + } + + // (Test) Pre: npartition_sz of all added block is the same + // different blocks of memory does not overlap + void add_ordered_block(void* const block, + const size_type nsz, const size_type npartition_sz) + { + set_partition_size(npartition_sz); + allocated_blocks.push_back( + std::pair<void*, std::size_t>(block, nsz) ); + boost::simple_segregated_storage<std::size_t>::add_ordered_block( + block, nsz, npartition_sz ); + // Post: !empty() + BOOST_TEST(!empty()); + } + + void* malloc() + { + void* const ret + = boost::simple_segregated_storage<std::size_t>::malloc(); + // Chunk returned should actually be from added blocks + BOOST_TEST(is_inside_allocated_blocks(ret)); + check_in(ret); + return ret; + } + + void free(void* const chunk) + { + BOOST_ASSERT(chunk); + check_out(chunk); + boost::simple_segregated_storage<std::size_t>::free(chunk); + // Post: !empty() + BOOST_TEST(!empty()); + } + + void ordered_free(void* const chunk) + { + BOOST_ASSERT(chunk); + check_out(chunk); + boost::simple_segregated_storage<std::size_t>::ordered_free(chunk); + // Post: !empty() + BOOST_TEST(!empty()); + } + + void* malloc_n(size_type n, size_type partition_size) + { + void* const ret + = boost::simple_segregated_storage<std::size_t>::malloc_n( + n, partition_size ); + + if(ret) + { + for(std::size_t i=0; i < n; ++i) + { + void* const chunk = static_cast<char*>(ret) + + (i * partition_size); + // Memory returned should actually be from added blocks + BOOST_TEST(is_inside_allocated_blocks(chunk)); + check_in(chunk); + } + } + + return ret; + } +}; + +#endif // BOOST_POOL_TEST_SIMP_SEG_STORE_HPP diff --git a/src/boost/libs/pool/test/test_threading.cpp b/src/boost/libs/pool/test/test_threading.cpp new file mode 100644 index 000000000..f01fea32a --- /dev/null +++ b/src/boost/libs/pool/test/test_threading.cpp @@ -0,0 +1,80 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +#include <iostream> +#include <boost/pool/pool_alloc.hpp> +#include <boost/thread.hpp> +#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600) +#pragma warning(push) +#pragma warning(disable: 4244) +// ..\..\boost/random/uniform_int_distribution.hpp(171) : +// warning C4127: conditional expression is constant +#pragma warning(disable: 4127) +// ..\..\boost/random/detail/polynomial.hpp(315) : +// warning C4267: 'argument' : conversion from 'size_t' +// to 'int', possible loss of data +#pragma warning(disable: 4267) +#endif +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int_distribution.hpp> +#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600) +#pragma warning(pop) +#endif + +void run_tests() +{ + boost::random::mt19937 gen; + boost::random::uniform_int_distribution<> dist(-10, 10); + std::list<int, boost::fast_pool_allocator<int> > l; + + for(int i = 0; i < 100; ++i) + l.push_back(i); + + for(int i = 0; i < 20000; ++i) + { + int val = dist(gen); + if(val < 0) + { + while(val && l.size()) + { + l.pop_back(); + ++val; + } + } + else + { + while(val) + { + l.push_back(val); + --val; + } + } + } +} + +int main() +{ + std::list<boost::shared_ptr<boost::thread> > threads; + for(int i = 0; i < 10; ++i) + { + try{ + threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(&run_tests))); + } + catch(const std::exception& e) + { + std::cerr << "<note>Thread creation failed with message: " << e.what() << "</note>" << std::endl; + } + } + std::list<boost::shared_ptr<boost::thread> >::const_iterator a(threads.begin()), b(threads.end()); + while(a != b) + { + (*a)->join(); + ++a; + } + return 0; +} + diff --git a/src/boost/libs/pool/test/test_valgrind_fail_1.cpp b/src/boost/libs/pool/test/test_valgrind_fail_1.cpp new file mode 100644 index 000000000..43e749742 --- /dev/null +++ b/src/boost/libs/pool/test/test_valgrind_fail_1.cpp @@ -0,0 +1,22 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// Test of bug #2656 (https://svn.boost.org/trac/boost/ticket/2656) + +#include <boost/pool/pool.hpp> +#include <iostream> +#include <iomanip> + +static const int magic_value = 0x12345678; + +int main() +{ + boost::pool<> p(sizeof(int)); + int* ptr = static_cast<int*>((p.malloc)()); + std::cout << *ptr << std::endl; // uninitialized read + return 0; +} diff --git a/src/boost/libs/pool/test/test_valgrind_fail_2.cpp b/src/boost/libs/pool/test/test_valgrind_fail_2.cpp new file mode 100644 index 000000000..84b703b7b --- /dev/null +++ b/src/boost/libs/pool/test/test_valgrind_fail_2.cpp @@ -0,0 +1,20 @@ +/* Copyright (C) 2011 John Maddock +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +// Test of bug #2656 (https://svn.boost.org/trac/boost/ticket/2656) + +#include <boost/pool/pool.hpp> + +int main() +{ + boost::pool<> p(sizeof(int)); + int* ptr = static_cast<int*>((p.malloc)()); + *ptr = 0; + (p.free)(ptr); + *ptr = 2; // write to freed memory + return 0; +} diff --git a/src/boost/libs/pool/test/track_allocator.hpp b/src/boost/libs/pool/test/track_allocator.hpp new file mode 100644 index 000000000..ed989f048 --- /dev/null +++ b/src/boost/libs/pool/test/track_allocator.hpp @@ -0,0 +1,104 @@ +/* Copyright (C) 2000, 2001 Stephen Cleary +* Copyright (C) 2011 Kwan Ting Chan +* +* Use, modification and distribution is subject to the +* Boost Software License, Version 1.0. (See accompanying +* file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +*/ + +#ifndef BOOST_POOL_TRACK_ALLOCATOR_HPP +#define BOOST_POOL_TRACK_ALLOCATOR_HPP + +#include <boost/detail/lightweight_test.hpp> + +#include <new> +#include <set> +#include <stdexcept> + +#include <cstddef> + +// Each "tester" object below checks into and out of the "cdtor_checker", +// which will check for any problems related to the construction/destruction of +// "tester" objects. +class cdtor_checker +{ +private: + // Each constructed object registers its "this" pointer into "objs" + std::set<void*> objs; + +public: + // True iff all objects that have checked in have checked out + bool ok() const { return objs.empty(); } + + ~cdtor_checker() + { + BOOST_TEST(ok()); + } + + void check_in(void * const This) + { + BOOST_TEST(objs.find(This) == objs.end()); + objs.insert(This); + } + + void check_out(void * const This) + { + BOOST_TEST(objs.find(This) != objs.end()); + objs.erase(This); + } +}; +static cdtor_checker mem; + +struct tester +{ + tester(bool throw_except = false) + { + if(throw_except) + { + throw std::logic_error("Deliberate constructor exception"); + } + + mem.check_in(this); + } + + tester(const tester &) + { + mem.check_in(this); + } + + ~tester() + { + mem.check_out(this); + } +}; + +// Allocator that registers alloc/dealloc to/from the system memory +struct track_allocator +{ + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static std::set<char*> allocated_blocks; + + static char* malloc(const size_type bytes) + { + char* const ret = new (std::nothrow) char[bytes]; + allocated_blocks.insert(ret); + return ret; + } + + static void free(char* const block) + { + BOOST_TEST(allocated_blocks.find(block) != allocated_blocks.end()); + allocated_blocks.erase(block); + delete [] block; + } + + static bool ok() + { + return allocated_blocks.empty(); + } +}; +std::set<char*> track_allocator::allocated_blocks; + +#endif // BOOST_POOL_TRACK_ALLOCATOR_HPP diff --git a/src/boost/libs/pool/test/valgrind_config_check.cpp b/src/boost/libs/pool/test/valgrind_config_check.cpp new file mode 100644 index 000000000..35252eefa --- /dev/null +++ b/src/boost/libs/pool/test/valgrind_config_check.cpp @@ -0,0 +1,7 @@ + +#include <valgrind/valgrind.h> + +int main() +{ + return 0; +}
\ No newline at end of file |