mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-09 04:49:39 -10:00
256 lines
7.3 KiB
C++
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
|