Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mempler committed Dec 16, 2023
1 parent 3ea5e73 commit 12a0a4a
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 4 deletions.
10 changes: 10 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ test --test_sharding_strategy=explicit
test --test_verbose_timeout_warnings
test --test_output=errors
test --sandbox_default_allow_network=false
test --config=asan

# ASAN
build:asan --strip=never
build:asan --copt -fsanitize=address
build:asan --copt -DADDRESS_SANITIZER
build:asan --copt -O1
build:asan --copt -g
build:asan --copt -fno-omit-frame-pointer
build:asan --linkopt -fsanitize=address

# User-specific .bazelrc
try-import %workspace%/user.bazelrc
Expand Down
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ RUN wget ${BUILDTOOLS_BUILDIFIER_URL} -O /bin/buildifier && \
RUN apt-get install -y \
build-essential \
bash-completion \
gdb
gdb \
lcov

#
# Bash Completion
Expand Down
32 changes: 32 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bazel-bin/lib/runtime/allocator_test",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}
20 changes: 20 additions & 0 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cheat-sheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
To generate a code coverage report, run the following command:

```shell
bazel coverage -c dbg --nocache_test_results --combined_report=lcov //...
bazel coverage -c dbg --nocache_test_results --combined_report=lcov //lib/runtime:all
```

To view the report
Expand Down
6 changes: 5 additions & 1 deletion lib/runtime/source/Memory/SlabAllocator.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ RtlCreateSlabCache (

Status = STATUS_SUCCESS;

if ((Cache == NULL) || (ObjectSize == 0)) {
if ((Cache == NULL) || (ObjectSize == 0) || (BaseAllocator == NULL)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
Expand Down Expand Up @@ -275,6 +275,10 @@ RtlSlabFree (
}

Exit:
if (SUCCEEDED (Status)) {
*Object = NULL;
}

return Status;
}

Expand Down
3 changes: 3 additions & 0 deletions lib/runtime/source/Memory/SlabAllocatorUtilities.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ AllocateEmptySlab (
goto Exit;
}

// it is not guaranteed that PA_ALLOCATE will zero the memory
RtlZeroMemory (Slab, sizeof (SLAB));

Slab->FreeMap = (VOID*)(Slab + 1);
Slab->FreeMapEnd = ((VOID*)Slab) + (SlabPages * PAGE_SIZE_4K);
Slab->Data = (VOID*)Slab->FreeMapEnd;
Expand Down
14 changes: 13 additions & 1 deletion lib/runtime/tests/Allocators/BumpAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,16 @@ TEST_CASE ("FreePages", "[BumpAllocator]") {
STATUS status = PA_FREE(&allocator, NULL, 1, PAGE_SIZE_4K);
REQUIRE(status == STATUS_INVALID_PARAMETER);
}
}

SECTION("Free cannot be zero") {
VOID* address = NULL;
STATUS status = PA_ALLOCATE(&allocator, &address, 1, PAGE_SIZE_4K);
REQUIRE(status == STATUS_SUCCESS);

status = PA_FREE(&allocator, &address, 0, PAGE_SIZE_4K);
REQUIRE(status == STATUS_INVALID_PARAMETER);
}

delete[] (UINT8*)allocator.bumpers[0].heap_start;
delete[] (UINT8*)allocator.bumpers[1].heap_start;
}
128 changes: 128 additions & 0 deletions lib/runtime/tests/Allocators/SlabAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,39 @@ PAGE_ALLOCATOR g_MallocAllocator = {
}
};

//
// Emulation code for a full page allocator.
//
PAGE_ALLOCATOR g_NullAllocator = {
[](PAGE_ALLOCATOR* Self, VOID** Address, UINTN Pages, UINTN Align) -> STATUS {
return STATUS_OUT_OF_MEMORY;
},
[](PAGE_ALLOCATOR* Self, VOID** Address, UINTN Pages, UINTN Align) -> STATUS {
return STATUS_SUCCESS;
}
};

TEST_CASE("RtlCreateSlabCache", "[SlabAllocator]") {
SLAB_CACHE* Cache = NULL;
STATUS Status = STATUS_SUCCESS;

SECTION("Check for invalid parameter") {
Status = RtlCreateSlabCache(NULL, &g_MallocAllocator, sizeof(UINTN), SLAB_CACHE_FLAGS_NONE, NULL, NULL);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlCreateSlabCache(&Cache, NULL, sizeof(UINTN), SLAB_CACHE_FLAGS_NONE, NULL, NULL);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlCreateSlabCache(&Cache, &g_MallocAllocator, 0, SLAB_CACHE_FLAGS_NONE, NULL, NULL);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlCreateSlabCache(&Cache, &g_MallocAllocator, sizeof(UINTN), SLAB_CACHE_FLAGS_NONE, NULL, NULL);
REQUIRE(Status == STATUS_SUCCESS);

Status = RtlDestroySlabCache(&Cache);
REQUIRE(Status == STATUS_SUCCESS);
}

SECTION("Create and destroy a slab cache") {
Status = RtlCreateSlabCache(&Cache, &g_MallocAllocator, sizeof(UINTN), SLAB_CACHE_FLAGS_NONE, NULL, NULL);

Expand All @@ -64,6 +93,24 @@ TEST_CASE("RtlCreateSlabCache", "[SlabAllocator]") {
Status = RtlDestroySlabCache(&Cache);
REQUIRE(Status == STATUS_SUCCESS);
}

SECTION("Make sure we cannot allocate a cache if the base allocator is full") {
Status = RtlCreateSlabCache(&Cache, &g_NullAllocator, sizeof(UINTN), SLAB_CACHE_FLAGS_NONE, NULL, NULL);
REQUIRE(Status == STATUS_OUT_OF_MEMORY);
}
}

TEST_CASE("RtlDestroySlabCache", "[SlabAllocator]") {
SLAB_CACHE* Cache = NULL;
STATUS Status = STATUS_SUCCESS;

SECTION("Invalid arguments") {
Status = RtlDestroySlabCache(NULL);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlDestroySlabCache(&Cache);
REQUIRE(Status == STATUS_INVALID_PARAMETER);
}
}

TEST_CASE("RtlSlabAllocate", "[SlabAllocator]") {
Expand Down Expand Up @@ -92,6 +139,87 @@ TEST_CASE("RtlSlabAllocate", "[SlabAllocator]") {
REQUIRE(Cache->Full == NULL);
}

SECTION("Allocate all Objects") {
UINTN* Object = NULL;

for (UINTN i = 0; i < Cache->ObjectCount; i++) {
Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS);

// We need an object
REQUIRE(Object != NULL);
REQUIRE(Cache->Empty == NULL);

if (i <= Cache->ObjectCount - 2) {
REQUIRE(Cache->Partial != NULL);
REQUIRE(Cache->Partial->FreeCount == Cache->ObjectCount - i - 1);
REQUIRE(Cache->Partial->Next == NULL);
}
}

// We should have allocated all objects
REQUIRE(Cache->Full != NULL);
}

SECTION("Don't allocate at all") {
// Just to test the teardown code
}

SECTION("Allocate invalid arguments") {
UINTN* Object = NULL;

Status = RtlSlabAllocate(NULL, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, NULL);
REQUIRE(Status == STATUS_INVALID_PARAMETER);

Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS);

Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS);
}

SECTION("Over-allocate") {
UINTN* Object = NULL;

for (UINTN i = 0; i < Cache->ObjectCount; i++) {
Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS);
}

Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS); // This should be a new slab
REQUIRE(Cache->Full != NULL);
REQUIRE(Cache->Full->Next == NULL);
REQUIRE(Cache->Full->FreeCount == 0);

REQUIRE(Cache->Partial != NULL);
REQUIRE(Cache->Partial->Next == NULL);
REQUIRE(Cache->Partial->FreeCount == Cache->ObjectCount - 1);
}

SECTION("Allocate and free") {
UINTN* Object = NULL;

// Allocate
Status = RtlSlabAllocate(Cache, SLAB_CACHE_FLAGS_NONE, (VOID**)&Object);
REQUIRE(Status == STATUS_SUCCESS); // This should be a new slab
REQUIRE(Cache->Partial != NULL);
REQUIRE(Cache->Partial->Next == NULL);
REQUIRE(Cache->Partial->FreeCount == Cache->ObjectCount - 1);

// Free
Status = RtlSlabFree(Cache, SLAB_CACHE_FLAGS_NONE, (VOID **)&Object);
REQUIRE(Status == STATUS_SUCCESS);
REQUIRE(Object == NULL);
REQUIRE(Cache->Empty != NULL);
REQUIRE(Cache->Empty->Next == NULL);
REQUIRE(Cache->Empty->FreeCount == Cache->ObjectCount);
REQUIRE(Cache->Partial == NULL);
}

//
// Teardown
//
Expand Down

0 comments on commit 12a0a4a

Please sign in to comment.