diff options
Diffstat (limited to 'libparc/parc/algol/test/test_parc_SafeMemory.c')
-rw-r--r-- | libparc/parc/algol/test/test_parc_SafeMemory.c | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/libparc/parc/algol/test/test_parc_SafeMemory.c b/libparc/parc/algol/test/test_parc_SafeMemory.c new file mode 100644 index 00000000..53c0b3c8 --- /dev/null +++ b/libparc/parc/algol/test/test_parc_SafeMemory.c @@ -0,0 +1,813 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + */ +#include "../parc_SafeMemory.c" + +#include <LongBow/unit-test.h> + +#include <fcntl.h> + +LONGBOW_TEST_RUNNER(safetyMemory) +{ + LONGBOW_RUN_TEST_FIXTURE(Static); + LONGBOW_RUN_TEST_FIXTURE(ReportAllocation); + LONGBOW_RUN_TEST_FIXTURE(Global); + LONGBOW_RUN_TEST_FIXTURE(Errors); + + LONGBOW_RUN_TEST_FIXTURE(Performance); +} + +LONGBOW_TEST_RUNNER_SETUP(safetyMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_RUNNER_TEARDOWN(safetyMemory) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Static) +{ + LONGBOW_RUN_TEST_CASE(Static, PARCSafeMemory_Report); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_StateToString); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN); + LONGBOW_RUN_TEST_CASE(Static, _parcSafeMemory_FormatPrefix); + LONGBOW_RUN_TEST_CASE(Static, _computeUsableMemoryLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Static) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Static, PARCSafeMemory_Report) +{ + size_t expectedSize = 100; + void *memory = parcSafeMemory_Allocate(expectedSize); + int fd = open("/dev/null", O_WRONLY); + _parcSafeMemory_Report(memory, fd); + close(fd); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_StateToString) +{ + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OK), + "PARCSafeMemoryState_OK cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_MISMATCHED), + "PARCSafeMemoryState_MISMATCHED cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_UNDERRUN), + "PARCSafeMemoryState_UNDERRUN cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_OVERRUN), + "PARCSafeMemoryState_OVERRUN cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_NOTHINGALLOCATED), + "PARCSafeMemoryState_NOTHINGALLOCATED cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(PARCSafeMemoryState_ALREADYFREE), + "PARCSafeMemoryState_ALREADYFREE cannot be a NULL string."); + assertNotNull(_parcSafeMemory_StateToString(-1), + "Garbage cannot be represented by a NULL string."); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_OK) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char origin[100]; // just some number + + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) origin, expectedLength, expectedAlignment); + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory); + assertTrue(actual == PARCSafeMemoryState_OK, + "Expected PARCSafeMemoryState_OK, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_ALREADYFREE) +{ + PARCSafeMemoryUsable *usable = parcSafeMemory_Allocate(10); + PARCSafeMemoryUsable *saved = usable; + + parcSafeMemory_Deallocate((void **) &usable); + + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(saved); + assertTrue(actual == PARCSafeMemoryState_ALREADYFREE, + "Expected PARCSafeMemoryState_ALREADYFREE, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_GetPrefixState_UNDERRUN) +{ + char *usable = parcSafeMemory_Allocate(10); + + char savedByte = usable[-1]; + usable[-1] = 0; + + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState((PARCSafeMemoryUsable *) usable); + assertTrue(actual == PARCSafeMemoryState_UNDERRUN, + "Expected PARCSafeMemoryState_UNDERRUN, actual = %d", actual); + usable[-1] = savedByte; + parcSafeMemory_Deallocate((void **) &usable); +} + +LONGBOW_TEST_CASE(Static, _parcSafeMemory_FormatPrefix) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *) - 1; + char base[100]; // just some number + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + assertNull(memory, + "Expected _parcSafeMemory_FormatPrefix to return NULL for bad alignment specification."); +} + +LONGBOW_TEST_CASE(Static, _computeUsableMemoryLength) +{ + size_t actual = _computeUsableMemoryLength(100, sizeof(void *)); + + // The result must be >= to the requested length and an even multiple of sizeof(void *) + assertTrue(actual >= 100 && (actual % sizeof(void *)) == 0, + "Expected the result to be >= to the requested length and an even multiple of sizeof(void *)"); +} + +LONGBOW_TEST_FIXTURE(ReportAllocation) +{ + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty); + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One); + LONGBOW_RUN_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Empty) +{ + _parcSafeMemory_DeallocateAll(); + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + assertTrue(result == 0, "Expected 0, was %zd", result); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_One) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + assertTrue(result == 1, "Expected 1, was %zd", result); + + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(ReportAllocation, parcSafeMemory_ReportAllocation_Deallocated) +{ + size_t size = 100; + void *memory = parcSafeMemory_Allocate(size); + assertTrue(parcSafeMemory_Outstanding() != 0, "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_OK, "Expected uncorrupted memory."); + + int fd = open("/dev/null", O_WRONLY); + size_t result = parcSafeMemory_ReportAllocation(fd); + close(fd); + + assertTrue(result == 0, "Expected 0, was %zd", result); +} + +LONGBOW_TEST_FIXTURE_SETUP(ReportAllocation) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(ReportAllocation) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE(Global) +{ + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_MemAlign); + + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger); + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero); + LONGBOW_RUN_TEST_CASE(Global, PARCSafeMemory_Validate); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_AllocateAndClear); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Reallocate); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_True); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_IsValid_False); + + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_Display_NULL); + + LONGBOW_RUN_TEST_CASE(Global, compute_prefix_length); + LONGBOW_RUN_TEST_CASE(Global, _parcSafeMemory_FormatMemory); + LONGBOW_RUN_TEST_CASE(Global, memory_prefix_format); + LONGBOW_RUN_TEST_CASE(Global, memory_prefix_validate); + LONGBOW_RUN_TEST_CASE(Global, memory_suffix_format); + LONGBOW_RUN_TEST_CASE(Global, memory_suffix_validate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long); + LONGBOW_RUN_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short); + LONGBOW_RUN_TEST_CASE(Global, validateAlignment); +} + +LONGBOW_TEST_FIXTURE_SETUP(Global) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Global) +{ + assertTrue(parcSafeMemory_Outstanding() == 0, "Expected 0 outstanding allocations") + { + printf("Leaking test case: %s", longBowTestCase_GetName(testCase)); + } + return LONGBOW_STATUS_SUCCEEDED; +} + + +LONGBOW_TEST_CASE(Global, validateAlignment) +{ + assertTrue(_alignmentIsValid(sizeof(void *)), + "Expected alignment of sizeof(void *) failed."); + assertTrue(_alignmentIsValid(16), + "Expected alignment of 16 failed."); +} + +LONGBOW_TEST_CASE(Global, compute_prefix_length) +{ + // Test that the result is a multiple of the alignment value and greater than the size of _MemoryPrefix. + for (int i = 0; i < 9; i++) { + size_t alignment = 1 << i; + size_t actual = _computePrefixLength(alignment); + assertTrue((actual & (alignment - 1)) == 0, + "Alignment needs to be a multiple of %zd", alignment); + } +} + +LONGBOW_TEST_CASE(Global, memory_prefix_format) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix(memory); + + assertAligned(prefix, sizeof(void *), + "prefix address %p is not aligned to %d", + memory, expectedAlignment); + assertAligned(memory, expectedAlignment, + "memory address %p is not aligned to %d", + memory, expectedAlignment); + + assertTrue((void *) prefix >= (void *) base, + "Expected >= %p, actual %p", (void *) base, (void *) prefix); + assertTrue(_parcSafeMemory_PrefixMagic == prefix->magic, + "Prefix magic is wrong."); + assertTrue(expectedLength == prefix->requestedLength, + "Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + assertTrue(expectedAlignment == prefix->alignment, + "Expected alignment %d, actual %zu", + expectedAlignment, prefix->alignment); + assertTrue(_parcSafeMemory_Guard == prefix->guard, + "Prefix guard is wrong."); +} + +LONGBOW_TEST_CASE(Global, memory_suffix_format) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory); + assertAligned(suffix, sizeof(void *), "suffix pointer is not aligned to %zu", sizeof(void*)); +} + +LONGBOW_TEST_CASE(Global, memory_suffix_validate) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + _MemorySuffix *suffix = _parcSafeMemory_FormatSuffix(memory); + assertAligned(suffix, sizeof(void *), + "suffix pointer is not aligned to %zu", sizeof(void*)); + + PARCSafeMemoryState suffixState = _parcSafeMemory_GetSuffixState(memory); + assertTrue(suffixState == PARCSafeMemoryState_OK, + "Expected PARCSafeMemoryState_OK suffix state, actual %s", _parcSafeMemory_StateToString(suffixState)); +} + +LONGBOW_TEST_CASE(Global, memory_prefix_validate) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + + void *memory = _parcSafeMemory_FormatPrefix((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + PARCSafeMemoryState actual = _parcSafeMemory_GetPrefixState(memory); + assertTrue(actual == PARCSafeMemoryState_OK, + "Expected valid prefix, actual = %d", actual); +} + +LONGBOW_TEST_CASE(Global, _parcSafeMemory_FormatMemory) +{ + size_t expectedLength = 5; + int expectedAlignment = sizeof(void *); + char base[100]; + + void *memory = _parcSafeMemory_FormatMemory((PARCSafeMemoryOrigin *) base, expectedLength, expectedAlignment); + + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + + assertTrue(state == PARCSafeMemoryState_OK, + "Memory did not validate. Actual %d", state); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + assertTrue(memory != NULL, + "Expected non-NULL return."); + + assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK, + "Prefix did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_MemAlign) +{ + void *memory; + size_t size = 100; + + int failure = parcSafeMemory_MemAlign(&memory, sizeof(void *), size); + assertTrue(failure == 0, + "parcSafeMemory_MemAlign failed: %d", failure); + + assertTrue(memory != NULL, + "Expected non-NULL return."); + + assertTrue((_parcSafeMemory_GetPrefixState(memory)) == PARCSafeMemoryState_OK, + "Prefix did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_ReportAllocation) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + assertTrue(memory != NULL, "Expected non-NULL return."); + PARCSafeMemoryState prefixState = _parcSafeMemory_GetPrefixState(memory); + assertTrue(prefixState == PARCSafeMemoryState_OK, + "Prefix did not validate."); + + parcSafeMemory_ReportAllocation(1); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Validate) +{ + void *memory; + size_t size = 100; + + memory = parcSafeMemory_Allocate(size); + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Larger) +{ + void *memory = parcSafeMemory_Allocate(100); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Expected memory to be OK."); + + size_t expectedLength = 100 + 1; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) memory) != PARCSafeMemoryState_OK, + "Expected original memory to NOT be OK."); + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK, + "Expected new memory to be OK."); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory); + assertTrue(prefix->requestedLength == expectedLength, + "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + + for (int i = 0; i < 100; i++) { + assertTrue(((unsigned char *) newMemory)[i] == i, + "PARCSafeMemory_Realloc did not copy old memory correctly"); + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory); + parcSafeMemory_Deallocate((void **) &newMemory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected old memory to be invalid."); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_Realloc_Smaller) +{ + void *memory = parcSafeMemory_Allocate(100); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + size_t expectedLength = 100 - 1; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected original memory to NOT be OK."); + assertTrue(_parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory) == PARCSafeMemoryState_OK, + "Expected new memory to be OK."); + + _MemoryPrefix *prefix = _parcSafeMemory_GetPrefix((PARCSafeMemoryUsable *) newMemory); + assertTrue(prefix->requestedLength == expectedLength, + "Prefix Expected length %zd, actual %zd", expectedLength, prefix->requestedLength); + + for (int i = 0; i < expectedLength; i++) { + assertTrue(((unsigned char *) newMemory)[i] == i, + "PARCSafeMemory_Realloc did not copy correctly"); + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState((PARCSafeMemoryUsable *) newMemory); + parcSafeMemory_Deallocate((void **) &newMemory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected PARCSafeMemory_Deallocate of new memory to be OK, actual =%d", state); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected old memory to be invalid."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate_Zero) +{ + void *memory = parcSafeMemory_Allocate(100); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < 100; i++) { + ((unsigned char *) memory)[i] = i; + } + + size_t expectedLength = 0; + unsigned char *newMemory = parcSafeMemory_Reallocate(memory, expectedLength); + + assertTrue(newMemory == NULL, + "Expected NULL, actual %p", (void *) newMemory); + + parcSafeMemory_Deallocate(&memory); + assertNull(memory, + "Expected memory pointer to be NULL."); +} + +LONGBOW_TEST_CASE(Global, PARCSafeMemory_DoubleFree) +{ + size_t expectedSize = 100; + + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < expectedSize; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_OK, + "Expected memory to validate"); + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + assertTrue(state == PARCSafeMemoryState_UNDERRUN, + "Expected memory to be underrun (double free)."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate) +{ + char *string = "hello world"; + char *actual = parcSafeMemory_StringDuplicate(string, strlen(string)); + + assertTrue(strcmp(string, actual) == 0, + "Expected %s, actual %s", string, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Long) +{ + char *string = "hello world"; + char *actual = parcSafeMemory_StringDuplicate(string, SIZE_MAX); + + assertTrue(strcmp(string, actual) == 0, + "Expected %s, actual %s", string, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_StringDuplicate_Short) +{ + char *string = "hello world"; + char *expected = "hello"; + char *actual = parcSafeMemory_StringDuplicate(string, 5); + + assertTrue(strcmp(expected, actual) == 0, + "Expected %s, actual %s", expected, actual); + parcSafeMemory_Deallocate((void **) &actual); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadAlignment) +{ + void *result; + size_t alignment = 3; + size_t size = 100; + + int failure = parcSafeMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcSafeMemory_MemAlign failed to report bad aligment specification"); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Allocate_BadSize) +{ + void *result; + size_t alignment = sizeof(void *); + size_t size = 0; + + int failure = parcSafeMemory_MemAlign(&result, alignment, size); + assertTrue(failure == EINVAL, + "parcSafeMemory_MemAlign failed to report bad aligment specification"); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_AllocateAndClear) +{ + void *result; + size_t size = 100; + + result = parcSafeMemory_AllocateAndClear(size); + assertNotNull(result, + "parcSafeMemory_AllocateAndClear failed: NULL result."); + + for (size_t i = 0; i < size; i++) { + assertTrue(((char *) result)[i] == 0, + "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i); + } + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Reallocate) +{ + size_t size = 100; + + void *result = parcSafeMemory_AllocateAndClear(size); + assertNotNull(result, + "parcSafeMemory_Allocate failed: NULL."); + + for (size_t i = 0; i < size; i++) { + assertTrue(((char *) result)[i] == 0, + "parcSafeMemory_AllocateAndClear failed to zero memory at index %zd", i); + } + + result = parcSafeMemory_Reallocate(result, size * 2); + + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Deallocate_NothingAllocated) +{ + void *result = 0; + + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_True) +{ + void *result = parcSafeMemory_AllocateAndClear(5); + + assertTrue(parcSafeMemory_IsValid(result), "Expected properly allocated memory to be valid PARC Safe Memory."); + + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_IsValid_False) +{ + char *memory[10]; + + assertFalse(parcSafeMemory_IsValid(memory), "Expected improperly allocated memory to be invalid PARC Safe Memory."); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Display) +{ + void *result = parcSafeMemory_AllocateAndClear(5); + + parcSafeMemory_Display(result, 0); + parcSafeMemory_Deallocate(&result); +} + +LONGBOW_TEST_CASE(Global, parcSafeMemory_Display_NULL) +{ + parcSafeMemory_Display(NULL, 0); +} + +LONGBOW_TEST_FIXTURE(Errors) +{ + LONGBOW_RUN_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL); + LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Overrun); + LONGBOW_RUN_TEST_CASE(Errors, PARCSafeMemory_Deallocate_Underrun); +} + +LONGBOW_TEST_FIXTURE_SETUP(Errors) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Errors) +{ + // The tests purposefully wreck the various per-allocation accounting structures for the allocated memory in order to test for + // properly catching the overrun, underrun or other damage. + // As a result any cleanup of allocated memory is not possible, so these tests leak allocated memory. + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_CASE(Errors, parcSafeMemory_Reallocate_NULL) +{ + void *result = NULL; + size_t size = 100; + + result = parcSafeMemory_Reallocate(result, size * 2); + + assertTrue(parcSafeMemory_Outstanding() == 1, + "Expected 1 outstanding allocation, actual %d", parcSafeMemory_Outstanding()); + parcSafeMemory_Deallocate(&result); + assertTrue(parcSafeMemory_Outstanding() == 0, + "Expected 0 outstanding allocations, actual %d", parcSafeMemory_Outstanding()); +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Underrun, .event = &LongBowTrapUnexpectedStateEvent) +{ + size_t expectedSize = sizeof(void *) * 2; + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (int i = -2; i < (int) expectedSize; i++) { + ((unsigned char *) memory)[i] = (unsigned char) i; + } + + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_UNDERRUN, + "Memory did not underrun."); + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + PARCSafeMemoryState state = _parcSafeMemory_GetState(memory); + parcSafeMemory_Deallocate(&memory); + + assertTrue(state == PARCSafeMemoryState_UNDERRUN, + "Expected memory to be underrun"); +} + +LONGBOW_TEST_CASE_EXPECTS(Errors, PARCSafeMemory_Deallocate_Overrun, .event = &LongBowTrapUnexpectedStateEvent) +{ + size_t expectedSize = 100; + void *memory = parcSafeMemory_Allocate(expectedSize); + assertTrue(_parcSafeMemory_GetState(memory) == PARCSafeMemoryState_OK, + "Memory did not validate."); + + for (unsigned char i = 0; i < expectedSize + 5; i++) { + ((unsigned char *) memory)[i] = i; + } + + assertTrue(parcSafeMemory_Outstanding() != 0, + "No memory allocated!"); + assertTrue(_parcSafeMemory_GetState(memory) != PARCSafeMemoryState_OK, + "Expected not OK, actual %s", _parcSafeMemory_StateToString(_parcSafeMemory_GetState(memory))); + // this is expected to fail + parcSafeMemory_Deallocate(&memory); +} + +LONGBOW_TEST_FIXTURE_OPTIONS(Performance, .enabled = false) +{ + LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase); + LONGBOW_RUN_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase); + + LONGBOW_RUN_TEST_CASE(Performance, _computeUsableMemoryLength); +} + +LONGBOW_TEST_FIXTURE_SETUP(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +LONGBOW_TEST_FIXTURE_TEARDOWN(Performance) +{ + return LONGBOW_STATUS_SUCCEEDED; +} + +void *memory[1000000]; + +LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_WorstCase) +{ + size_t size = 100; + + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + memory[i] = parcSafeMemory_Allocate(size); + } + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + parcSafeMemory_Deallocate(&memory[i]); + } +} + +LONGBOW_TEST_CASE(Performance, parcSafeMemory_AllocateDeallocate_1000000_BestCase) +{ + size_t size = 100; + + for (int i = 0; i < sizeof(memory) / sizeof(memory[0]); i++) { + memory[i] = parcSafeMemory_Allocate(size); + } + + int i = sizeof(memory) / sizeof(memory[0]); + do { + i--; + parcSafeMemory_Deallocate(&memory[i]); + } while (i > 0); +} + +LONGBOW_TEST_CASE(Performance, _computeUsableMemoryLength) +{ + for (int i = 0; i < 100000000; i++) { + size_t alignment = sizeof(void *); + size_t requestedLength = 10; + _computeUsableMemoryLength(requestedLength, alignment); + } +} + +int +main(int argc, char *argv[argc]) +{ + LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(safetyMemory); + int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner); + longBowTestRunner_Destroy(&testRunner); + exit(exitStatus); +} |