ztring.c: A few important extension for <string.h>
 All Classes Files Functions Variables Enumerator Friends Macros
zchz.h
Go to the documentation of this file.
1 // zchz.h (c) 2014 adolfo@di-mare.com
2 
3 /** \file zchz.h
4  \brief Surrounded memory block used to detect unbounded string copies.
5 
6  This class is useful to check that no memory overruns occur in C programs.
7  Even though this is a C++ class, it can be used to test C programs.
8 
9  \author Adolfo Di Mare <adolfo@di-mare.com>
10  \date 2014
11 */
12 
13 #ifndef zchz_h
14 #define zchz_h ///< Avoid multiple inclusion
15 
16 // #include <cstddef> // size_t
17 #include <iostream> // cout
18 #include <climits> // UCHAR_MAX && size_t
19 #include <cstring> // strlen()
20 
21 /// Contains a memory block of 'SIZE' characters in
22 /// between 3 memory blocks of that same 'zchz::SIZE'.
23 /// The stored value can be retrieved using 'operator char*()'
24 /// and it is aligned to an 16 byte word.
25 class zchz {
26  enum {
27  SIZE = 200, ///< Max block size (change it if you need more)
28  adjust_SIZE = (SIZE+1)*16,
29  /// Size of the allocated block for any 'zchz'
30  real_SIZE = ( SIZE%16==0 ? SIZE : adjust_SIZE/16 ),
31  RZ = real_SIZE///< Abreviation for real_SIZE
32  };
33 
34  int m_errno; ///< Error code.
35  size_t m_idx; ///< Current offset for pointer access.
36  size_t m_size; ///< Current size of stored value.
37  char m_block[3*real_SIZE]; ///< Stored string value.
38 public:
39  zchz(size_t n) : m_errno(0),m_size(0) { set( n ); } ///< Constructor
40  zchz(const char * str) : m_errno(0),m_size(0) { set(str); } ///< Constructor
41 
42  size_t strsz() const { return m_size; } ///< Get current block size
43  zchz& operator++(); ///< ++p
44  zchz& operator+=( size_t n ); // p+=4;
45  char& operator[]( size_t i ); // str[i]
46  operator char*(); // no-const conversion
47  operator const char*() const; // const conversion
48  friend ptrdiff_t operator-( char* l, zchz& r ); // pointer arithmetic
49  friend ptrdiff_t operator-( zchz& l, char* r );
50  friend char* operator+( zchz& l , int i );
51 private:
52  void set( size_t size ); // Internal block will be of size 'size'
53  void set( const char * str ); // Set to string
54 
55  void reset_filling(); // rested surrounding blocks
56  void check(); // check invariant
57 
58  enum { // check() error codes
66  };
67 };
68 
69 int rand( long & seed );
70 
71 /// Checks whether the memory around the string value holds
72 /// the value stored method set().
73 /// When this method returns 'false' it usually means that
74 /// a memory lick happened.
75 /// Resets to zero the current error number 'm_errno'.
76 inline void zchz::check() {
77  if ( m_errno!=0 ) { // error detected in previous method invocation
78  std::cout << "zchz->errno[ ";
79  switch (m_errno) {
80  case before_overwrite : std::cout << "Before overwrite"; break;
81  case after_overwrite : std::cout << "After overwrite"; break;
82  case size_is_0_or_too_large : std::cout << "Size is 0 or too large"; break;
83  case pointer_out_of_bounce : std::cout << "Pointer out of bounce"; break;
84  case index_out_of_bounce : std::cout << "Index out of bounce"; break;
85  case invalid_pointer_difference : std::cout <<" Invalid pointer difference"; break;
86  default: std::cout << "Unknow error"; break;
87  }
88  std::cout << "] \n";
89  m_errno = 0;
90  }
91  long seed = ( (SIZE<=0) ? 1-SIZE : SIZE );
92  char * before = m_block;
93  char * after = (m_block+SIZE) + m_size;
94  for ( size_t i=0; i<SIZE; ++i ) {
95  char next = rand(seed) % UCHAR_MAX;
96  if ( before[i] != next ) {
98  reset_filling();
99  return;
100  }
101  if ( after[i] != next ) {
103  reset_filling();
104  return;
105  }
106  }
107 }
108 
109 /// Initializes the block that surroung the stored value.
110 inline void zchz::reset_filling() {
111  long seed = ( (SIZE<=0) ? 1-SIZE : SIZE );
112  char * before = m_block;
113  char * after = (m_block+SIZE) + m_size;
114  for ( size_t i=0; i<SIZE; ++i ) {
115  char next = rand(seed) % UCHAR_MAX;
116  before[i] = next;
117  after[i] = next;
118  }
119 }
120 
121 /// Set the internal will have size equal to 'size'.
122 /// No char value is used for initializing the memory block.
123 /// When 'size' is too big or zero, the block size is set to 'SIZE'.
124 inline void zchz::set( size_t size ) {
125  if ( m_errno!=0 && m_size!=0 ) {
126  // only the constructors set this 2 values to 0
127  // - this is a mark to avoid invoking check() on construction
128  check();
129  }
130  if ( 0<size && size<=SIZE ) {
131  m_size = size;
132  m_errno = 0;
133  }
134  else {
135  m_size = SIZE;
137  }
138  m_idx = 0;
139  reset_filling();
140 }
141 
142 /// Set the internal block to the value to 'str'.
143 /// The for the block will be 1+strlen(str).
144 /// When 'size' is too big no memory size adjusted is performed
145 /// and the string is not copied.
146 inline void zchz::set( const char * str ) {
147  set( 1+strlen(str) );
148  memcpy( (m_block+SIZE), str , m_size );
149 }
150 
152  check();
153  ++m_idx;
154  if ( m_idx > m_size ) {
155  m_idx = m_size;
157  }
158  return *this;
159 }
160 
161 /// ZCHZ[i].
162 /// When 'i' is too big, returns ZCHZ[ ZCHZ.strsz() ]
163 /// (one past the final character).
164 /// ZCHZ[ ZCHZ.strsz() ] is not flagged as an invalid reference
165 /// (but changing that character will be flagged later).
166 inline zchz& zchz::operator+=( size_t n ) {
167  check();
168  m_idx += n;
169  if ( m_idx > m_size ) {
170  m_idx = m_size ;
172  }
173  return *this;
174 }
175 
176 /// ZCHZ += i.
177 /// When 'i' is too big, ZCHZ will point to ZCHZ[ ZCHZ.strsz() ]
178 /// (one past the final character).
179 /// ZCHZ[ ZCHZ.strsz() ] is not flagged as an invalid reference
180 /// (but changing that character will be flagged later).
181 inline char& zchz::operator[]( size_t i ) {
182  check();
183  if ( m_idx+i > m_size ) {
185  return * ( (m_block+SIZE) + m_size );
186  }
187  else {
188  return * ( (m_block+SIZE) + (m_idx+i) );
189  }
190 }
191 
192 /// Returns the stored string (non-const operator).
193 inline zchz::operator char*() {
194  check();
195  return (m_block+SIZE) + m_idx;
196 }
197 
198 /// Returns the stored string (const operator).
199 inline zchz::operator const char*() const {
200  ( const_cast<zchz*>(this) ) -> check();
201  return (m_block+SIZE) + m_idx;
202 }
203 
204 inline ptrdiff_t operator-( char *l, zchz& r ) {
205  r.check();
206  char *view = r.m_block;
207  view += r.m_idx;
208  ptrdiff_t diff = l - ( (r.m_block+zchz::SIZE) + r.m_idx );
209 
210  if ( diff<0 ) {
211  diff = 0;
213  }
214  else if( diff > ptrdiff_t(r.m_size) ) {
215  diff = r.m_size;
217  }
218  return diff;
219 }
220 
221 inline ptrdiff_t operator-( zchz& l , char *r ) {
222  l.check();
223  ptrdiff_t diff = ( (l.m_block+zchz::SIZE) + l.m_idx ) - r;
224 
225  if ( diff<0 ) {
226  diff = 0;
228  }
229  else if( diff > ptrdiff_t(l.m_size) ) {
230  diff = l.m_size;
232  }
233  return diff;
234 }
235 
236 inline char* operator+( zchz& l , int i ) {
237  l.check();
238  char * ret = (l.m_block+zchz::SIZE) + l.m_idx;
239  ret += i;
240  ptrdiff_t diff = ret - (l.m_block+zchz::SIZE);
241  if ( diff<0 ) {
242  ret = (l.m_block+zchz::SIZE);
244  }
245  else if( diff > ptrdiff_t(l.m_size) ) {
246  ret = (l.m_block+zchz::SIZE) + l.m_size;
248  }
249  return ret;
250 }
251 
252 /// Used 'seed' to generate the next random number.
253 inline int rand( long & seed ) {
254  #if ( INT_MAX <= 32767 )
255  // Borland v3.1 rand()
256  seed = 22,695,477 * seed + 1;
257  return ((int)(seed >> 16) & 0x7fff);
258  #else
259  const int a = 16807;
260  const int m = 2147483647; // 2^31-1
261  const int q = m / a; // 127773
262  const int r = m % a; // 2836
263  {
264  int lo, hi, test;
265 
266  hi = seed / q;
267  lo = seed % q;
268  test = a * lo - r * hi;
269  seed = ( test>0 ? test : test+m );
270  return seed;
271  }
272  #endif
273 }
274 
275 /*
276  #include <errno.h>
277  argument_out_of_domain = EDOM, // Mathematics argument out of domain of function
278  bad_address = EFAULT,
279  invalid_argument = EINVAL,
280  result_out_of_range = ERANGE, // Result too large
281  value_too_large = EOVERFLOW // Value too large to be stored in data type
282 */
283 /*
284  Why ALL methods are declared 'inline'
285 
286  This is a trick to avoid implementing class 'zchz' using 2 files (zchz.h
287  && zchz.cpp)
288 
289  This makes the compiler responsible for removing duplicate object
290  modules when this header file is included in more than one source [.cpp]
291  files.
292 */
293 #endif
294 
295 // EOF: zchz.h
friend char * operator+(zchz &l, int i)
Definition: zchz.h:236
void check()
Checks whether the memory around the string value holds the value stored method set().
Definition: zchz.h:76
friend ptrdiff_t operator-(char *l, zchz &r)
Definition: zchz.h:204
Size of the allocated block for any 'zchz'.
Definition: zchz.h:30
int rand(long &seed)
Used 'seed' to generate the next random number.
Definition: zchz.h:253
ptrdiff_t operator-(char *l, zchz &r)
Definition: zchz.h:204
size_t m_idx
Current offset for pointer access.
Definition: zchz.h:35
char m_block[3 *real_SIZE]
Stored string value.
Definition: zchz.h:37
size_t strsz() const
Get current block size.
Definition: zchz.h:42
zchz & operator++()
++p
Definition: zchz.h:151
Contains a memory block of 'SIZE' characters in between 3 memory blocks of that same 'zchz::SIZE'...
Definition: zchz.h:25
char & operator[](size_t i)
ZCHZ += i.
Definition: zchz.h:181
int m_errno
Error code.
Definition: zchz.h:34
size_t m_size
Current size of stored value.
Definition: zchz.h:36
zchz(size_t n)
Constructor.
Definition: zchz.h:39
Abreviation for real_SIZE.
Definition: zchz.h:31
zchz(const char *str)
Constructor.
Definition: zchz.h:40
zchz & operator+=(size_t n)
ZCHZ[i].
Definition: zchz.h:166
void reset_filling()
Initializes the block that surroung the stored value.
Definition: zchz.h:110
Max block size (change it if you need more)
Definition: zchz.h:27
char * operator+(zchz &l, int i)
Definition: zchz.h:236
void set(size_t size)
Set the internal will have size equal to 'size'.
Definition: zchz.h:124