79f21e90878dbe52182a3a20eab176e6e4dbf84e
[libcds.git] / cds / memory / michael / bound_check.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8     
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
29 */
30
31 #ifndef CDSLIB_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H
32 #define CDSLIB_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H
33
34 #include <exception>
35 #include <memory.h>
36 #include <cds/opt/options.h>
37
38 namespace cds { namespace memory { namespace michael {
39
40     //@cond
41     namespace details {
42         class bound_checker
43         {
44         protected:
45             typedef uint64_t trailer_type;
46             static const trailer_type s_BoundCheckerTrailer = 0xbadcafeedeadc0feULL;
47
48         public:
49             enum {
50                 trailer_size = sizeof(trailer_type) + sizeof(size_t)
51             };
52
53             void make_trailer( void * pStartArea, void * pEndBlock, size_t nAllocSize )
54             {
55                 char * pArea = reinterpret_cast<char *>(pStartArea);
56                 assert( reinterpret_cast<char *>(pEndBlock) - (pArea + nAllocSize) >= trailer_size );
57
58                 trailer_type trailer = s_BoundCheckerTrailer;
59                 memcpy( pArea + nAllocSize, &trailer, sizeof(trailer) );
60
61                 // the next assignment is correct because pBlock is at least sizeof(size_t)-byte aligned
62                 assert( (reinterpret_cast<uintptr_t>(pEndBlock) & (sizeof(size_t) - 1)) == 0 );
63                 *(reinterpret_cast<size_t *>( pEndBlock ) - 1) = nAllocSize;
64             }
65
66             bool check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
67             {
68                 trailer_type trailer = s_BoundCheckerTrailer;
69                 size_t nAllocSize = *(reinterpret_cast<size_t *>( pEndBlock ) - 1);
70
71                 assert( nAllocSize < nBlockSize );
72                 return nAllocSize < nBlockSize
73                     && memcmp( reinterpret_cast<char *>(pStartArea) + nAllocSize, &trailer, sizeof(trailer) ) == 0;
74             }
75         };
76     }
77     //@endcond
78
79 #if defined(CDS_DOXYGEN_INVOKED) || defined(_DEBUG)
80     /// Debug bound checker
81     /**
82         This is one of value of opt::check_bounds option for Michael's \ref Heap memory allocator.
83         It is intended for debug mode only. It throws an assertion when memory bound violation is detected.
84         In release mode it is equal to <tt>opt::check_bounds<cds::opt::none> </tt>.
85     */
86     class debug_bound_checking: public details::bound_checker
87     {
88     //@cond
89         typedef details::bound_checker  base_class;
90     public:
91         void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
92         {
93             // Bound checking assertion
94             assert( base_class::check_bounds( pStartArea, pEndBlock, nBlockSize ) );
95         }
96
97     //@endcond
98     };
99 #else
100     typedef cds::opt::none  debug_bound_checking;
101 #endif
102
103     /// Exception of \ref strong_bound_checking bound checker
104     class bound_checker_exception: public std::out_of_range
105     {
106     //@cond
107     public:
108         bound_checker_exception()
109             : std::out_of_range( "Memory bound checking violation" )
110         {}
111     //@endcond
112     };
113
114     /// Exception throwing bound checker
115     /**
116         This is one of value of opt::check_bounds option for Michael's \ref Heap memory allocator.
117         It is intended for debug and release mode.
118         When memory bound violation is detected
119             \li In debug mode - an assertion is raised
120             \li In release mode  - an exception of type \ref bound_checker_exception is thrown
121     */
122     class strong_bound_checking: public details::bound_checker
123     {
124     //@cond
125         typedef details::bound_checker  base_class;
126     public:
127         void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
128         {
129             if ( !base_class::check_bounds( pStartArea, pEndBlock, nBlockSize ) ) {
130                 throw bound_checker_exception();
131             }
132         }
133     //@endcond
134     };
135
136
137     //@cond
138     namespace details {
139         template <typename BOUND_CHECKER>
140         class bound_checker_selector: public BOUND_CHECKER
141         {
142             typedef BOUND_CHECKER base_class;
143         public:
144             enum {
145                 trailer_size = base_class::trailer_size
146             };
147
148             void make_trailer( void * pStartArea, void * pEndBlock, size_t nAllocSize )
149             {
150                 base_class::make_trailer( pStartArea, pEndBlock, nAllocSize );
151             }
152
153             void check_bounds( void * pStartArea, void * pEndBlock, size_t nBlockSize )
154             {
155                 base_class::check_bounds( pStartArea, pEndBlock, nBlockSize );
156             }
157         };
158
159         template <>
160         class bound_checker_selector<cds::opt::none>
161         {
162         public:
163             enum {
164                 trailer_size = 0
165             };
166
167             void make_trailer( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nAllocSize*/ )
168             {}
169
170             void check_bounds( void * /*pStartArea*/, void * /*pEndBlock*/, size_t /*nBlockSize*/ )
171             {}
172         };
173     }   // namespace details
174     //@endcond
175
176
177 }}} // namespace cds::memory::michael
178
179 #endif // #ifndef CDSLIB_MEMORY_MICHAEL_ALLOCATOR_BOUND_CHECK_H