1 /* It is a condition of use that safe_strings.cpp, safe_strings.h, safe_strings_test.cpp remain together.
2 *
3 * Maintained by portej05 - contact via PM on www.hard-light.net/forums
4 * Why have we got this, what is it for?
5 * VC2005+ define some safe string functions which check buffer sizes before doing anything
6 * Unfortunately, GCC and MACOS do not provide these functions, therefore, we must!
7 * (if only to reduce the amount of noise the static analysis tools are spitting out)
8 * They are part of ISO/IEC TR 24731 and may find their way into the CRTs at some point, at which
9 * point these functions must be removed from the engine.
10 * While these functions do not add a huge amount of benefit for heap-allocated strings, they
11 * can protect against a class of buffer overruns in stack allocated situations.
12 *
13 */
14
15 #ifdef SAFESTRINGS_TEST_APP
16
17 #include <stdio.h>
18 #include <errno.h>
19 #include "safe_strings.h"
20
21 int last_errno = 0;
error_handler(int errnoValue,const char * errnoStr,const char * file,const char * function,int line)22 void error_handler( int errnoValue, const char* errnoStr, const char* file, const char* function, int line )
23 {
24 last_errno = errnoValue;
25 (errnoStr);
26 (file);
27 (function);
28 (line);
29 }
30
31 #define _RESET_ERRNO( ) last_errno = 0
32
33 #define _EXPECTED_ERRNO( errnoVal ) if ( last_errno != errnoVal ) printf("errno value of %d not found: %d %s(%d)\n",errnoVal,last_errno,__FILE__,__LINE__)
34 #define _EXPECTED_LAST_ERRNO( errnoVal ) _EXPECTED_ERRNO( errnoVal )
35 #define _EXPECTED_RETURN( value, function ) if ( function != value ) printf("expected value not received: %s(%d)\n", __FILE__,__LINE__)
36
37 #define _EXPECTED_STRING( str, value ) if ( !strcmp( str, value ) ) printf("strings do not match: %s(%d)\n", __FILE__, __LINE__)
38 #define _EXPECTED_VALUE( val, value ) if ( val != value ) printf("values do not match: %s(%d)\n", __FILE__, __LINE__ )
39
40 /* Dumb memset (because we can't include string.h in this program) */
dumb_memset(void * buf,char val,size_t bytes)41 void dumb_memset( void* buf, char val, size_t bytes )
42 {
43 char* p = (char*)buf;
44
45 while ( bytes-- )
46 {
47 *(p++) = val;
48 }
49 }
50
strcmp(const char * str1,const char * str2)51 bool strcmp( const char* str1, const char* str2 )
52 {
53 while ( *str1 && *str2 )
54 {
55 if ( *str1 != *str2 )
56 return false;
57 str1++;
58 str2++;
59 }
60
61 return ( !*str1 && !*str2 );
62 }
63
test_strcpy_s()64 void test_strcpy_s( )
65 {
66 #define _RESET_STRINGS( ) dumb_memset( strSource, 0, 15 );\
67 dumb_memset( strDest, 0, 15 );
68
69 char strSource[ 15 ];
70 char strDest[ 15 ];
71
72 /* strcpy_s tests
73 * Must test both strcpy_s functions (even though one calls the other)
74 * 1) Copy string into larger buffer
75 * - Expecting buffer to contain string + NULL
76 * 2) Attempt to copy string into too small buffer
77 * - strDest[0] = NULL
78 * - calls __safe_strings_error_handler with ERANGE
79 * - returns ERANGE
80 * 3) strSource = NULL
81 * - returns EINVAL
82 * - calls __safe_strings_error_handler with EINVAL
83 * - strDest[0] = NULL
84 * 4) strDest = NULL
85 * - calls __safe_strings_error_handler with EINVAL
86 * - returns EINVAL
87 * 5) strSource = NULL, strDest = NULL
88 * - calls __safe_strings_error_handler with EINVAL
89 * - returns EINVAL
90 * 6) sizeInBytes = 0
91 * - calls __safe_strings_error_handler with ERANGE
92 * - returns ERANGE
93 * 7) A string with the size+NULL the same as the size of the buffer
94 * - returns 0
95 * - strDest should contain the string
96 */
97
98 _RESET_ERRNO( );
99
100 /* 1 */
101 _RESET_STRINGS( );
102 _EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello World" ) );
103 _EXPECTED_LAST_ERRNO( 0 );
104 _EXPECTED_STRING( strDest, "Hello World" );
105
106 _RESET_STRINGS( );
107 _EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello World" ) );
108 _EXPECTED_LAST_ERRNO( 0 );
109 _EXPECTED_STRING( strDest, "Hello World" );
110
111
112 /* 2 */
113 _RESET_STRINGS( );
114 _EXPECTED_RETURN( ERANGE, strcpy_s( strDest, "Hello World, this is a test" ) );
115 _EXPECTED_ERRNO( ERANGE );
116 _EXPECTED_VALUE( strDest[ 0 ], NULL );
117
118 _RESET_STRINGS( );
119 _EXPECTED_RETURN( ERANGE, strcpy_s( strDest, 15, "Hello World, this is a test" ) );
120 _EXPECTED_ERRNO( ERANGE );
121 _EXPECTED_VALUE( strDest[ 0 ], NULL );
122
123 /* 3 */
124 _RESET_STRINGS( );
125 _EXPECTED_RETURN( EINVAL, strcpy_s( strDest, NULL ) );
126 _EXPECTED_ERRNO( EINVAL );
127
128 _RESET_STRINGS( );
129 _EXPECTED_RETURN( EINVAL, strcpy_s( strDest, 15, NULL ) );
130 _EXPECTED_ERRNO( EINVAL );
131
132 /* 4 - can't be done on template version */
133 _RESET_STRINGS( );
134 _EXPECTED_RETURN( EINVAL, strcpy_s( NULL, 15, "Hello World" ) );
135 _EXPECTED_ERRNO( EINVAL );
136
137 /* 5 - can't be done on template version */
138 _RESET_STRINGS( );
139 _EXPECTED_RETURN( EINVAL, strcpy_s( NULL, 15, NULL ) );
140 _EXPECTED_ERRNO( EINVAL );
141
142 /* 6 - can't be done on strcpy_s template version */
143 _RESET_STRINGS( );
144 _EXPECTED_RETURN( ERANGE, strcpy_s( strDest, 0, "Hello World") );
145 _EXPECTED_ERRNO( ERANGE );
146
147 /* 7 */
148 _RESET_STRINGS( );
149 _EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello World th" ) );
150 _EXPECTED_LAST_ERRNO( ERANGE );
151
152 #undef _RESET_STRINGS
153 }
154
test_strcat_s()155 void test_strcat_s( )
156 {
157 #define _RESET_STRINGS( ) dumb_memset( strSource, 0, 15 );\
158 dumb_memset( strDest, 0, 15 );
159
160 char strSource[ 15 ];
161 char strDest[ 15 ];
162
163 /* Test cases for strcat_s
164 * 1) Normal concatenation where total string size < buffersize -1
165 * - No change in errno (i.e. handler is not called)
166 * - returns 0
167 * 2) strSource = NULL, sizeInBytes != 0, strDest != NULL
168 * - errno now EINVAL
169 * - strDest[ 0 ] == NULL
170 * - returns EINVAL
171 * 3) strSource != NULL, sizeInBytes != 0, strDest == NULL
172 * - errno now EINVAL
173 * - returns EINVAL
174 * 4) sizeInBytes = 0
175 * - errno now ERANGE
176 * - returns ERANGE
177 * 5) final string that is 15 chars+null
178 * - returns 0
179 * - no change in errno
180 */
181
182 _RESET_ERRNO( );
183
184 /* 1 */
185 _RESET_STRINGS( );
186 _EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello " ) );
187 _EXPECTED_LAST_ERRNO( 0 );
188 _EXPECTED_RETURN( 0, strcat_s( strDest, "World" ) );
189 _EXPECTED_LAST_ERRNO( 0 );
190
191 _RESET_STRINGS( );
192 _EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
193 _EXPECTED_LAST_ERRNO( 0 );
194 _EXPECTED_RETURN( 0, strcat_s( strDest, 15, "World" ) );
195 _EXPECTED_LAST_ERRNO( 0 );
196
197 /* 2 */
198 _RESET_STRINGS( );
199 _EXPECTED_RETURN( 0, strcpy_s( strDest, "World" ) );
200 _EXPECTED_LAST_ERRNO( 0);
201 _EXPECTED_RETURN( EINVAL, strcat_s( strDest, NULL ) );
202 _EXPECTED_ERRNO( EINVAL );
203 _EXPECTED_VALUE( strDest[ 0 ], NULL );
204
205 _RESET_STRINGS( );
206 _EXPECTED_RETURN( 0, strcpy_s( strDest, "World" ) );
207 _EXPECTED_LAST_ERRNO( EINVAL );
208 _EXPECTED_RETURN( EINVAL, strcat_s( strDest, 15, NULL ) );
209 _EXPECTED_ERRNO( EINVAL );
210 _EXPECTED_VALUE( strDest[ 0 ], NULL );
211
212 /* 3 - can't be done with templated version */
213 _RESET_STRINGS( );
214 _EXPECTED_RETURN( 0, strcpy_s( strSource, "Hello " ) );
215 _EXPECTED_LAST_ERRNO( EINVAL );
216 _EXPECTED_RETURN( EINVAL, strcat_s( NULL, 15, strSource ) );
217 _EXPECTED_ERRNO( EINVAL );
218
219 /* 4 - can't be done with templated version*/
220 _RESET_STRINGS( );
221 _EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
222 _EXPECTED_LAST_ERRNO( EINVAL );
223 _EXPECTED_RETURN( ERANGE, strcat_s( strDest, 0, "World" ) );
224 _EXPECTED_ERRNO( ERANGE );
225
226 /* 5 */
227 _RESET_STRINGS( );
228 _EXPECTED_RETURN( 0, strcpy_s( strDest, "Hello " ) );
229 _EXPECTED_LAST_ERRNO( ERANGE );
230 _EXPECTED_RETURN( 0, strcpy_s( strDest, "World th" ) );
231 _EXPECTED_LAST_ERRNO( ERANGE );
232
233 _RESET_STRINGS( );
234 _EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "Hello " ) );
235 _EXPECTED_LAST_ERRNO( ERANGE );
236 _EXPECTED_RETURN( 0, strcpy_s( strDest, 15, "World th" ) );
237 _EXPECTED_LAST_ERRNO( ERANGE );
238
239 #undef _RESET_STRINGS
240 }
241
main(int argc,char * argv[])242 int main(int argc, char* argv[])
243 {
244 (argc);
245 (argv);
246
247 test_strcpy_s( );
248 test_strcat_s( );
249
250 printf("done.\n");
251
252 return 0;
253 }
254
255 #endif
256