Files
fs2open.github.com/code/globalincs/safe_strings_test.cpp
T

256 lines
7.3 KiB
C++

/* 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