File: safe_strings_test.cpp

package info (click to toggle)
freespace2 3.7.4%2Brepack-1.1
  • links: PTS, VCS
  • area: non-free
  • in suites: bullseye
  • size: 22,268 kB
  • sloc: cpp: 393,535; ansic: 4,106; makefile: 1,091; xml: 181; sh: 137
file content (255 lines) | stat: -rw-r--r-- 7,507 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/* It is a condition of use that safe_strings.cpp, safe_strings.h, safe_strings_test.cpp remain together.
 *
 * Maintained by portej05 - contact via PM on www.hard-light.net/forums
 * Why have we got this, what is it for?
 * VC2005+ define some safe string functions which check buffer sizes before doing anything
 * Unfortunately, GCC and MACOS do not provide these functions, therefore, we must!
 * (if only to reduce the amount of noise the static analysis tools are spitting out)
 * They are part of ISO/IEC TR 24731 and may find their way into the CRTs at some point, at which
 * point these functions must be removed from the engine.
 * While these functions do not add a huge amount of benefit for heap-allocated strings, they
 * can protect against a class of buffer overruns in stack allocated situations.
 *
 */

#ifdef SAFESTRINGS_TEST_APP

#include <stdio.h>
#include <errno.h>
#include "safe_strings.h"

int last_errno = 0;
void error_handler( int errnoValue, const char* errnoStr, const char* file, const char* function, int line )
{
	last_errno = errnoValue;
	(errnoStr);
	(file);
	(function);
	(line);
}

#define _RESET_ERRNO( ) last_errno = 0

#define _EXPECTED_ERRNO( errnoVal ) if ( last_errno != errnoVal ) printf("errno value of %d not found: %d %s(%d)\n",errnoVal,last_errno,__FILE__,__LINE__)
#define _EXPECTED_LAST_ERRNO( errnoVal ) _EXPECTED_ERRNO( errnoVal )
#define _EXPECTED_RETURN( value, function ) if ( function != value ) printf("expected value not received: %s(%d)\n", __FILE__,__LINE__)

#define _EXPECTED_STRING( str, value ) if ( !strcmp( str, value ) ) printf("strings do not match: %s(%d)\n", __FILE__, __LINE__)
#define _EXPECTED_VALUE( val, value ) if ( val != value ) printf("values do not match: %s(%d)\n", __FILE__, __LINE__ )

/* Dumb memset (because we can't include string.h in this program) */
void dumb_memset( void* buf, char val, size_t bytes )
{
	char* p = (char*)buf;

	while ( bytes-- )
	{
		*(p++) = val;
	}
}

bool strcmp( const char* str1, const char* str2 )
{
	while ( *str1 && *str2 )
	{
		if ( *str1 != *str2 )
			return false;
		str1++;
		str2++;
	}

	return ( !*str1 && !*str2 );
}

void test_strcpy_s( )
{
#define _RESET_STRINGS( ) dumb_memset( strSource, 0, 15 );\
						  dumb_memset( strDest, 0, 15 );

	char strSource[ 15 ];
	char strDest[ 15 ];

	/* strcpy_s tests
	 * Must test both strcpy_s functions (even though one calls the other)
	 * 1) Copy string into larger buffer
	 *    - Expecting buffer to contain string + NULL
	 * 2) Attempt to copy string into too small buffer
	 *    - strDest[0] = NULL
	 *    - calls __safe_strings_error_handler with ERANGE
	 *    - returns ERANGE
	 * 3) strSource = NULL
	 *    - returns EINVAL
	 *    - calls __safe_strings_error_handler with EINVAL
	 *    - strDest[0] = NULL
	 * 4) strDest = NULL
	 *    - calls __safe_strings_error_handler with EINVAL
	 *    - returns EINVAL
	 * 5) strSource = NULL, strDest = NULL
	 *    - calls __safe_strings_error_handler with EINVAL
	 *	  - returns EINVAL
	 * 6) sizeInBytes = 0
	 *	  - calls __safe_strings_error_handler with ERANGE
	 *    - returns ERANGE
	 * 7) A string with the size+NULL the same as the size of the buffer
	 *    - returns 0
	 *    - strDest should contain the string
	 */

	_RESET_ERRNO( );

	/* 1 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello World" ) );
	_EXPECTED_LAST_ERRNO( 0 );
	_EXPECTED_STRING( strDest, "Hello World" );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello World" ) );
	_EXPECTED_LAST_ERRNO( 0 );
	_EXPECTED_STRING( strDest, "Hello World" );


	/* 2 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( ERANGE, strcpy_s( strDest, "Hello World, this is a test" ) );
	_EXPECTED_ERRNO( ERANGE );
	_EXPECTED_VALUE( strDest[ 0 ], NULL );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( ERANGE, strcpy_s( strDest, 15, "Hello World, this is a test" ) );
	_EXPECTED_ERRNO( ERANGE );
	_EXPECTED_VALUE( strDest[ 0 ], NULL );

	/* 3 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( EINVAL, strcpy_s( strDest, NULL ) );
	_EXPECTED_ERRNO( EINVAL );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( EINVAL, strcpy_s( strDest, 15, NULL ) );
	_EXPECTED_ERRNO( EINVAL );

	/* 4 - can't be done on template version */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( EINVAL, strcpy_s( NULL, 15, "Hello World" ) );
	_EXPECTED_ERRNO( EINVAL );

	/* 5 - can't be done on template version */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( EINVAL, strcpy_s( NULL, 15, NULL ) );
	_EXPECTED_ERRNO( EINVAL );

	/* 6 - can't be done on strcpy_s template version */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( ERANGE, strcpy_s( strDest, 0, "Hello World") );
	_EXPECTED_ERRNO( ERANGE );

	/* 7 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello World th" ) );
	_EXPECTED_LAST_ERRNO( ERANGE );

#undef _RESET_STRINGS
}

void test_strcat_s( )
{
#define _RESET_STRINGS( ) dumb_memset( strSource, 0, 15 );\
						  dumb_memset( strDest, 0, 15 );

	char strSource[ 15 ];
	char strDest[ 15 ];

	/* Test cases for strcat_s
	 * 1) Normal concatenation where total string size < buffersize -1
	 *    - No change in errno (i.e. handler is not called)
	 *    - returns 0
	 * 2) strSource = NULL, sizeInBytes != 0, strDest != NULL
	 *    - errno now EINVAL
	 *    - strDest[ 0 ] == NULL
	 *    - returns EINVAL
	 * 3) strSource != NULL, sizeInBytes != 0, strDest == NULL
	 *    - errno now EINVAL
	 *    - returns EINVAL
	 * 4) sizeInBytes = 0
	 *    - errno now ERANGE
	 *    - returns ERANGE
	 * 5) final string that is 15 chars+null
	 *    - returns 0
	 *    - no change in errno
	 */

	_RESET_ERRNO( );

	/* 1 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello " ) );
	_EXPECTED_LAST_ERRNO( 0 );
	_EXPECTED_RETURN( 0, strcat_s( strDest, "World" ) );
	_EXPECTED_LAST_ERRNO( 0 );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
	_EXPECTED_LAST_ERRNO( 0 );
	_EXPECTED_RETURN( 0, strcat_s( strDest, 15, "World" ) );
	_EXPECTED_LAST_ERRNO( 0 );
	
	/* 2 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "World" ) );
	_EXPECTED_LAST_ERRNO(  0);
	_EXPECTED_RETURN( EINVAL, strcat_s( strDest, NULL ) );
	_EXPECTED_ERRNO( EINVAL );
	_EXPECTED_VALUE( strDest[ 0 ], NULL );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "World" ) );
	_EXPECTED_LAST_ERRNO( EINVAL );
	_EXPECTED_RETURN( EINVAL, strcat_s( strDest, 15, NULL ) );
	_EXPECTED_ERRNO( EINVAL );
	_EXPECTED_VALUE( strDest[ 0 ], NULL );

	/* 3 - can't be done with templated version */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strSource, "Hello " ) );
	_EXPECTED_LAST_ERRNO( EINVAL );
	_EXPECTED_RETURN( EINVAL, strcat_s( NULL, 15, strSource ) );
	_EXPECTED_ERRNO( EINVAL );

	/* 4 - can't be done with templated version*/
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
	_EXPECTED_LAST_ERRNO( EINVAL );
	_EXPECTED_RETURN( ERANGE, strcat_s( strDest, 0, "World" ) );
	_EXPECTED_ERRNO( ERANGE );	

	/* 5 */
	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello " ) );
	_EXPECTED_LAST_ERRNO( ERANGE );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, "World th" ) );
	_EXPECTED_LAST_ERRNO( ERANGE );

	_RESET_STRINGS( );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
	_EXPECTED_LAST_ERRNO( ERANGE );
	_EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "World th" ) );
	_EXPECTED_LAST_ERRNO( ERANGE );

#undef _RESET_STRINGS
}

int main(int argc, char* argv[])
{
	(argc);
	(argv);

	test_strcpy_s( );
	test_strcat_s( );

	printf("done.\n");

	return 0;
}

#endif