diff --git a/.travis.yml b/.travis.yml index 8d32264a3836df1d1baa9e0b426920c9523986e0..ebd4672ac7d7c70f18df51f9fb23232f2b86fc59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,9 @@ script: - cd ../extras/fixture/test && rake ci - make -s default noStdlibMalloc - make -s C89 + - cd ../extras/memory/test && rake ci + - make -s default noStdlibMalloc + - make -s C89 - cd ../../../examples/example_1 && make -s ci - cd ../example_2 && make -s ci - cd ../example_3 && rake diff --git a/extras/fixture/rakefile_helper.rb b/extras/fixture/rakefile_helper.rb index 91dafaf7ccc586f0643cc8076364e1ab312af145..c543d10b43f91011de32fb911dd1b63efbb5a446 100644 --- a/extras/fixture/rakefile_helper.rb +++ b/extras/fixture/rakefile_helper.rb @@ -55,12 +55,7 @@ def build_compiler_fields defines = if $cfg['compiler']['defines']['items'].nil? '' else - decl = if $is_windows - 'UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar(int)' - else - 'UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\)' - end - squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar'] + [decl]) + squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items']) end options = squash('', $cfg['compiler']['options']) includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) diff --git a/extras/fixture/readme.md b/extras/fixture/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..38a31321a73212839ebc1f947b9433f635dd5cc7 --- /dev/null +++ b/extras/fixture/readme.md @@ -0,0 +1,17 @@ +# Unity Fixtures + +This Framework is an optional add-on to Unity. By including unity_framework.h in place of unity.h, +you may now work with Unity in a manner similar to CppUTest. This framework adds the concepts of +test groups and gives finer control of your tests over the command line. + +This framework is primarily supplied for those working through James Grenning's book on Embedded +Test Driven Development, or those coming to Unity from CppUTest. We should note that using this +framework glosses over some of the features of Unity, and makes it more difficult +to integrate with other testing tools like Ceedling and CMock. + +# Dependency Notification + +Fixtures, by default, uses the Memory addon as well. This is to make it simple for those trying to +follow along with James' book. Using them together is completely optional. You may choose to use +Fixtures without Memory handling by defining `UNITY_FIXTURE_NO_EXTRAS`. It will then stop automatically +pulling in extras and leave you to do it as desired. diff --git a/extras/fixture/readme.txt b/extras/fixture/readme.txt deleted file mode 100644 index 6b9a78c17f7e54108ca9c61e9435c063b522fc87..0000000000000000000000000000000000000000 --- a/extras/fixture/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -Copyright (c) 2010 James Grenning and Contributed to Unity Project - -Unity Project - A Test Framework for C -Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams -[Released under MIT License. Please refer to license.txt for details] - -This Framework is an optional add-on to Unity. By including unity_framework.h in place of unity.h, -you may now work with Unity in a manner similar to CppUTest. This framework adds the concepts of -test groups and gives finer control of your tests over the command line. \ No newline at end of file diff --git a/extras/fixture/src/unity_fixture.c b/extras/fixture/src/unity_fixture.c index 958a37fcde5636084b252b07831e97ca03617e90..3b66a6d16971c4568333b20faef77b164594d3f2 100644 --- a/extras/fixture/src/unity_fixture.c +++ b/extras/fixture/src/unity_fixture.c @@ -94,7 +94,6 @@ void UnityTestRunner(unityfunction* setup, } Unity.NumberOfTests++; - UnityMalloc_StartTest(); UnityPointer_Init(); UNITY_EXEC_TIME_START(); @@ -111,8 +110,6 @@ void UnityTestRunner(unityfunction* setup, if (TEST_PROTECT()) { UnityPointer_UndoAllSets(); - if (!Unity.CurrentTestFailed) - UnityMalloc_EndTest(); } UnityConcludeFixtureTest(); } @@ -140,204 +137,6 @@ void UnityIgnoreTest(const char* printableName, const char* group, const char* n } } - -/*------------------------------------------------- */ -/* Malloc and free stuff */ -#define MALLOC_DONT_FAIL -1 -static int malloc_count; -static int malloc_fail_countdown = MALLOC_DONT_FAIL; - -void UnityMalloc_StartTest(void) -{ - malloc_count = 0; - malloc_fail_countdown = MALLOC_DONT_FAIL; -} - -void UnityMalloc_EndTest(void) -{ - malloc_fail_countdown = MALLOC_DONT_FAIL; - if (malloc_count != 0) - { - UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!"); - } -} - -void UnityMalloc_MakeMallocFailAfterCount(int countdown) -{ - malloc_fail_countdown = countdown; -} - -/* These definitions are always included from unity_fixture_malloc_overrides.h */ -/* We undef to use them or avoid conflict with per the C standard */ -#undef malloc -#undef free -#undef calloc -#undef realloc - -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC -static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES]; -static size_t heap_index; -#else -#include -#endif - -typedef struct GuardBytes -{ - size_t size; - size_t guard_space; -} Guard; - - -#define UNITY_MALLOC_ALIGNMENT (UNITY_POINTER_WIDTH / 8) -static const char end[] = "END"; - - -static size_t unity_size_round_up(size_t size) -{ - size_t rounded_size; - - rounded_size = ((size + UNITY_MALLOC_ALIGNMENT - 1) / UNITY_MALLOC_ALIGNMENT) * UNITY_MALLOC_ALIGNMENT; - - return rounded_size; -} - -void* unity_malloc(size_t size) -{ - char* mem; - Guard* guard; - size_t total_size; - - total_size = sizeof(Guard) + unity_size_round_up(size + sizeof(end)); - - if (malloc_fail_countdown != MALLOC_DONT_FAIL) - { - if (malloc_fail_countdown == 0) - return NULL; - malloc_fail_countdown--; - } - - if (size == 0) return NULL; -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES) - { - guard = NULL; - } - else - { - guard = (Guard*)&unity_heap[heap_index]; - heap_index += total_size; - } -#else - guard = (Guard*)UNITY_FIXTURE_MALLOC(total_size); -#endif - if (guard == NULL) return NULL; - malloc_count++; - guard->size = size; - guard->guard_space = 0; - mem = (char*)&(guard[1]); - memcpy(&mem[size], end, sizeof(end)); - - return (void*)mem; -} - -static int isOverrun(void* mem) -{ - Guard* guard = (Guard*)mem; - char* memAsChar = (char*)mem; - guard--; - - return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0; -} - -static void release_memory(void* mem) -{ - Guard* guard = (Guard*)mem; - guard--; - - malloc_count--; -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - { - size_t block_size; - - block_size = unity_size_round_up(guard->size + sizeof(end)); - - if (mem == unity_heap + heap_index - block_size) - { - heap_index -= (sizeof(Guard) + block_size); - } - } -#else - UNITY_FIXTURE_FREE(guard); -#endif -} - -void unity_free(void* mem) -{ - int overrun; - - if (mem == NULL) - { - return; - } - - overrun = isOverrun(mem); - release_memory(mem); - if (overrun) - { - UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()"); - } -} - -void* unity_calloc(size_t num, size_t size) -{ - void* mem = unity_malloc(num * size); - if (mem == NULL) return NULL; - memset(mem, 0, num * size); - return mem; -} - -void* unity_realloc(void* oldMem, size_t size) -{ - Guard* guard = (Guard*)oldMem; - void* newMem; - - if (oldMem == NULL) return unity_malloc(size); - - guard--; - if (isOverrun(oldMem)) - { - release_memory(oldMem); - UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()"); - } - - if (size == 0) - { - release_memory(oldMem); - return NULL; - } - - if (guard->size >= size) return oldMem; - -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC /* Optimization if memory is expandable */ - { - size_t old_total_size = unity_size_round_up(guard->size + sizeof(end)); - - if ((oldMem == unity_heap + heap_index - old_total_size) && - ((heap_index - old_total_size + unity_size_round_up(size + sizeof(end))) <= UNITY_INTERNAL_HEAP_SIZE_BYTES)) - { - release_memory(oldMem); /* Not thread-safe, like unity_heap generally */ - return unity_malloc(size); /* No memcpy since data is in place */ - } - } -#endif - newMem = unity_malloc(size); - if (newMem == NULL) return NULL; /* Do not release old memory */ - memcpy(newMem, oldMem, guard->size); - release_memory(oldMem); - return newMem; -} - - /*-------------------------------------------------------- */ /*Automatic pointer restoration functions */ struct PointerPair diff --git a/extras/fixture/src/unity_fixture.h b/extras/fixture/src/unity_fixture.h index 2dcf473c7f2697c843a31cbbc597bf52541f3dbc..c042a264adab48976011eee804544fe0c7da2094 100644 --- a/extras/fixture/src/unity_fixture.h +++ b/extras/fixture/src/unity_fixture.h @@ -10,7 +10,6 @@ #include "unity.h" #include "unity_internals.h" -#include "unity_fixture_malloc_overrides.h" #include "unity_fixture_internals.h" int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)); @@ -77,7 +76,4 @@ int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)); #define DOUBLES_EQUAL(expected, actual, delta) TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual)) #endif -/* You must compile with malloc replacement, as defined in unity_fixture_malloc_overrides.h */ -void UnityMalloc_MakeMallocFailAfterCount(int countdown); - #endif /* UNITY_FIXTURE_H_ */ diff --git a/extras/fixture/src/unity_fixture_internals.h b/extras/fixture/src/unity_fixture_internals.h index 98d4d4430dcdea5cd081c1154e839be10337c748..1c51aa986abc2e24fc36928d47990b9b37a2ff62 100644 --- a/extras/fixture/src/unity_fixture_internals.h +++ b/extras/fixture/src/unity_fixture_internals.h @@ -33,8 +33,6 @@ void UnityTestRunner(unityfunction* setup, const char* file, unsigned int line); void UnityIgnoreTest(const char* printableName, const char* group, const char* name); -void UnityMalloc_StartTest(void); -void UnityMalloc_EndTest(void); int UnityGetCommandLineOptions(int argc, const char* argv[]); void UnityConcludeFixtureTest(void); diff --git a/extras/fixture/test/Makefile b/extras/fixture/test/Makefile index 2560868d1c2b9679d10993cf3a809c5a62781f92..897c5dce711ec67c70379dba78b9dd411309ec41 100644 --- a/extras/fixture/test/Makefile +++ b/extras/fixture/test/Makefile @@ -5,17 +5,10 @@ endif #DEBUG = -O0 -g CFLAGS += -std=c99 -pedantic -Wall -Wextra -Werror CFLAGS += $(DEBUG) -DEFINES = -D UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar -ifeq ($(OS),Windows_NT) - DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar(int) -else - DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\) -endif SRC = ../src/unity_fixture.c \ ../../../src/unity.c \ unity_fixture_Test.c \ unity_fixture_TestRunner.c \ - unity_output_Spy.c \ main/AllTests.c INC_DIR = -I../src -I../../../src/ diff --git a/extras/fixture/test/main/AllTests.c b/extras/fixture/test/main/AllTests.c index e30dd853d123ccdc1bc9f6b95c9ea92fb1de7585..30242cb30e5ad410b22d763867bbf4d93b0127f7 100644 --- a/extras/fixture/test/main/AllTests.c +++ b/extras/fixture/test/main/AllTests.c @@ -11,8 +11,6 @@ static void runAllTests(void) { RUN_TEST_GROUP(UnityFixture); RUN_TEST_GROUP(UnityCommandOptions); - RUN_TEST_GROUP(LeakDetection); - RUN_TEST_GROUP(InternalMalloc); } int main(int argc, const char* argv[]) diff --git a/extras/fixture/test/unity_fixture_Test.c b/extras/fixture/test/unity_fixture_Test.c index 4b59d988748a6cb027467f2ff08968284d3767d3..1422b48964f929f4f0a593aa076c79444f0ccbf9 100644 --- a/extras/fixture/test/unity_fixture_Test.c +++ b/extras/fixture/test/unity_fixture_Test.c @@ -6,7 +6,6 @@ * ========================================== */ #include "unity_fixture.h" -#include "unity_output_Spy.h" #include #include @@ -44,71 +43,6 @@ TEST(UnityFixture, PointerSetting) TEST_ASSERT_POINTERS_EQUAL(pointer3, (int*)3); } -TEST(UnityFixture, ForceMallocFail) -{ - void* m; - void* mfails; - UnityMalloc_MakeMallocFailAfterCount(1); - m = malloc(10); - CHECK(m); - mfails = malloc(10); - TEST_ASSERT_POINTERS_EQUAL(0, mfails); - free(m); -} - -TEST(UnityFixture, ReallocSmallerIsUnchanged) -{ - void* m1 = malloc(10); - void* m2 = realloc(m1, 5); - TEST_ASSERT_POINTERS_EQUAL(m1, m2); - free(m2); -} - -TEST(UnityFixture, ReallocSameIsUnchanged) -{ - void* m1 = malloc(10); - void* m2 = realloc(m1, 10); - TEST_ASSERT_POINTERS_EQUAL(m1, m2); - free(m2); -} - -TEST(UnityFixture, ReallocLargerNeeded) -{ - void* m1 = malloc(10); - void* m2; - CHECK(m1); - strcpy((char*)m1, "123456789"); - m2 = realloc(m1, 15); - /* CHECK(m1 != m2); //Depends on implementation */ - STRCMP_EQUAL("123456789", m2); - free(m2); -} - -TEST(UnityFixture, ReallocNullPointerIsLikeMalloc) -{ - void* m = realloc(0, 15); - CHECK(m != 0); - free(m); -} - -TEST(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer) -{ - void* m1 = malloc(10); - void* m2 = realloc(m1, 0); - TEST_ASSERT_POINTERS_EQUAL(0, m2); -} - -TEST(UnityFixture, CallocFillsWithZero) -{ - void* m = calloc(3, sizeof(char)); - char* s = (char*)m; - CHECK(m); - TEST_ASSERT_BYTES_EQUAL(0, s[0]); - TEST_ASSERT_BYTES_EQUAL(0, s[1]); - TEST_ASSERT_BYTES_EQUAL(0, s[2]); - free(m); -} - static char *p1; static char *p2; @@ -140,12 +74,10 @@ TEST(UnityFixture, ConcludeTestIncrementsFailCount) { UNITY_UINT savedFails = Unity.TestFailures; UNITY_UINT savedIgnores = Unity.TestIgnores; - UnityOutputCharSpy_Enable(1); Unity.CurrentTestFailed = 1; UnityConcludeFixtureTest(); /* Resets TestFailed for this test to pass */ Unity.CurrentTestIgnored = 1; UnityConcludeFixtureTest(); /* Resets TestIgnored */ - UnityOutputCharSpy_Enable(0); TEST_ASSERT_EQUAL(savedFails + 1, Unity.TestFailures); TEST_ASSERT_EQUAL(savedIgnores + 1, Unity.TestIgnores); Unity.TestFailures = savedFails; @@ -311,235 +243,3 @@ IGNORE_TEST(UnityCommandOptions, TestShouldBeIgnored) { TEST_FAIL_MESSAGE("This test should not run!"); } - -/*------------------------------------------------------------ */ - -TEST_GROUP(LeakDetection); - -TEST_SETUP(LeakDetection) -{ -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - UnityOutputCharSpy_Create(200); -#else - UnityOutputCharSpy_Create(1000); -#endif -} - -TEST_TEAR_DOWN(LeakDetection) -{ - UnityOutputCharSpy_Destroy(); -} - -#define EXPECT_ABORT_BEGIN \ - { \ - jmp_buf TestAbortFrame; \ - memcpy(TestAbortFrame, Unity.AbortFrame, sizeof(jmp_buf)); \ - if (TEST_PROTECT()) \ - { - -#define EXPECT_ABORT_END \ - } \ - memcpy(Unity.AbortFrame, TestAbortFrame, sizeof(jmp_buf)); \ - } - -/* This tricky set of defines lets us see if we are using the Spy, returns 1 if true */ -#ifdef __STDC_VERSION__ - -#ifdef UNITY_SUPPORT_VARIADIC_MACROS -#define USING_SPY_AS(a) EXPAND_AND_USE_2ND(ASSIGN_VALUE(a), 0) -#define ASSIGN_VALUE(a) VAL_##a -#define VAL_UnityOutputCharSpy_OutputChar 0, 1 -#define EXPAND_AND_USE_2ND(a, b) SECOND_PARAM(a, b, throwaway) -#define SECOND_PARAM(a, b, ...) b -#if USING_SPY_AS(UNITY_OUTPUT_CHAR) - #define USING_OUTPUT_SPY /* UNITY_OUTPUT_CHAR = UnityOutputCharSpy_OutputChar */ -#endif -#endif /* UNITY_SUPPORT_VARIADIC_MACROS */ - -#else /* __STDC_VERSION__ else */ - -#define UnityOutputCharSpy_OutputChar 42 -#if UNITY_OUTPUT_CHAR == UnityOutputCharSpy_OutputChar /* Works if no -Wundef -Werror */ - #define USING_OUTPUT_SPY -#endif -#undef UnityOutputCharSpy_OutputChar - -#endif /* __STDC_VERSION__ */ - -TEST(LeakDetection, DetectsLeak) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE_MESSAGE("Build with '-D UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar' to enable tests"); -#else - void* m = malloc(10); - TEST_ASSERT_NOT_NULL(m); - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - UnityMalloc_EndTest(); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "This test leaks!")); - free(m); -#endif -} - -TEST(LeakDetection, BufferOverrunFoundDuringFree) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE(); -#else - void* m = malloc(10); - char* s = (char*)m; - TEST_ASSERT_NOT_NULL(m); - s[10] = (char)0xFF; - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - free(m); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); -#endif -} - -TEST(LeakDetection, BufferOverrunFoundDuringRealloc) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE(); -#else - void* m = malloc(10); - char* s = (char*)m; - TEST_ASSERT_NOT_NULL(m); - s[10] = (char)0xFF; - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - m = realloc(m, 100); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); -#endif -} - -TEST(LeakDetection, BufferGuardWriteFoundDuringFree) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE(); -#else - void* m = malloc(10); - char* s = (char*)m; - TEST_ASSERT_NOT_NULL(m); - s[-1] = (char)0x00; /* Will not detect 0 */ - s[-2] = (char)0x01; - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - free(m); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); -#endif -} - -TEST(LeakDetection, BufferGuardWriteFoundDuringRealloc) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE(); -#else - void* m = malloc(10); - char* s = (char*)m; - TEST_ASSERT_NOT_NULL(m); - s[-1] = (char)0x0A; - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - m = realloc(m, 100); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); -#endif -} - -TEST(LeakDetection, PointerSettingMax) -{ -#ifndef USING_OUTPUT_SPY - TEST_IGNORE(); -#else - int i; - for (i = 0; i < UNITY_MAX_POINTERS; i++) UT_PTR_SET(pointer1, &int1); - UnityOutputCharSpy_Enable(1); - EXPECT_ABORT_BEGIN - UT_PTR_SET(pointer1, &int1); - EXPECT_ABORT_END - UnityOutputCharSpy_Enable(0); - Unity.CurrentTestFailed = 0; - CHECK(strstr(UnityOutputCharSpy_Get(), "Too many pointers set")); -#endif -} - -/*------------------------------------------------------------ */ - -TEST_GROUP(InternalMalloc); -#define TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(first_mem_ptr, ptr) \ - ptr = malloc(10); free(ptr); \ - TEST_ASSERT_EQUAL_PTR_MESSAGE(first_mem_ptr, ptr, "Memory was stranded, free in LIFO order"); - - -TEST_SETUP(InternalMalloc) { } -TEST_TEAR_DOWN(InternalMalloc) { } - -TEST(InternalMalloc, MallocPastBufferFails) -{ -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); - void* n = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); - free(m); - TEST_ASSERT_NOT_NULL(m); - TEST_ASSERT_NULL(n); - TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); -#endif -} - -TEST(InternalMalloc, CallocPastBufferFails) -{ -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - void* m = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); - void* n = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2); - free(m); - TEST_ASSERT_NOT_NULL(m); - TEST_ASSERT_NULL(n); - TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); -#endif -} - -TEST(InternalMalloc, MallocThenReallocGrowsMemoryInPlace) -{ -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); - void* n = realloc(m, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 9); - free(n); - TEST_ASSERT_NOT_NULL(m); - TEST_ASSERT_EQUAL(m, n); - TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); -#endif -} - -TEST(InternalMalloc, ReallocFailDoesNotFreeMem) -{ -#ifdef UNITY_EXCLUDE_STDLIB_MALLOC - void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); - void* n1 = malloc(10); - void* out_of_mem = realloc(n1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); - void* n2 = malloc(10); - - free(n2); - if (out_of_mem == NULL) free(n1); - free(m); - - TEST_ASSERT_NOT_NULL(m); /* Got a real memory location */ - TEST_ASSERT_NULL(out_of_mem); /* The realloc should have failed */ - TEST_ASSERT_NOT_EQUAL(n2, n1); /* If n1 != n2 then realloc did not free n1 */ - TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n2); -#endif -} diff --git a/extras/fixture/test/unity_fixture_TestRunner.c b/extras/fixture/test/unity_fixture_TestRunner.c index e8713e1bc4c00205118f9a47fac36f7bec95aeb2..7b78c49c0eb15c0b3be0f7c93cda202f677afa3c 100644 --- a/extras/fixture/test/unity_fixture_TestRunner.c +++ b/extras/fixture/test/unity_fixture_TestRunner.c @@ -10,13 +10,6 @@ TEST_GROUP_RUNNER(UnityFixture) { RUN_TEST_CASE(UnityFixture, PointerSetting); - RUN_TEST_CASE(UnityFixture, ForceMallocFail); - RUN_TEST_CASE(UnityFixture, ReallocSmallerIsUnchanged); - RUN_TEST_CASE(UnityFixture, ReallocSameIsUnchanged); - RUN_TEST_CASE(UnityFixture, ReallocLargerNeeded); - RUN_TEST_CASE(UnityFixture, ReallocNullPointerIsLikeMalloc); - RUN_TEST_CASE(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer); - RUN_TEST_CASE(UnityFixture, CallocFillsWithZero); RUN_TEST_CASE(UnityFixture, PointerSet); RUN_TEST_CASE(UnityFixture, FreeNULLSafety); RUN_TEST_CASE(UnityFixture, ConcludeTestIncrementsFailCount); @@ -37,21 +30,3 @@ TEST_GROUP_RUNNER(UnityCommandOptions) RUN_TEST_CASE(UnityCommandOptions, GroupFilterReallyFilters); RUN_TEST_CASE(UnityCommandOptions, TestShouldBeIgnored); } - -TEST_GROUP_RUNNER(LeakDetection) -{ - RUN_TEST_CASE(LeakDetection, DetectsLeak); - RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringFree); - RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringRealloc); - RUN_TEST_CASE(LeakDetection, BufferGuardWriteFoundDuringFree); - RUN_TEST_CASE(LeakDetection, BufferGuardWriteFoundDuringRealloc); - RUN_TEST_CASE(LeakDetection, PointerSettingMax); -} - -TEST_GROUP_RUNNER(InternalMalloc) -{ - RUN_TEST_CASE(InternalMalloc, MallocPastBufferFails); - RUN_TEST_CASE(InternalMalloc, CallocPastBufferFails); - RUN_TEST_CASE(InternalMalloc, MallocThenReallocGrowsMemoryInPlace); - RUN_TEST_CASE(InternalMalloc, ReallocFailDoesNotFreeMem); -} diff --git a/extras/memory/rakefile.rb b/extras/memory/rakefile.rb new file mode 100644 index 0000000000000000000000000000000000000000..328f3c68284ac0822401df2ac2ff81d2adeb7df9 --- /dev/null +++ b/extras/memory/rakefile.rb @@ -0,0 +1,45 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require 'rake' +require 'rake/clean' +require 'rake/testtask' +require_relative 'rakefile_helper' + +TEMP_DIRS = [ + File.join(__dir__, 'build') +].freeze + +TEMP_DIRS.each do |dir| + directory(dir) + CLOBBER.include(dir) +end + +task prepare_for_tests: TEMP_DIRS + +# Load default configuration, for now +DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml'.freeze +configure_toolchain(DEFAULT_CONFIG_FILE) + +task unit: [:prepare_for_tests] do + run_tests(false) + run_tests(true) +end + +desc 'Build and test Unity Framework' +task all: %i[clean unit] +task default: %i[clobber all] +task ci: %i[no_color default] +task cruise: %i[no_color default] + +desc 'Load configuration' +task :config, :config_file do |_t, args| + configure_toolchain(args[:config_file]) +end + +task :no_color do + $colour_output = false +end diff --git a/extras/memory/rakefile_helper.rb b/extras/memory/rakefile_helper.rb new file mode 100644 index 0000000000000000000000000000000000000000..f91106fd7ae1f7b7371ed584eb266a7197eee0f1 --- /dev/null +++ b/extras/memory/rakefile_helper.rb @@ -0,0 +1,187 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require 'yaml' +require 'fileutils' +require 'rbconfig' +require_relative '../../auto/unity_test_summary' +require_relative '../../auto/generate_test_runner' +require_relative '../../auto/colour_reporter' + +$is_windows = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) + +C_EXTENSION = '.c'.freeze + +def load_configuration(config_file) + return if $configured + + $cfg_file = "#{__dir__}/../../test/targets/#{config_file}" unless config_file =~ /[\\|\/]/ + $cfg = YAML.load(File.read($cfg_file)) + $colour_output = false unless $cfg['colour'] + $configured = true if config_file != DEFAULT_CONFIG_FILE +end + +def configure_clean + CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? +end + +def configure_toolchain(config_file = DEFAULT_CONFIG_FILE) + config_file += '.yml' unless config_file =~ /\.yml$/ + config_file = config_file unless config_file =~ /[\\|\/]/ + load_configuration(config_file) + configure_clean +end + +def tackit(strings) + result = if strings.is_a?(Array) + "\"#{strings.join}\"" + else + strings + end + result +end + +def squash(prefix, items) + result = '' + items.each { |item| result += " #{prefix}#{tackit(item)}" } + result +end + +def build_compiler_fields + command = tackit($cfg['compiler']['path']) + defines = if $cfg['compiler']['defines']['items'].nil? + '' + else + decl = if $is_windows + 'UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar(int)' + else + 'UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\)' + end + squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar'] + [decl]) + end + options = squash('', $cfg['compiler']['options']) + includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + + { command: command, defines: defines, options: options, includes: includes } +end + +def compile(file, _defines = []) + compiler = build_compiler_fields + unity_include = $cfg['compiler']['includes']['prefix'] + '../../src' + cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{unity_include} #{file} " \ + "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" \ + "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}" + + execute(cmd_str) +end + +def build_linker_fields + command = tackit($cfg['linker']['path']) + options = if $cfg['linker']['options'].nil? + '' + else + squash('', $cfg['linker']['options']) + end + includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil? + '' + else + squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) + end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + + { command: command, options: options, includes: includes } +end + +def link_it(exe_name, obj_list) + linker = build_linker_fields + cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " + + (obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join + + $cfg['linker']['bin_files']['prefix'] + ' ' + + $cfg['linker']['bin_files']['destination'] + + exe_name + $cfg['linker']['bin_files']['extension'] + execute(cmd_str) +end + +def build_simulator_fields + return nil if $cfg['simulator'].nil? + + command = if $cfg['simulator']['path'].nil? + '' + else + (tackit($cfg['simulator']['path']) + ' ') + end + pre_support = if $cfg['simulator']['pre_support'].nil? + '' + else + squash('', $cfg['simulator']['pre_support']) + end + post_support = if $cfg['simulator']['post_support'].nil? + '' + else + squash('', $cfg['simulator']['post_support']) + end + { command: command, pre_support: pre_support, post_support: post_support } +end + +def execute(command_string, verbose = true) + report command_string + output = `#{command_string}`.chomp + report(output) if verbose && !output.nil? && !output.empty? + + raise "Command failed. (Returned #{$?.exitstatus})" if $?.exitstatus != 0 + + output +end + +def report_summary + summary = UnityTestSummary.new + summary.root = __dir__ + results_glob = "#{$cfg['compiler']['build_path']}*.test*" + results_glob.tr!('\\', '/') + results = Dir[results_glob] + summary.targets = results + summary.run +end + +def run_tests(exclude_stdlib=false) + report 'Running Unity system tests...' + + # Tack on TEST define for compiling unit tests + load_configuration($cfg_file) + test_defines = ['TEST'] + $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil? + $cfg['compiler']['defines']['items'] << 'UNITY_EXCLUDE_STDLIB_MALLOC' if exclude_stdlib + + # Get a list of all source files needed + src_files = Dir["#{__dir__}/src/*.c"] + src_files += Dir["#{__dir__}/test/*.c"] + src_files << '../../src/unity.c' + + # Build object files + src_files.each { |f| compile(f, test_defines) } + obj_list = src_files.map { |f| File.basename(f.ext($cfg['compiler']['object_files']['extension'])) } + + # Link the test executable + test_base = 'framework_test' + link_it(test_base, obj_list) + + # Execute unit test and generate results file + simulator = build_simulator_fields + executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension'] + cmd_str = if simulator.nil? + executable + ' -v -r' + else + "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}" + end + output = execute(cmd_str) + test_results = $cfg['compiler']['build_path'] + test_base + test_results += if output.match(/OK$/m).nil? + '.testfail' + else + '.testpass' + end + File.open(test_results, 'w') { |f| f.print output } +end diff --git a/extras/memory/readme.md b/extras/memory/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..37769825c9bcdc14c57fb715abcabb755c85ec1e --- /dev/null +++ b/extras/memory/readme.md @@ -0,0 +1,49 @@ +# Unity Memory + +This Framework is an optional add-on to Unity. By including unity.h and then +unity_memory.h, you have the added ability to track malloc and free calls. This +addon requires that the stdlib functions be overridden by its own defines. These +defines will still malloc / realloc / free etc, but will also track the calls +in order to ensure that you don't have any memory leaks in your programs. + +Note that this is only useful in situations where a unit is in charge of both +the allocation and deallocation of memory. When it is not symmetric, unit testing +can report a number of false failures. A more advanced runtime tool is required to +track complete system memory handling. + +# Module API + +## `UnityMalloc_StartTest` and `UnityMalloc_EndTest` + +These must be called at the beginning and end of each test. For simplicity, they can +be added to `setUp` and `tearDown` in order to do their job. When using the test +runner generator scripts, these will be automatically added to the runner whenever +unity_memory.h is included. + +## `UnityMalloc_MakeMallocFailAfterCount` + +This can be called from the tests themselves. Passing this function a number will +force the reference counter to start keeping track of malloc calls. During that test, +if the number of malloc calls exceeds the number given, malloc will immediately +start returning `NULL`. This allows you to test error conditions. Think of it as a +simplified mock. + +# Configuration + +## `UNITY_MALLOC` and `UNITY_FREE` + +By default, this module tries to use the real stdlib `malloc` and `free` internally. +If you would prefer it to use something else, like FreeRTOS's `pvPortMalloc` and +`pvPortFree`, then you can use these defines to make it so. + +## `UNITY_EXCLUDE_STDLIB_MALLOC` + +If you would like this library to ignore stdlib or other heap engines completely, and +manage the memory on its own, then define this. All memory will be handled internally +(and at likely lower overhead). Note that this is not a very featureful memory manager, +but is sufficient for most testing purposes. + +## `UNITY_INTERNAL_HEAP_SIZE_BYTES` + +When using the built-in memory manager (see `UNITY_EXCLUDE_STDLIB_MALLOC`) this define +allows you to set the heap size this library will use to manage the memory. diff --git a/extras/memory/src/unity_memory.c b/extras/memory/src/unity_memory.c new file mode 100644 index 0000000000000000000000000000000000000000..e112e8d564288cd523b62fed297790160432ed36 --- /dev/null +++ b/extras/memory/src/unity_memory.c @@ -0,0 +1,201 @@ +/* ========================================== + * Unity Project - A Test Framework for C + * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + * [Released under MIT License. Please refer to license.txt for details] + * ========================================== */ + +#include "unity.h" +#include "unity_memory.h" +#include + +#define MALLOC_DONT_FAIL -1 +static int malloc_count; +static int malloc_fail_countdown = MALLOC_DONT_FAIL; + +void UnityMalloc_StartTest(void) +{ + malloc_count = 0; + malloc_fail_countdown = MALLOC_DONT_FAIL; +} + +void UnityMalloc_EndTest(void) +{ + malloc_fail_countdown = MALLOC_DONT_FAIL; + if (malloc_count != 0) + { + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!"); + } +} + +void UnityMalloc_MakeMallocFailAfterCount(int countdown) +{ + malloc_fail_countdown = countdown; +} + +/* These definitions are always included from unity_fixture_malloc_overrides.h */ +/* We undef to use them or avoid conflict with per the C standard */ +#undef malloc +#undef free +#undef calloc +#undef realloc + +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC +static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES]; +static size_t heap_index; +#else +#include +#endif + +typedef struct GuardBytes +{ + size_t size; + size_t guard_space; +} Guard; + +#define UNITY_MALLOC_ALIGNMENT (UNITY_POINTER_WIDTH / 8) +static const char end[] = "END"; + +static size_t unity_size_round_up(size_t size) +{ + size_t rounded_size; + + rounded_size = ((size + UNITY_MALLOC_ALIGNMENT - 1) / UNITY_MALLOC_ALIGNMENT) * UNITY_MALLOC_ALIGNMENT; + + return rounded_size; +} + +void* unity_malloc(size_t size) +{ + char* mem; + Guard* guard; + size_t total_size; + + total_size = sizeof(Guard) + unity_size_round_up(size + sizeof(end)); + + if (malloc_fail_countdown != MALLOC_DONT_FAIL) + { + if (malloc_fail_countdown == 0) + return NULL; + malloc_fail_countdown--; + } + + if (size == 0) return NULL; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES) + { + guard = NULL; + } + else + { + guard = (Guard*)&unity_heap[heap_index]; + heap_index += total_size; + } +#else + guard = (Guard*)UNITY_MALLOC(total_size); +#endif + if (guard == NULL) return NULL; + malloc_count++; + guard->size = size; + guard->guard_space = 0; + mem = (char*)&(guard[1]); + memcpy(&mem[size], end, sizeof(end)); + + return (void*)mem; +} + +static int isOverrun(void* mem) +{ + Guard* guard = (Guard*)mem; + char* memAsChar = (char*)mem; + guard--; + + return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0; +} + +static void release_memory(void* mem) +{ + Guard* guard = (Guard*)mem; + guard--; + + malloc_count--; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + { + size_t block_size; + + block_size = unity_size_round_up(guard->size + sizeof(end)); + + if (mem == unity_heap + heap_index - block_size) + { + heap_index -= (sizeof(Guard) + block_size); + } + } +#else + UNITY_FREE(guard); +#endif +} + +void unity_free(void* mem) +{ + int overrun; + + if (mem == NULL) + { + return; + } + + overrun = isOverrun(mem); + release_memory(mem); + if (overrun) + { + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()"); + } +} + +void* unity_calloc(size_t num, size_t size) +{ + void* mem = unity_malloc(num * size); + if (mem == NULL) return NULL; + memset(mem, 0, num * size); + return mem; +} + +void* unity_realloc(void* oldMem, size_t size) +{ + Guard* guard = (Guard*)oldMem; + void* newMem; + + if (oldMem == NULL) return unity_malloc(size); + + guard--; + if (isOverrun(oldMem)) + { + release_memory(oldMem); + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()"); + } + + if (size == 0) + { + release_memory(oldMem); + return NULL; + } + + if (guard->size >= size) return oldMem; + +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC /* Optimization if memory is expandable */ + { + size_t old_total_size = unity_size_round_up(guard->size + sizeof(end)); + + if ((oldMem == unity_heap + heap_index - old_total_size) && + ((heap_index - old_total_size + unity_size_round_up(size + sizeof(end))) <= UNITY_INTERNAL_HEAP_SIZE_BYTES)) + { + release_memory(oldMem); /* Not thread-safe, like unity_heap generally */ + return unity_malloc(size); /* No memcpy since data is in place */ + } + } +#endif + newMem = unity_malloc(size); + if (newMem == NULL) return NULL; /* Do not release old memory */ + memcpy(newMem, oldMem, guard->size); + release_memory(oldMem); + return newMem; +} diff --git a/extras/fixture/src/unity_fixture_malloc_overrides.h b/extras/memory/src/unity_memory.h similarity index 58% rename from extras/fixture/src/unity_fixture_malloc_overrides.h rename to extras/memory/src/unity_memory.h index 7daba50aae5b84441096c72b7290fc20e94c0b6f..ccdb826fe7311c2be7ce81e69f13229702982c32 100644 --- a/extras/fixture/src/unity_fixture_malloc_overrides.h +++ b/extras/memory/src/unity_memory.h @@ -1,12 +1,16 @@ -/* Copyright (c) 2010 James Grenning and Contributed to Unity Project - * ========================================== +/* ========================================== * Unity Project - A Test Framework for C * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams * [Released under MIT License. Please refer to license.txt for details] * ========================================== */ -#ifndef UNITY_FIXTURE_MALLOC_OVERRIDES_H_ -#define UNITY_FIXTURE_MALLOC_OVERRIDES_H_ +#ifndef UNITY_MEMORY_OVERRIDES_H_ +#define UNITY_MEMORY_OVERRIDES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif #include @@ -21,17 +25,17 @@ #endif #endif -/* These functions are used by the Unity Fixture to allocate and release memory +/* These functions are used by Unity to allocate and release memory * on the heap and can be overridden with platform-specific implementations. - * For example, when using FreeRTOS UNITY_FIXTURE_MALLOC becomes pvPortMalloc() - * and UNITY_FIXTURE_FREE becomes vPortFree(). */ -#if !defined(UNITY_FIXTURE_MALLOC) || !defined(UNITY_FIXTURE_FREE) + * For example, when using FreeRTOS UNITY_MALLOC becomes pvPortMalloc() + * and UNITY_FREE becomes vPortFree(). */ +#if !defined(UNITY_MALLOC) || !defined(UNITY_FREE) #include - #define UNITY_FIXTURE_MALLOC(size) malloc(size) - #define UNITY_FIXTURE_FREE(ptr) free(ptr) + #define UNITY_MALLOC(size) malloc(size) + #define UNITY_FREE(ptr) free(ptr) #else - extern void* UNITY_FIXTURE_MALLOC(size_t size); - extern void UNITY_FIXTURE_FREE(void* ptr); + extern void* UNITY_MALLOC(size_t size); + extern void UNITY_FREE(void* ptr); #endif #define malloc unity_malloc @@ -44,4 +48,13 @@ void* unity_calloc(size_t num, size_t size); void* unity_realloc(void * oldMem, size_t size); void unity_free(void * mem); -#endif /* UNITY_FIXTURE_MALLOC_OVERRIDES_H_ */ +/* You must compile with malloc replacement, as defined in unity_fixture_malloc_overrides.h */ +void UnityMalloc_StartTest(void); +void UnityMalloc_EndTest(void); +void UnityMalloc_MakeMallocFailAfterCount(int countdown); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/extras/memory/test/Makefile b/extras/memory/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f3f86ce6052167826bcfef8cda2ee3d6e06f34b0 --- /dev/null +++ b/extras/memory/test/Makefile @@ -0,0 +1,78 @@ +CC = gcc +ifeq ($(shell uname -s), Darwin) +CC = clang +endif +#DEBUG = -O0 -g +CFLAGS += -std=c99 -pedantic -Wall -Wextra -Werror +CFLAGS += $(DEBUG) +DEFINES = -D UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar +ifeq ($(OS),Windows_NT) + DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar(int) +else + DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\) +endif +SRC = ../src/unity_memory.c \ + ../../../src/unity.c \ + unity_memory_Test.c \ + unity_memory_TestRunner.c \ + unity_output_Spy.c \ + +INC_DIR = -I../src -I../../../src/ +BUILD_DIR = ../build +TARGET = ../build/memory_tests.exe + +all: default noStdlibMalloc 32bits + +default: $(BUILD_DIR) + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -D UNITY_SUPPORT_64 + @ echo "default build" + ./$(TARGET) + +32bits: $(BUILD_DIR) + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -m32 + @ echo "32bits build" + ./$(TARGET) + +noStdlibMalloc: $(BUILD_DIR) + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -D UNITY_EXCLUDE_STDLIB_MALLOC + @ echo "build with noStdlibMalloc" + ./$(TARGET) + +C89: CFLAGS += -D UNITY_EXCLUDE_STDINT_H # C89 did not have type 'long long', +C89: $(BUILD_DIR) + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -std=c89 && ./$(TARGET) + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -D UNITY_EXCLUDE_STDLIB_MALLOC -std=c89 + ./$(TARGET) + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +clean: + rm -f $(TARGET) $(BUILD_DIR)/*.gc* + +cov: $(BUILD_DIR) + cd $(BUILD_DIR) && \ + $(CC) $(DEFINES) $(foreach i, $(SRC), ../test/$(i)) $(INC_DIR) -o $(TARGET) -fprofile-arcs -ftest-coverage + rm -f $(BUILD_DIR)/*.gcda + ./$(TARGET) > /dev/null ; ./$(TARGET) -v > /dev/null + cd $(BUILD_DIR) && \ + gcov unity_memory.c | head -3 + grep '###' $(BUILD_DIR)/unity_memory.c.gcov -C2 || true # Show uncovered lines + +# These extended flags DO get included before any target build runs +CFLAGS += -Wbad-function-cast +CFLAGS += -Wcast-qual +CFLAGS += -Wconversion +CFLAGS += -Wformat=2 +CFLAGS += -Wmissing-prototypes +CFLAGS += -Wold-style-definition +CFLAGS += -Wpointer-arith +CFLAGS += -Wshadow +CFLAGS += -Wstrict-overflow=5 +CFLAGS += -Wstrict-prototypes +CFLAGS += -Wswitch-default +CFLAGS += -Wundef +CFLAGS += -Wno-error=undef # Warning only, this should not stop the build +CFLAGS += -Wunreachable-code +CFLAGS += -Wunused +CFLAGS += -fstrict-aliasing diff --git a/extras/memory/test/unity_memory_Test.c b/extras/memory/test/unity_memory_Test.c new file mode 100644 index 0000000000000000000000000000000000000000..65eebce8fe69b6302e5b322a82dfbaac436863a3 --- /dev/null +++ b/extras/memory/test/unity_memory_Test.c @@ -0,0 +1,300 @@ +/* ========================================== + * Unity Project - A Test Framework for C + * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + * [Released under MIT License. Please refer to license.txt for details] + * ========================================== */ + +#include "unity.h" +#include "unity_memory.h" +#include "unity_output_Spy.h" +#include +#include + +void setUp(void) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + UnityOutputCharSpy_Create(200); +#else + UnityOutputCharSpy_Create(1000); +#endif + UnityMalloc_StartTest(); +} + +void tearDown(void) +{ + UnityMalloc_EndTest(); + UnityOutputCharSpy_Destroy(); +} + +void test_ForceMallocFail(void) +{ + void* m; + void* mfails; + UnityMalloc_MakeMallocFailAfterCount(1); + m = malloc(10); + TEST_ASSERT_NOT_NULL(m); + mfails = malloc(10); + TEST_ASSERT_EQUAL_PTR(0, mfails); + free(m); +} + +void test_ReallocSmallerIsUnchanged(void) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 5); + TEST_ASSERT_NOT_NULL(m1); + TEST_ASSERT_EQUAL_PTR(m1, m2); + free(m2); +} + +void test_ReallocSameIsUnchanged(void) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 10); + TEST_ASSERT_NOT_NULL(m1); + TEST_ASSERT_EQUAL_PTR(m1, m2); + free(m2); +} + +void test_ReallocLargerNeeded(void) +{ + void* m2; + void* m1 = malloc(10); + TEST_ASSERT_NOT_NULL(m1); + strcpy((char*)m1, "123456789"); + m2 = realloc(m1, 15); + TEST_ASSERT_EQUAL_STRING("123456789", m2); + free(m2); +} + +void test_ReallocNullPointerIsLikeMalloc(void) +{ + void* m = realloc(0, 15); + TEST_ASSERT_NOT_NULL(m); + free(m); +} + +void test_ReallocSizeZeroFreesMemAndReturnsNullPointer(void) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 0); + TEST_ASSERT_EQUAL_PTR(0, m2); +} + +void test_CallocFillsWithZero(void) +{ + void* m = calloc(3, sizeof(char)); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_EQUAL_HEX8(0, s[0]); + TEST_ASSERT_EQUAL_HEX8(0, s[1]); + TEST_ASSERT_EQUAL_HEX8(0, s[2]); + free(m); +} + +void test_FreeNULLSafety(void) +{ + free(NULL); +} + +/*------------------------------------------------------------ */ + +#define EXPECT_ABORT_BEGIN \ + { \ + jmp_buf TestAbortFrame; \ + memcpy(TestAbortFrame, Unity.AbortFrame, sizeof(jmp_buf)); \ + if (TEST_PROTECT()) \ + { + +#define EXPECT_ABORT_END \ + } \ + memcpy(Unity.AbortFrame, TestAbortFrame, sizeof(jmp_buf)); \ + } + +/* This tricky set of defines lets us see if we are using the Spy, returns 1 if true */ +#ifdef __STDC_VERSION__ + +#ifdef UNITY_SUPPORT_VARIADIC_MACROS +#define USING_SPY_AS(a) EXPAND_AND_USE_2ND(ASSIGN_VALUE(a), 0) +#define ASSIGN_VALUE(a) VAL_##a +#define VAL_UnityOutputCharSpy_OutputChar 0, 1 +#define EXPAND_AND_USE_2ND(a, b) SECOND_PARAM(a, b, throwaway) +#define SECOND_PARAM(a, b, ...) b +#if USING_SPY_AS(UNITY_OUTPUT_CHAR) + #define USING_OUTPUT_SPY /* UNITY_OUTPUT_CHAR = UnityOutputCharSpy_OutputChar */ +#endif +#endif /* UNITY_SUPPORT_VARIADIC_MACROS */ + +#else /* __STDC_VERSION__ else */ + +#define UnityOutputCharSpy_OutputChar 42 +#if UNITY_OUTPUT_CHAR == UnityOutputCharSpy_OutputChar /* Works if no -Wundef -Werror */ + #define USING_OUTPUT_SPY +#endif +#undef UnityOutputCharSpy_OutputChar + +#endif /* __STDC_VERSION__ */ + +void test_DetectsLeak(void) +{ +#ifdef USING_OUTPUT_SPY + void* m = malloc(10); + TEST_ASSERT_NOT_NULL(m); + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + UnityMalloc_EndTest(); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + TEST_ASSERT_NOT_NULL(strstr(UnityOutputCharSpy_Get(), "This test leaks!")); + free(m); +#else + TEST_IGNORE_MESSAGE("Enable USING_OUTPUT_SPY To Run This Test"); +#endif +} + +void test_BufferOverrunFoundDuringFree(void) +{ +#ifdef USING_OUTPUT_SPY + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[10] = (char)0xFF; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + free(m); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + TEST_ASSERT_NOT_NULL(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); +#else + TEST_IGNORE_MESSAGE("Enable USING_OUTPUT_SPY To Run This Test"); +#endif +} + +void test_BufferOverrunFoundDuringRealloc(void) +{ +#ifdef USING_OUTPUT_SPY + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[10] = (char)0xFF; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + m = realloc(m, 100); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + TEST_ASSERT_NOT_NULL(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); +#else + TEST_IGNORE_MESSAGE("Enable USING_OUTPUT_SPY To Run This Test"); +#endif +} + +void test_BufferGuardWriteFoundDuringFree(void) +{ +#ifdef USING_OUTPUT_SPY + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[-1] = (char)0x00; /* Will not detect 0 */ + s[-2] = (char)0x01; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + free(m); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + TEST_ASSERT_NOT_NULL(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); +#else + TEST_IGNORE_MESSAGE("Enable USING_OUTPUT_SPY To Run This Test"); +#endif +} + +void test_BufferGuardWriteFoundDuringRealloc(void) +{ +#ifdef USING_OUTPUT_SPY + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[-1] = (char)0x0A; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + m = realloc(m, 100); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + TEST_ASSERT_NOT_NULL(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); +#else + TEST_IGNORE_MESSAGE("Enable USING_OUTPUT_SPY To Run This Test"); +#endif +} + +/*------------------------------------------------------------ */ + +#define TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(first_mem_ptr, ptr) \ + ptr = malloc(10); free(ptr); \ + TEST_ASSERT_EQUAL_PTR_MESSAGE(first_mem_ptr, ptr, "Memory was stranded, free in LIFO order"); + +void test_MallocPastBufferFails(void) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + free(m); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_NULL(n); + TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); +#else + TEST_IGNORE_MESSAGE("Enable UNITY_EXCLUDE_STDLIB_MALLOC to Run This Test"); +#endif +} + +void test_CallocPastBufferFails(void) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + free(m); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_NULL(n); + TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); +#else + TEST_IGNORE_MESSAGE("Enable UNITY_EXCLUDE_STDLIB_MALLOC to Run This Test"); +#endif +} + +void test_MallocThenReallocGrowsMemoryInPlace(void) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = realloc(m, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 9); + free(n); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_EQUAL(m, n); + TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n); +#else + TEST_IGNORE_MESSAGE("Enable UNITY_EXCLUDE_STDLIB_MALLOC to Run This Test"); +#endif +} + +void test_ReallocFailDoesNotFreeMem(void) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + void* n1 = malloc(10); + void* out_of_mem = realloc(n1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n2 = malloc(10); + + free(n2); + if (out_of_mem == NULL) free(n1); + free(m); + + TEST_ASSERT_NOT_NULL(m); /* Got a real memory location */ + TEST_ASSERT_NULL(out_of_mem); /* The realloc should have failed */ + TEST_ASSERT_NOT_EQUAL(n2, n1); /* If n1 != n2 then realloc did not free n1 */ + TEST_ASSERT_MEMORY_ALL_FREE_LIFO_ORDER(m, n2); +#else + TEST_IGNORE_MESSAGE("Enable UNITY_EXCLUDE_STDLIB_MALLOC to Run This Test"); +#endif +} diff --git a/extras/memory/test/unity_memory_TestRunner.c b/extras/memory/test/unity_memory_TestRunner.c new file mode 100644 index 0000000000000000000000000000000000000000..4c91a59953db050ae6a16b1cd67d014e1edad8e3 --- /dev/null +++ b/extras/memory/test/unity_memory_TestRunner.c @@ -0,0 +1,49 @@ +/* ========================================== + * Unity Project - A Test Framework for C + * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + * [Released under MIT License. Please refer to license.txt for details] + * ========================================== */ + +#include "unity.h" +#include "unity_memory.h" + +extern void test_ForceMallocFail(void); +extern void test_ReallocSmallerIsUnchanged(void); +extern void test_ReallocSameIsUnchanged(void); +extern void test_ReallocLargerNeeded(void); +extern void test_ReallocNullPointerIsLikeMalloc(void); +extern void test_ReallocSizeZeroFreesMemAndReturnsNullPointer(void); +extern void test_CallocFillsWithZero(void); +extern void test_FreeNULLSafety(void); +extern void test_DetectsLeak(void); +extern void test_BufferOverrunFoundDuringFree(void); +extern void test_BufferOverrunFoundDuringRealloc(void); +extern void test_BufferGuardWriteFoundDuringFree(void); +extern void test_BufferGuardWriteFoundDuringRealloc(void); +extern void test_MallocPastBufferFails(void); +extern void test_CallocPastBufferFails(void); +extern void test_MallocThenReallocGrowsMemoryInPlace(void); +extern void test_ReallocFailDoesNotFreeMem(void); + +int main(void) +{ + UnityBegin("unity_memory_Test.c"); + RUN_TEST(test_ForceMallocFail); + RUN_TEST(test_ReallocSmallerIsUnchanged); + RUN_TEST(test_ReallocSameIsUnchanged); + RUN_TEST(test_ReallocLargerNeeded); + RUN_TEST(test_ReallocNullPointerIsLikeMalloc); + RUN_TEST(test_ReallocSizeZeroFreesMemAndReturnsNullPointer); + RUN_TEST(test_CallocFillsWithZero); + RUN_TEST(test_FreeNULLSafety); + RUN_TEST(test_DetectsLeak); + RUN_TEST(test_BufferOverrunFoundDuringFree); + RUN_TEST(test_BufferOverrunFoundDuringRealloc); + RUN_TEST(test_BufferGuardWriteFoundDuringFree); + RUN_TEST(test_BufferGuardWriteFoundDuringRealloc); + RUN_TEST(test_MallocPastBufferFails); + RUN_TEST(test_CallocPastBufferFails); + RUN_TEST(test_MallocThenReallocGrowsMemoryInPlace); + RUN_TEST(test_ReallocFailDoesNotFreeMem); + return UnityEnd(); +} diff --git a/extras/fixture/test/unity_output_Spy.c b/extras/memory/test/unity_output_Spy.c similarity index 88% rename from extras/fixture/test/unity_output_Spy.c rename to extras/memory/test/unity_output_Spy.c index be87bd58f4a32d8d58bc8bc9b26b265a4e0c6502..772fe0bdfe935dca7189912f68dd7dfd24026836 100644 --- a/extras/fixture/test/unity_output_Spy.c +++ b/extras/memory/test/unity_output_Spy.c @@ -1,16 +1,15 @@ -/* Copyright (c) 2010 James Grenning and Contributed to Unity Project - * ========================================== +/* ========================================== * Unity Project - A Test Framework for C * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams * [Released under MIT License. Please refer to license.txt for details] * ========================================== */ - +#include "unity.h" #include "unity_output_Spy.h" -#include "unity_fixture.h" #include #include +#include static int size; static int count; diff --git a/extras/fixture/test/unity_output_Spy.h b/extras/memory/test/unity_output_Spy.h similarity index 72% rename from extras/fixture/test/unity_output_Spy.h rename to extras/memory/test/unity_output_Spy.h index b30a7f13bbecc65637ce7fb7a1a38e93fc8aebfd..e2e401c488cc19bbb03a93e0292e461fd88e4248 100644 --- a/extras/fixture/test/unity_output_Spy.h +++ b/extras/memory/test/unity_output_Spy.h @@ -1,12 +1,11 @@ -/* Copyright (c) 2010 James Grenning and Contributed to Unity Project - * ========================================== +/* ========================================== * Unity Project - A Test Framework for C * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams * [Released under MIT License. Please refer to license.txt for details] * ========================================== */ -#ifndef D_unity_output_Spy_H -#define D_unity_output_Spy_H +#ifndef UNITY_OUTPUT_SPY_H +#define UNITY_OUTPUT_SPY_H void UnityOutputCharSpy_Create(int s); void UnityOutputCharSpy_Destroy(void);