From f018ca469439b7d73fee0103127bbed52fb4f6c2 Mon Sep 17 00:00:00 2001 From: Andreas Schiffler Date: Wed, 19 Mar 2014 21:39:55 -0700 Subject: [PATCH] Add input validation to SDL_getenv/SDL_setenv; update Stdlib testsuite; add Hints testsuite --- .../testautomation_VS2008.vcproj | 4 + .../testautomation_vs2010.vcxproj | 1 + .../testautomation_vs2012.vcxproj | 1 + .../testautomation_vs2013.vcxproj | 1 + src/stdlib/SDL_getenv.c | 35 +++- test/Makefile.in | 3 +- test/testautomation_hints.c | 168 ++++++++++++++++++ test/testautomation_stdlib.c | 141 ++++++++++++++- test/testautomation_suites.h | 2 + 9 files changed, 351 insertions(+), 5 deletions(-) create mode 100644 test/testautomation_hints.c diff --git a/VisualC/tests/testautomation/testautomation_VS2008.vcproj b/VisualC/tests/testautomation/testautomation_VS2008.vcproj index 5b5ffa66f..e6f465baa 100755 --- a/VisualC/tests/testautomation/testautomation_VS2008.vcproj +++ b/VisualC/tests/testautomation/testautomation_VS2008.vcproj @@ -271,6 +271,10 @@ RelativePath="..\..\..\test\testautomation_video.c" > + + diff --git a/VisualC/tests/testautomation/testautomation_vs2010.vcxproj b/VisualC/tests/testautomation/testautomation_vs2010.vcxproj index 3c4fe9d9f..073015951 100644 --- a/VisualC/tests/testautomation/testautomation_vs2010.vcxproj +++ b/VisualC/tests/testautomation/testautomation_vs2010.vcxproj @@ -194,6 +194,7 @@ + diff --git a/VisualC/tests/testautomation/testautomation_vs2012.vcxproj b/VisualC/tests/testautomation/testautomation_vs2012.vcxproj index a026096bc..b50329cd4 100644 --- a/VisualC/tests/testautomation/testautomation_vs2012.vcxproj +++ b/VisualC/tests/testautomation/testautomation_vs2012.vcxproj @@ -198,6 +198,7 @@ + diff --git a/VisualC/tests/testautomation/testautomation_vs2013.vcxproj b/VisualC/tests/testautomation/testautomation_vs2013.vcxproj index 7fb12228f..8bded7052 100644 --- a/VisualC/tests/testautomation/testautomation_vs2013.vcxproj +++ b/VisualC/tests/testautomation/testautomation_vs2013.vcxproj @@ -198,6 +198,7 @@ + diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index 449211064..782b8ccb0 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -33,16 +33,27 @@ static size_t SDL_envmemlen = 0; #endif /* Put a variable into the environment */ +/* Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/) */ #if defined(HAVE_SETENV) int SDL_setenv(const char *name, const char *value, int overwrite) { + /* Input validation */ + if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + return (-1); + } + return setenv(name, value, overwrite); } #elif defined(__WIN32__) int SDL_setenv(const char *name, const char *value, int overwrite) { + /* Input validation */ + if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + return (-1); + } + if (!overwrite) { char ch = 0; const size_t len = GetEnvironmentVariableA(name, &ch, sizeof (ch)); @@ -63,6 +74,11 @@ SDL_setenv(const char *name, const char *value, int overwrite) size_t len; char *new_variable; + /* Input validation */ + if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + return (-1); + } + if (getenv(name) != NULL) { if (overwrite) { unsetenv(name); @@ -91,8 +107,8 @@ SDL_setenv(const char *name, const char *value, int overwrite) char **new_env; char *new_variable; - /* A little error checking */ - if (!name || !value) { + /* Input validation */ + if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { return (-1); } @@ -152,6 +168,11 @@ SDL_setenv(const char *name, const char *value, int overwrite) char * SDL_getenv(const char *name) { + /* Input validation */ + if (!name || SDL_strlen(name)==0) { + return NULL; + } + return getenv(name); } #elif defined(__WIN32__) @@ -160,6 +181,11 @@ SDL_getenv(const char *name) { size_t bufferlen; + /* Input validation */ + if (!name || SDL_strlen(name)==0) { + return NULL; + } + bufferlen = GetEnvironmentVariableA(name, SDL_envmem, (DWORD) SDL_envmemlen); if (bufferlen == 0) { @@ -183,6 +209,11 @@ SDL_getenv(const char *name) int len, i; char *value; + /* Input validation */ + if (!name || SDL_strlen(name)==0) { + return NULL; + } + value = (char *) 0; if (SDL_env) { len = SDL_strlen(name); diff --git a/test/Makefile.in b/test/Makefile.in index bf03896fc..7ed1a7ac9 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -92,7 +92,8 @@ testautomation$(EXE): $(srcdir)/testautomation.c \ $(srcdir)/testautomation_surface.c \ $(srcdir)/testautomation_syswm.c \ $(srcdir)/testautomation_timer.c \ - $(srcdir)/testautomation_video.c + $(srcdir)/testautomation_video.c \ + $(srcdir)/testautomation_hints.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c diff --git a/test/testautomation_hints.c b/test/testautomation_hints.c new file mode 100644 index 000000000..a6beb88d7 --- /dev/null +++ b/test/testautomation_hints.c @@ -0,0 +1,168 @@ +/** + * Hints test suite + */ + +#include + +#include "SDL.h" +#include "SDL_test.h" + + +const int _numHintsEnum = 25; +char* _HintsEnum[] = + { + SDL_HINT_ACCELEROMETER_AS_JOYSTICK, + SDL_HINT_FRAMEBUFFER_ACCELERATION, + SDL_HINT_GAMECONTROLLERCONFIG, + SDL_HINT_GRAB_KEYBOARD, + SDL_HINT_IDLE_TIMER_DISABLED, + SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, + SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, + SDL_HINT_MOUSE_RELATIVE_MODE_WARP, + SDL_HINT_ORIENTATIONS, + SDL_HINT_RENDER_DIRECT3D_THREADSAFE, + SDL_HINT_RENDER_DRIVER, + SDL_HINT_RENDER_OPENGL_SHADERS, + SDL_HINT_RENDER_SCALE_QUALITY, + SDL_HINT_RENDER_VSYNC, + SDL_HINT_TIMER_RESOLUTION, + SDL_HINT_VIDEO_ALLOW_SCREENSAVER, + SDL_HINT_VIDEO_HIGHDPI_DISABLED, + SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, + SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, + SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, + SDL_HINT_VIDEO_WIN_D3DCOMPILER, + SDL_HINT_VIDEO_X11_XINERAMA, + SDL_HINT_VIDEO_X11_XRANDR, + SDL_HINT_VIDEO_X11_XVIDMODE, + SDL_HINT_XINPUT_ENABLED, + }; +char* _HintsVerbose[] = + { + "SDL_HINT_ACCELEROMETER_AS_JOYSTICK", + "SDL_HINT_FRAMEBUFFER_ACCELERATION", + "SDL_HINT_GAMECONTROLLERCONFIG", + "SDL_HINT_GRAB_KEYBOARD", + "SDL_HINT_IDLE_TIMER_DISABLED", + "SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS", + "SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK", + "SDL_HINT_MOUSE_RELATIVE_MODE_WARP", + "SDL_HINT_ORIENTATIONS", + "SDL_HINT_RENDER_DIRECT3D_THREADSAFE", + "SDL_HINT_RENDER_DRIVER", + "SDL_HINT_RENDER_OPENGL_SHADERS", + "SDL_HINT_RENDER_SCALE_QUALITY", + "SDL_HINT_RENDER_VSYNC", + "SDL_HINT_TIMER_RESOLUTION", + "SDL_HINT_VIDEO_ALLOW_SCREENSAVER", + "SDL_HINT_VIDEO_HIGHDPI_DISABLED", + "SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES", + "SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS", + "SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT", + "SDL_HINT_VIDEO_WIN_D3DCOMPILER", + "SDL_HINT_VIDEO_X11_XINERAMA", + "SDL_HINT_VIDEO_X11_XRANDR", + "SDL_HINT_VIDEO_X11_XVIDMODE", + "SDL_HINT_XINPUT_ENABLED" + }; + + +/* Test case functions */ + +/** + * @brief Call to SDL_GetHint + */ +int +hints_getHint(void *arg) +{ + char *result1; + char *result2; + int i; + + for (i=0; i<_numHintsEnum; i++) { + result1 = (char *)SDL_GetHint((char*)_HintsEnum[i]); + SDLTest_AssertPass("Call to SDL_GetHint(%s) - using define definition", (char*)_HintsEnum[i]); + result2 = (char *)SDL_GetHint((char *)_HintsVerbose[i]); + SDLTest_AssertPass("Call to SDL_GetHint(%s) - using string definition", (char*)_HintsVerbose[i]); + SDLTest_AssertCheck( + (result1 == NULL && result2 == NULL) || (SDL_strcmp(result1, result2) == 0), + "Verify returned values are equal; got: result1='%s' result2='%s", + (result1 == NULL) ? "null" : result1, + (result2 == NULL) ? "null" : result2); + } + + return TEST_COMPLETED; +} + +/** + * @brief Call to SDL_SetHint + */ +int +hints_setHint(void *arg) +{ + char *originalValue; + char *value; + char *testValue; + SDL_bool result; + int i, j; + + /* Create random values to set */ + value = SDLTest_RandomAsciiStringOfSize(10); + + for (i=0; i<_numHintsEnum; i++) { + /* Capture current value */ + originalValue = (char *)SDL_GetHint((char*)_HintsEnum[i]); + SDLTest_AssertPass("Call to SDL_GetHint(%s)", (char*)_HintsEnum[i]); + + /* Set value (twice) */ + for (j=1; j<=2; j++) { + result = SDL_SetHint((char*)_HintsEnum[i], value); + SDLTest_AssertPass("Call to SDL_SetHint(%s, %s) (iteration %i)", (char*)_HintsEnum[i], value, j); + SDLTest_AssertCheck( + result == SDL_TRUE || result == SDL_FALSE, + "Verify valid result was returned, got: %i", + (int)result); + testValue = (char *)SDL_GetHint((char*)_HintsEnum[i]); + SDLTest_AssertPass("Call to SDL_GetHint(%s) - using string definition", (char*)_HintsVerbose[i]); + SDLTest_AssertCheck( + (SDL_strcmp(value, testValue) == 0), + "Verify returned value equals set value; got: testValue='%s' value='%s", + (testValue == NULL) ? "null" : testValue, + value); + } + + /* Reset original value */ + result = SDL_SetHint((char*)_HintsEnum[i], originalValue); + SDLTest_AssertPass("Call to SDL_SetHint(%s, originalValue)", (char*)_HintsEnum[i]); + SDLTest_AssertCheck( + result == SDL_TRUE || result == SDL_FALSE, + "Verify valid result was returned, got: %i", + (int)result); + } + + SDL_free(value); + + return TEST_COMPLETED; +} + +/* ================= Test References ================== */ + +/* Hints test cases */ +static const SDLTest_TestCaseReference hintsTest1 = + { (SDLTest_TestCaseFp)hints_getHint, "hints_getHint", "Call to SDL_GetHint", TEST_ENABLED }; + +static const SDLTest_TestCaseReference hintsTest2 = + { (SDLTest_TestCaseFp)hints_setHint, "hints_setHint", "Call to SDL_SetHint", TEST_ENABLED }; + +/* Sequence of Hints test cases */ +static const SDLTest_TestCaseReference *hintsTests[] = { + &hintsTest1, &hintsTest2, NULL +}; + +/* Hints test suite (global) */ +SDLTest_TestSuiteReference hintsTestSuite = { + "Hints", + NULL, + hintsTests, + NULL +}; diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c index 93ce8911d..7da8d3068 100644 --- a/test/testautomation_stdlib.c +++ b/test/testautomation_stdlib.c @@ -119,6 +119,140 @@ stdlib_snprintf(void *arg) return TEST_COMPLETED; } +/** + * @brief Call to SDL_getenv and SDL_setenv + */ +int +stdlib_getsetenv(void *arg) +{ + const int nameLen = 16; + int counter; + int result; + char name[nameLen + 1]; + char * value1; + char * value2; + char * expected; + int overwrite; + char * text; + + /* Create a random name. This tests SDL_getenv, since we need to */ + /* make sure the variable is not set yet (it shouldn't). */ + do { + for(counter = 0; counter < nameLen; counter++) { + name[counter] = (char)SDLTest_RandomIntegerInRange(65, 90); + } + name[nameLen] = '\0'; + + text = SDL_getenv(name); + SDLTest_AssertPass("Call to SDL_getenv('%s')", name); + if (text != NULL) { + SDLTest_Log("Expected: NULL, Got: '%s' (%i)", text, SDL_strlen(text)); + } + } while (text != NULL); + + /* Create random values to set */ + value1 = SDLTest_RandomAsciiStringOfSize(10); + value2 = SDLTest_RandomAsciiStringOfSize(10); + + /* Set value 1 without overwrite */ + overwrite = 0; + expected = value1; + result = SDL_setenv(name, value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('%s','%s', %i)", name, value1, overwrite); + SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result); + + /* Check value */ + text = SDL_getenv(name); + SDLTest_AssertPass("Call to SDL_getenv('%s')", name); + SDLTest_AssertCheck(text != NULL, "Verify returned text is not NULL"); + if (text != NULL) { + SDLTest_AssertCheck( + SDL_strcmp(text, expected) == 0, + "Verify returned text, expected: %s, got: %s", + expected, + text); + } + + /* Set value 2 with overwrite */ + overwrite = 1; + expected = value2; + result = SDL_setenv(name, value2, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('%s','%s', %i)", name, value2, overwrite); + SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result); + + /* Check value */ + text = SDL_getenv(name); + SDLTest_AssertPass("Call to SDL_getenv('%s')", name); + SDLTest_AssertCheck(text != NULL, "Verify returned text is not NULL"); + if (text != NULL) { + SDLTest_AssertCheck( + SDL_strcmp(text, expected) == 0, + "Verify returned text, expected: %s, got: %s", + expected, + text); + } + + /* Set value 1 without overwrite */ + overwrite = 0; + expected = value2; + result = SDL_setenv(name, value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('%s','%s', %i)", name, value1, overwrite); + SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result); + + /* Check value */ + text = SDL_getenv(name); + SDLTest_AssertPass("Call to SDL_getenv('%s')", name); + SDLTest_AssertCheck(text != NULL, "Verify returned text is not NULL"); + if (text != NULL) { + SDLTest_AssertCheck( + SDL_strcmp(text, expected) == 0, + "Verify returned text, expected: %s, got: %s", + expected, + text); + } + + /* Set value 1 without overwrite */ + overwrite = 1; + expected = value1; + result = SDL_setenv(name, value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('%s','%s', %i)", name, value1, overwrite); + SDLTest_AssertCheck(result == 0, "Check result, expected: 0, got: %i", result); + + /* Check value */ + text = SDL_getenv(name); + SDLTest_AssertPass("Call to SDL_getenv('%s')", name); + SDLTest_AssertCheck(text != NULL, "Verify returned text is not NULL"); + if (text != NULL) { + SDLTest_AssertCheck( + SDL_strcmp(text, expected) == 0, + "Verify returned text, expected: %s, got: %s", + expected, + text); + } + + /* Negative cases */ + for (overwrite=0; overwrite <= 1; overwrite++) { + result = SDL_setenv(NULL, value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv(NULL,'%s', %i)", value1, overwrite); + SDLTest_AssertCheck(result == -1, "Check result, expected: -1, got: %i", result); + result = SDL_setenv("", value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('','%s', %i)", value1, overwrite); + SDLTest_AssertCheck(result == -1, "Check result, expected: -1, got: %i", result); + result = SDL_setenv("=", value1, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('=','%s', %i)", value1, overwrite); + SDLTest_AssertCheck(result == -1, "Check result, expected: -1, got: %i", result); + result = SDL_setenv(name, NULL, overwrite); + SDLTest_AssertPass("Call to SDL_setenv('%s', NULL, %i)", name, overwrite); + SDLTest_AssertCheck(result == -1, "Check result, expected: -1, got: %i", result); + } + + /* Clean up */ + SDL_free(value1); + SDL_free(value2); + + return TEST_COMPLETED; +} + /* ================= Test References ================== */ /* Standard C routine test cases */ @@ -128,14 +262,17 @@ static const SDLTest_TestCaseReference stdlibTest1 = static const SDLTest_TestCaseReference stdlibTest2 = { (SDLTest_TestCaseFp)stdlib_snprintf, "stdlib_snprintf", "Call to SDL_snprintf", TEST_ENABLED }; +static const SDLTest_TestCaseReference stdlibTest3 = + { (SDLTest_TestCaseFp)stdlib_getsetenv, "stdlib_getsetenv", "Call to SDL_getenv and SDL_setenv", TEST_ENABLED }; + /* Sequence of Standard C routine test cases */ static const SDLTest_TestCaseReference *stdlibTests[] = { - &stdlibTest1, &stdlibTest2, NULL + &stdlibTest1, &stdlibTest2, &stdlibTest3, NULL }; /* Timer test suite (global) */ SDLTest_TestSuiteReference stdlibTestSuite = { - "Standard C routines", + "Stdlib", NULL, stdlibTests, NULL diff --git a/test/testautomation_suites.h b/test/testautomation_suites.h index 1ba7c95f1..b5f921e3d 100644 --- a/test/testautomation_suites.h +++ b/test/testautomation_suites.h @@ -26,6 +26,7 @@ extern SDLTest_TestSuiteReference surfaceTestSuite; extern SDLTest_TestSuiteReference syswmTestSuite; extern SDLTest_TestSuiteReference timerTestSuite; extern SDLTest_TestSuiteReference videoTestSuite; +extern SDLTest_TestSuiteReference hintsTestSuite; /* All test suites */ SDLTest_TestSuiteReference *testSuites[] = { @@ -46,6 +47,7 @@ SDLTest_TestSuiteReference *testSuites[] = { &syswmTestSuite, &timerTestSuite, &videoTestSuite, + &hintsTestSuite, NULL };