diff --git a/extras/fixture/src/unity_fixture.c b/extras/fixture/src/unity_fixture.c index 240661f..c8275f4 100644 --- a/extras/fixture/src/unity_fixture.c +++ b/extras/fixture/src/unity_fixture.c @@ -6,21 +6,19 @@ ========================================== */ #include -#include #include "unity_fixture.h" #include "unity_internals.h" UNITY_FIXTURE_T UnityFixture; //If you decide to use the function pointer approach. -int (*outputChar)(int) = putchar; +//Build with -D UNITY_OUTPUT_CHAR=outputChar and include +//int (*outputChar)(int) = putchar; -int verbose = 0; - -void setUp(void); -void tearDown(void); +#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) void setUp(void) { /*does nothing*/ } void tearDown(void) { /*does nothing*/ } +#endif static void announceTestRun(unsigned int runNumber) { @@ -50,7 +48,7 @@ int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)) return UnityFailureCount(); } -static int selected(const char * filter, const char * name) +static int selected(const char* filter, const char* name) { if (filter == 0) return 1; @@ -67,18 +65,13 @@ static int groupSelected(const char* group) return selected(UnityFixture.GroupFilter, group); } -static void runTestCase(void) -{ - -} - void UnityTestRunner(unityfunction* setup, - unityfunction* testBody, - unityfunction* teardown, - const char * printableName, - const char * group, - const char * name, - const char * file, int line) + unityfunction* testBody, + unityfunction* teardown, + const char* printableName, + const char* group, + const char* name, + const char* file, int line) { if (testSelected(name) && groupSelected(group)) { @@ -95,7 +88,6 @@ void UnityTestRunner(unityfunction* setup, UnityMalloc_StartTest(); UnityPointer_Init(); - runTestCase(); if (TEST_PROTECT()) { setup(); @@ -115,7 +107,7 @@ void UnityTestRunner(unityfunction* setup, } } -void UnityIgnoreTest(const char * printableName, const char * group, const char * name) +void UnityIgnoreTest(const char* printableName, const char* group, const char* name) { if (testSelected(name) && groupSelected(group)) { @@ -157,24 +149,19 @@ void UnityMalloc_MakeMallocFailAfterCount(int countdown) malloc_fail_countdown = countdown; } -#ifdef malloc +// 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 -#endif - -#ifdef free #undef free -#endif - -#ifdef calloc #undef calloc -#endif - -#ifdef realloc #undef realloc -#endif +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC +static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES]; +static unsigned int heap_index; +#else #include -#include +#endif typedef struct GuardBytes { @@ -185,21 +172,35 @@ typedef struct GuardBytes static const char end[] = "END"; -void * unity_malloc(size_t size) +void* unity_malloc(size_t size) { char* mem; Guard* guard; + size_t total_size = size + sizeof(Guard) + sizeof(end); if (malloc_fail_countdown != MALLOC_DONT_FAIL) { if (malloc_fail_countdown == 0) - return 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 = (Guard*)UNITY_FIXTURE_MALLOC(size + sizeof(Guard) + sizeof(end)); guard->size = size; mem = (char*)&(guard[1]); memcpy(&mem[size], end, sizeof(end)); @@ -207,7 +208,7 @@ void * unity_malloc(size_t size) return (void*)mem; } -static int isOverrun(void * mem) +static int isOverrun(void* mem) { Guard* guard = (Guard*)mem; char* memAsChar = (char*)mem; @@ -216,16 +217,23 @@ static int isOverrun(void * mem) return strcmp(&memAsChar[guard->size], end) != 0; } -static void release_memory(void * mem) +static void release_memory(void* mem) { Guard* guard = (Guard*)mem; guard--; malloc_count--; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + if (mem == unity_heap + heap_index - guard->size - sizeof(end)) + { + heap_index -= (guard->size + sizeof(Guard) + sizeof(end)); + } +#else UNITY_FIXTURE_FREE(guard); +#endif } -void unity_free(void * mem) +void unity_free(void* mem) { int overrun; @@ -234,7 +242,7 @@ void unity_free(void * mem) return; } - overrun = isOverrun(mem);//strcmp(&memAsChar[guard->size], end) != 0; + overrun = isOverrun(mem); release_memory(mem); if (overrun) { @@ -245,18 +253,17 @@ void unity_free(void * mem) void* unity_calloc(size_t num, size_t size) { void* mem = unity_malloc(num * size); - memset(mem, 0, num*size); + if (mem == NULL) return NULL; + memset(mem, 0, num * size); return mem; } -void* unity_realloc(void * oldMem, size_t size) +void* unity_realloc(void* oldMem, size_t size) { Guard* guard = (Guard*)oldMem; -// char* memAsChar = (char*)oldMem; void* newMem; - if (oldMem == 0) - return unity_malloc(size); + if (oldMem == NULL) return unity_malloc(size); guard--; if (isOverrun(oldMem)) @@ -268,15 +275,23 @@ void* unity_realloc(void * oldMem, size_t size) if (size == 0) { release_memory(oldMem); - return 0; + return NULL; } - if (guard->size >= size) - return oldMem; + if (guard->size >= size) return oldMem; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC // Optimization if memory is expandable + if (oldMem == unity_heap + heap_index - guard->size - sizeof(end) && + heap_index + size - guard->size <= 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); - unity_free(oldMem); + release_memory(oldMem); return newMem; } @@ -285,9 +300,9 @@ void* unity_realloc(void * oldMem, size_t size) //Automatic pointer restoration functions typedef struct _PointerPair { - struct _PointerPair * next; - void ** pointer; - void * old_value; + struct _PointerPair* next; + void** pointer; + void* old_value; } PointerPair; enum {MAX_POINTERS=50}; @@ -299,7 +314,7 @@ void UnityPointer_Init(void) pointer_index = 0; } -void UnityPointer_Set(void ** pointer, void * newValue) +void UnityPointer_Set(void** pointer, void* newValue) { if (pointer_index >= MAX_POINTERS) { @@ -320,8 +335,7 @@ void UnityPointer_UndoAllSets(void) { pointer_index--; *(pointer_store[pointer_index].pointer) = - pointer_store[pointer_index].old_value; - + pointer_store[pointer_index].old_value; } } @@ -382,7 +396,13 @@ int UnityGetCommandLineOptions(int argc, const char* argv[]) { if (*(argv[i]) >= '0' && *(argv[i]) <= '9') { - UnityFixture.RepeatCount = atoi(argv[i]); + unsigned int digit = 0; + UnityFixture.RepeatCount = 0; + while (argv[i][digit] >= '0' && argv[i][digit] <= '9') + { + UnityFixture.RepeatCount *= 10; + UnityFixture.RepeatCount += (unsigned int)argv[i][digit++] - '0'; + } i++; } } diff --git a/extras/fixture/src/unity_fixture_internals.h b/extras/fixture/src/unity_fixture_internals.h index 2dd9734..1c4fcff 100644 --- a/extras/fixture/src/unity_fixture_internals.h +++ b/extras/fixture/src/unity_fixture_internals.h @@ -17,15 +17,15 @@ typedef struct _UNITY_FIXTURE_T } UNITY_FIXTURE_T; typedef void unityfunction(void); -void UnityTestRunner(unityfunction * setup, - unityfunction * body, - unityfunction * teardown, - const char * printableName, - const char * group, - const char * name, - const char * file, int line); +void UnityTestRunner(unityfunction* setup, + unityfunction* body, + unityfunction* teardown, + const char* printableName, + const char* group, + const char* name, + const char* file, int line); -void UnityIgnoreTest(const char * printableName, const char * group, const char * name); +void UnityIgnoreTest(const char* printableName, const char* group, const char* name); void UnityMalloc_StartTest(void); void UnityMalloc_EndTest(void); UNITY_COUNTER_TYPE UnityFailureCount(void); @@ -34,13 +34,8 @@ UNITY_COUNTER_TYPE UnityTestsCount(void); int UnityGetCommandLineOptions(int argc, const char* argv[]); void UnityConcludeFixtureTest(void); -void UnityPointer_Set(void ** ptr, void * newValue); +void UnityPointer_Set(void** ptr, void* newValue); void UnityPointer_UndoAllSets(void); void UnityPointer_Init(void); -void UnityAssertEqualPointer(const void * expected, - const void * actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber); - #endif /* UNITY_FIXTURE_INTERNALS_H_ */ diff --git a/extras/fixture/src/unity_fixture_malloc_overrides.h b/extras/fixture/src/unity_fixture_malloc_overrides.h index 27b9884..e01a5fb 100644 --- a/extras/fixture/src/unity_fixture_malloc_overrides.h +++ b/extras/fixture/src/unity_fixture_malloc_overrides.h @@ -10,26 +10,27 @@ #include -// This function is used by the Unity Fixture to allocate memory on -// the heap and can be overridden with platform-specific heap -// implementations. For example, when using FreeRTOS -// UNITY_FIXTURE_MALLOC becomes pvPortMalloc(). - -#ifndef UNITY_FIXTURE_MALLOC - #define UNITY_FIXTURE_MALLOC( SIZE ) malloc( ( SIZE ) ) -#else - extern void * UNITY_FIXTURE_MALLOC(size_t size); +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC +// Define this macro to remove the use of stdlib.h, malloc, and free. +// Many embedded systems do not have a heap or malloc/free by default. +// This internal unity_malloc() provides allocated memory deterministically from +// the end of an array only, unity_free() only releases from end-of-array, +// blocks are not coalesced, and memory not freed in LIFO order is stranded. + #ifndef UNITY_INTERNAL_HEAP_SIZE_BYTES + #define UNITY_INTERNAL_HEAP_SIZE_BYTES 256 + #endif #endif -// This function is used by the Unity Fixture to release memory in the -// heap and can be overridden with platform-specific heap -// implementations. For example, when using FreeRTOS -// UNITY_FIXTURE_FREE becomes vPortFree(). - -#ifndef UNITY_FIXTURE_FREE - #define UNITY_FIXTURE_FREE( PTR ) free( ( PTR ) ) +// These functions are used by the Unity Fixture 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) + #define UNITY_FIXTURE_MALLOC(size) malloc(size) + #define UNITY_FIXTURE_FREE(ptr) free(ptr) #else - extern void UNITY_FIXTURE_FREE(void *ptr); + extern void* UNITY_FIXTURE_MALLOC(size_t size); + extern void UNITY_FIXTURE_FREE(void* ptr); #endif #define malloc unity_malloc diff --git a/extras/fixture/test/Makefile b/extras/fixture/test/Makefile index 04ec722..8888d6f 100644 --- a/extras/fixture/test/Makefile +++ b/extras/fixture/test/Makefile @@ -14,6 +14,22 @@ SRC = ../src/unity_fixture.c \ INC_DIR = -I../src -I../../../src/ TARGET = fixture_tests.exe -all: +all: default noStdlibMalloc 32bits + +default: $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) + @ echo "default build" ./$(TARGET) + +32bits: + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -m32 + @ echo "32bits build" + ./$(TARGET) + +noStdlibMalloc: + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -D UNITY_EXCLUDE_STDLIB_MALLOC + @ echo "build with noStdlibMalloc" + ./$(TARGET) + +clangEverything: + $(CC) $(CFLAGS) $(DEFINES) $(SRC) $(INC_DIR) -o $(TARGET) -m64 -Weverything # || true #prevents make from failing diff --git a/extras/fixture/test/main/AllTests.c b/extras/fixture/test/main/AllTests.c index 7d0577e..7cfbe8e 100644 --- a/extras/fixture/test/main/AllTests.c +++ b/extras/fixture/test/main/AllTests.c @@ -11,7 +11,8 @@ static void runAllTests(void) { RUN_TEST_GROUP(UnityFixture); RUN_TEST_GROUP(UnityCommandOptions); - RUN_TEST_GROUP(LeakDetection) + 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 667f1f1..9ca3bfd 100644 --- a/extras/fixture/test/unity_fixture_Test.c +++ b/extras/fixture/test/unity_fixture_Test.c @@ -79,9 +79,10 @@ TEST(UnityFixture, ReallocLargerNeeded) { void* m1 = malloc(10); void* m2; + CHECK(m1); strcpy((char*)m1, "123456789"); m2 = realloc(m1, 15); - CHECK(m1 != m2); + // CHECK(m1 != m2); //Depends on implementation STRCMP_EQUAL("123456789", m2); free(m2); } @@ -104,6 +105,7 @@ 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]); @@ -134,7 +136,7 @@ TEST(UnityFixture, PointerSet) TEST(UnityFixture, FreeNULLSafety) { - unity_free(NULL); + free(NULL); } //------------------------------------------------------------ @@ -288,7 +290,11 @@ TEST_GROUP(LeakDetection); TEST_SETUP(LeakDetection) { +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + UnityOutputCharSpy_Create(200); +#else UnityOutputCharSpy_Create(1000); +#endif } TEST_TEAR_DOWN(LeakDetection) @@ -323,6 +329,7 @@ TEST(LeakDetection, DetectsLeak) 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(); @@ -341,6 +348,7 @@ TEST(LeakDetection, BufferOverrunFoundDuringFree) TEST_IGNORE(); #else void* m = malloc(10); + TEST_ASSERT_NOT_NULL(m); char* s = (char*)m; s[10] = (char)0xFF; UnityOutputCharSpy_Enable(1); @@ -360,6 +368,7 @@ TEST(LeakDetection, BufferOverrunFoundDuringRealloc) TEST_IGNORE(); #else void* m = malloc(10); + TEST_ASSERT_NOT_NULL(m); char* s = (char*)m; s[10] = (char)0xFF; UnityOutputCharSpy_Enable(1); @@ -371,3 +380,57 @@ TEST(LeakDetection, BufferOverrunFoundDuringRealloc) CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); #endif } + +TEST_GROUP(InternalMalloc); + +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); + TEST_ASSERT_NOT_NULL(m); + void* n = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + TEST_ASSERT_NULL(n); + free(m); +#endif +} + +TEST(InternalMalloc, CallocPastBufferFails) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + TEST_ASSERT_NOT_NULL(m); + void* n = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + TEST_ASSERT_NULL(n); + free(m); +#endif +} + +TEST(InternalMalloc, MallocThenReallocGrowsMemoryInPlace) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + TEST_ASSERT_NOT_NULL(m); + void* n = realloc(m, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 9); + TEST_ASSERT_EQUAL(m, n); + free(n); +#endif +} + +TEST(InternalMalloc, ReallocFailDoesNotFreeMem) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + TEST_ASSERT_NOT_NULL(m); + void* n1 = malloc(10); + void* out_of_mem = realloc(n1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + TEST_ASSERT_NULL(out_of_mem); + void* n2 = malloc(10); + TEST_ASSERT_NOT_EQUAL(n2, n1); + free(n2); + free(n1); + free(m); +#endif +} diff --git a/extras/fixture/test/unity_fixture_TestRunner.c b/extras/fixture/test/unity_fixture_TestRunner.c index 6c1a90c..4f5eefc 100644 --- a/extras/fixture/test/unity_fixture_TestRunner.c +++ b/extras/fixture/test/unity_fixture_TestRunner.c @@ -41,3 +41,11 @@ TEST_GROUP_RUNNER(LeakDetection) RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringFree); RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringRealloc); } + +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/fixture/test/unity_output_Spy.c b/extras/fixture/test/unity_output_Spy.c index 68188e5..36bcf37 100644 --- a/extras/fixture/test/unity_output_Spy.c +++ b/extras/fixture/test/unity_output_Spy.c @@ -22,14 +22,15 @@ void UnityOutputCharSpy_Create(int s) size = s; count = 0; spy_enable = 0; - buffer = UNITY_FIXTURE_MALLOC(size); + buffer = malloc(size); + TEST_ASSERT_NOT_NULL_MESSAGE(buffer, "Internal malloc failed in Spy Create():" __FILE__); memset(buffer, 0, size); } void UnityOutputCharSpy_Destroy(void) { size = 0; - UNITY_FIXTURE_FREE(buffer); + free(buffer); } int UnityOutputCharSpy_OutputChar(int c)