aa9734ca50d7d6f33535463b193536856c358e63
[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 <exception>
7 #include <memory.h>
8 #include <cds/opt/options.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<uintptr_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::out_of_range
77     {
78     //@cond
79     public:
80         bound_checker_exception()
81             : std::out_of_range( "Memory bound checking violation" )
82         {}
83     //@endcond
84     };
85
86     /// Exception throwing bound checker
87     /**
88         This is one of value of opt::check_bounds option for Michael's \ref Heap memory allocator.
89         It is intended for debug and release mode.
90         When memory bound violation is detected
91             \li In debug mode - an assertion is raised
92             \li In release mode  - an exception of type \ref bound_checker_exception is thrown
93     */
94     class strong_bound_checking: public details::bound_checker
95     {
96     //@cond
97         typedef details::bound_checker  base_class;
98     public:
99         void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
100         {
101             if ( !base_class::check_bounds( pStartArea, pEndBlock, nBlockSize ) ) {
102                 throw bound_checker_exception();
103             }
104         }
105     //@endcond
106     };
107
108
109     //@cond
110     namespace details {
111         template <typename BOUND_CHECKER>
112         class bound_checker_selector: public BOUND_CHECKER
113         {
114             typedef BOUND_CHECKER base_class;
115         public:
116             enum {
117                 trailer_size = base_class::trailer_size
118             };
119
120             void make_trailer( void * pStartArea, void * pEndBlock, size_t nAllocSize )
121             {
122                 base_class::make_trailer( pStartArea, pEndBlock, nAllocSize );
123             }
124
125             void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
126             {
127                 base_class::check_bounds( pStartArea, pEndBlock, nBlockSize );
128             }
129         };
130
131         template <>
132         class bound_checker_selector<cds::opt::none>
133         {
134         public:
135             enum {
136                 trailer_size = 0
137             };
138
139             void make_trailer( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nAllocSize*/ )
140             {}
141
142             void check_bounds( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nBlockSize*/ )
143             {}
144         };
145     }   // namespace details
146     //@endcond
147
148
149 }}} // namespace cds::memory::michael
150
151 #endif // #ifndef __CDS_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H