Move libcds 1.6.0 from SVN
[libcds.git] / cds / memory / michael / bound_check.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H
4 #define __CDS_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H
5
6 #include <cds/opt/options.h>
7 #include <exception>
8 #include <memory.h>
9
10 namespace cds { namespace memory { namespace michael {
11
12     //@cond
13     namespace details {
14         class bound_checker
15         {
16         protected:
17             typedef atomic64u_t trailer_type;
18             static const trailer_type s_BoundCheckerTrailer = 0xbadcafeedeadc0feULL;
19
20         public:
21             enum {
22                 trailer_size = sizeof(trailer_type) + sizeof(size_t)
23             };
24
25             void make_trailer( void * pStartArea, void * pEndBlock, size_t nAllocSize )
26             {
27                 char * pArea = reinterpret_cast<char *>(pStartArea);
28                 assert( reinterpret_cast<char *>(pEndBlock) - (pArea + nAllocSize) >= trailer_size );
29
30                 trailer_type trailer = s_BoundCheckerTrailer;
31                 memcpy( pArea + nAllocSize, &trailer, sizeof(trailer) );
32
33                 // the next assignment is correct because pBlock is at least sizeof(size_t)-byte aligned
34                 assert( (reinterpret_cast<uptr_atomic_t>(pEndBlock) & (sizeof(size_t) - 1)) == 0 );
35                 *(reinterpret_cast<size_t *>( pEndBlock ) - 1) = nAllocSize;
36             }
37
38             bool check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
39             {
40                 trailer_type trailer = s_BoundCheckerTrailer;
41                 size_t nAllocSize = *(reinterpret_cast<size_t *>( pEndBlock ) - 1);
42
43                 assert( nAllocSize < nBlockSize );
44                 return nAllocSize < nBlockSize
45                     && memcmp( reinterpret_cast<char *>(pStartArea) + nAllocSize, &trailer, sizeof(trailer) ) == 0;
46             }
47         };
48     }
49     //@endcond
50
51 #if defined(CDS_DOXYGEN_INVOKED) || defined(_DEBUG)
52     /// Debug bound checker
53     /**
54         This is one of value of opt::check_bounds option for Michael's \ref Heap memory allocator.
55         It is intended for debug mode only. It throws an assertion when memory bound violation is detected.
56         In release mode it is equal to <tt>opt::check_bounds<cds::opt::none> </tt>.
57     */
58     class debug_bound_checking: public details::bound_checker
59     {
60     //@cond
61         typedef details::bound_checker  base_class;
62     public:
63         void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
64         {
65             // Bound checking assertion
66             assert( base_class::check_bounds( pStartArea, pEndBlock, nBlockSize ) );
67         }
68
69     //@endcond
70     };
71 #else
72     typedef cds::opt::none  debug_bound_checking;
73 #endif
74
75     /// %Exception of \ref strong_bound_checking bound checker
76     class bound_checker_exception: public std::exception
77     {
78     //@cond
79     public:
80         virtual const char * what() const throw()
81         {
82             return "Memory bound checking violation";
83         }
84     //@endcond
85     };
86
87     /// %Exception throwing bound checker
88     /**
89         This is one of value of opt::check_bounds option for Michael's \ref Heap memory allocator.
90         It is intended for debug and release mode.
91         When memory bound violation is detected
92             \li In debug mode - an assertion is raised
93             \li In release mode  - an exception of type \ref bound_checker_exception is thrown
94     */
95     class strong_bound_checking: public details::bound_checker
96     {
97     //@cond
98         typedef details::bound_checker  base_class;
99     public:
100         void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
101         {
102             if ( !base_class::check_bounds( pStartArea, pEndBlock, nBlockSize ) ) {
103                 throw bound_checker_exception();
104             }
105         }
106
107     //@endcond
108     };
109
110
111     //@cond
112     namespace details {
113         template <typename BOUND_CHECKER>
114         class bound_checker_selector: public BOUND_CHECKER
115         {
116             typedef BOUND_CHECKER base_class;
117         public:
118             enum {
119                 trailer_size = base_class::trailer_size
120             };
121
122             void make_trailer( void * pStartArea, void * pEndBlock, size_t nAllocSize )
123             {
124                 base_class::make_trailer( pStartArea, pEndBlock, nAllocSize );
125             }
126
127             void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
128             {
129                 base_class::check_bounds( pStartArea, pEndBlock, nBlockSize );
130             }
131         };
132
133         template <>
134         class bound_checker_selector<cds::opt::none>
135         {
136         public:
137             enum {
138                 trailer_size = 0
139             };
140
141             void make_trailer( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nAllocSize*/ )
142             {}
143
144             void check_bounds( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nBlockSize*/ )
145             {}
146         };
147     }   // namespace details
148     //@endcond
149
150
151 }}} // namespace cds::memory::michael
152
153 #endif // #ifndef __CDS_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H