diff --git a/build.sh b/build.sh index 2949aac..649d62c 100644 --- a/build.sh +++ b/build.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -gcc -o bld code/build_main.cpp -g +gcc -o bld code/build_main.cpp -g ./bld diff --git a/build_file.cpp b/build_file.cpp index 352beea..0b908ea 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -20,13 +20,13 @@ int CompileFiles(Strs cc, Strs files) { Str exe = FilenameWithoutExt(files[0]); Str filestr = Merge(files); if (cc == "gcc") { - result = OS_SystemF("g++ -o %Q.exe %Q -g -Wno-write-strings", exe, filestr); + result = OS_SystemF("g++ -o %Q.exe %Q -g -Wno-write-strings -fsanitize=address", exe, filestr); } else if (cc == "clang") { - result = OS_SystemF("clang++ -std=c++11 -o %Q.exe %Q -g -Wno-writable-strings", exe, filestr); + result = OS_SystemF("clang++ -std=c++11 -o %Q.exe %Q -g -Wno-writable-strings -fsanitize=address", exe, filestr); } else { - result = OS_SystemF("cl -Fe:%Q.exe %Q -Zi -WX -W3 -wd4200 -diagnostics:column -nologo -D_CRT_SECURE_NO_WARNINGS", exe, filestr); + result = OS_SystemF("cl -Fe:%Q.exe %Q -Zi -WX -W3 -wd4200 -diagnostics:column -nologo -D_CRT_SECURE_NO_WARNINGS -fsanitize=address -RTC1", exe, filestr); } if (result == 0) result = OS_SystemF(IF_WINDOWS_ELSE("", "./") "%Q.exe", exe); return result; diff --git a/code/arena.c b/code/arena.c index ce88687..13d2b86 100644 --- a/code/arena.c +++ b/code/arena.c @@ -33,6 +33,40 @@ MA_API void MA_MemoryCopy(void *dst, void *src, size_t size) { #endif #endif +// Marks memory region [addr, addr+size) as unaddressable. +// This memory must be previously allocated by the user program. Accessing +// addresses in this region from instrumented code is forbidden until +// this region is unpoisoned. This function is not guaranteed to poison +// the whole region - it may poison only subregion of [addr, addr+size) due +// to ASan alignment restrictions. +// Method is NOT thread-safe in the sense that no two threads can +// (un)poison memory in the same memory region simultaneously. +void __asan_poison_memory_region(void const volatile *addr, size_t size); +// Marks memory region [addr, addr+size) as addressable. +// This memory must be previously allocated by the user program. Accessing +// addresses in this region is allowed until this region is poisoned again. +// This function may unpoison a superregion of [addr, addr+size) due to +// ASan alignment restrictions. +// Method is NOT thread-safe in the sense that no two threads can +// (un)poison memory in the same memory region simultaneously. +void __asan_unpoison_memory_region(void const volatile *addr, size_t size); + +// User code should use macros instead of functions. +#if defined(__clang__) + #if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) + #define ASAN_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) + #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + __asan_unpoison_memory_region((addr), (size)) + #endif +#endif +#ifndef ASAN_POISON_MEMORY_REGION + #define ASAN_POISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) + #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ + ((void)(addr), (void)(size)) +#endif + MA_API size_t MA_GetAlignOffset(size_t size, size_t align) { size_t mask = align - 1; size_t val = size & mask; @@ -71,7 +105,9 @@ MA_StaticFunc uint8_t *MV__AdvanceCommit(MV_Memory *m, size_t *commit_size, size MA_API void MA_PopToPos(MA_Arena *arena, size_t pos) { MA_ASSERT(arena->len >= arena->base_len); pos = MA_CLAMP(pos, arena->base_len, arena->len); + size_t size = arena->len - pos; arena->len = pos; + ASAN_POISON_MEMORY_REGION(arena->memory.data + pos, size); } MA_API void MA_PopSize(MA_Arena *arena, size_t size) { @@ -122,6 +158,7 @@ MA_API void *MA_PushSizeNonZeroed(MA_Arena *a, size_t size) { uint8_t *result = a->memory.data + aligned_len; a->len += size_with_alignment; MA_ASSERT(a->len <= a->memory.commit); + ASAN_UNPOISON_MEMORY_REGION(result, a->len); return (void *)result; } @@ -133,6 +170,7 @@ MA_API void *MA_PushSize(MA_Arena *arena, size_t size) { MA_API void MA_InitEx(MA_Arena *a, size_t reserve) { a->memory = MV_Reserve(reserve); + ASAN_POISON_MEMORY_REGION(a->memory.data, a->memory.reserve); a->alignment = MA_DEFAULT_ALIGNMENT; } diff --git a/test/test_array.cpp b/test/test_array.cpp index 7a66766..a87dcac 100644 --- a/test/test_array.cpp +++ b/test/test_array.cpp @@ -47,6 +47,7 @@ void TestRemoveForLoop() { IO_Assert(array[5] == 6); IO_Assert(array[3] == 3); IO_Assert(array.len == 99); + array.dealloc(); } void TestBasic() { @@ -114,6 +115,8 @@ void TestCopy() { IO_Assert(b.cap == b.len && b.len == a.len); IO_Assert(a.len == c.len && a.cap == c.cap); + + a.dealloc(); } int main() { diff --git a/test/test_table.cpp b/test/test_table.cpp index 9ae6d22..d723879 100644 --- a/test/test_table.cpp +++ b/test/test_table.cpp @@ -34,6 +34,7 @@ void TestStrings() { IO_Assert(table.gets("1")->i == 1); IO_Assert(table.gets("2")->i == 2); IO_Assert(table.gets("3")->i == 3); + table.dealloc(); } int main() {