Get latest changes from Primitive Indexer

This commit is contained in:
2026-06-23 21:13:06 +10:00
parent ab4eaa5bb3
commit 544669d3cb
11 changed files with 786 additions and 416 deletions
+117 -49
View File
@@ -16,6 +16,54 @@ enum DN_ArenaUAFCheckReportType_
DN_ArenaUAFCheckReportType_TempEndOutOfOrder,
};
DN_API bool DN_VerifyArgsF(DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...)
{
bool result = expr;
if (result)
return result;
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
{
DN_Str8Builder builder = DN_Str8BuilderFromArena(&scratch.arena);
// NOTE: Log message prefix
DN_Str8BuilderAppendF(&builder, "Verify [%.*s] failed%s", DN_Str8PrintFmt(expr_str8), fmt ? ". " : "");
// NOTE: Log user message
if (fmt) {
va_list args;
va_start(args, fmt);
DN_Str8BuilderAppendFV(&builder, fmt, args);
va_end(args);
}
// NOTE: Log stack trace
if (DN_PARANOIA_LEVEL) {
if (type == DN_VerifyType_Nil) {
DN_Str8 trace = DN_Str8FromStackTraceNowArena(&scratch.arena, 128 /*limit*/, 4 /*skip*/);
DN_Str8BuilderAppendF(&builder, "\nTrace:\n ");
DN_Str8BuilderAppendRef(&builder, DN_Str8PadNewLinesArena(trace, DN_Str8Lit(" "), &scratch.arena));
}
}
DN_Str8 log = DN_Str8FromStr8BuilderArena(&builder, &scratch.arena);
DN_LogType log_type = type == DN_VerifyType_Nil ? DN_LogType_Error : DN_LogType_Warning;
DN_LogTypeParam log_type_param = DN_LogTypeParamFromType(log_type);
DN_LogPrintF(log_type_param, call_site, DN_LogFlags_Nil, "%.*s", DN_Str8PrintFmt(log));
}
DN_TCScratchEnd(&scratch);
if (type == DN_VerifyType_Nil && DN_PARANOIA_LEVEL) {
DN_DebugBreak;
}
return result;
}
DN_API bool DN_VerifyArgs(DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8) {
bool result = DN_VerifyArgsF(type, expr, call_site, expr_str8, /*fmt=*/ 0);
return result;
}
DN_API bool DN_MemStartsWith(void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size)
{
bool result = false;
@@ -159,7 +207,7 @@ DN_API DN_CPUReport DN_CPUGetReport()
int const EXTENDED_FUNC_BASE_EAX = 0x8000'0000;
int const REGISTER_SIZE = sizeof(fn_0000_[0].reg.eax);
// NOTE: Query standard/extended numbers ///////////////////////////////////////////////////////
// NOTE: Query standard/extended numbers
{
DN_CPUIDArgs args = {};
@@ -173,11 +221,11 @@ DN_API DN_CPUReport DN_CPUGetReport()
fn_8000_[0] = DN_CPUID(args);
}
// NOTE: Extract function count ////////////////////////////////////////////////////////////////
// NOTE: Extract function count
int const STANDARD_FUNC_MAX_EAX = fn_0000_[0x0000].reg.eax;
int const EXTENDED_FUNC_MAX_EAX = fn_8000_[0x0000].reg.eax;
// NOTE: Enumerate all CPUID results for the known function counts /////////////////////////////
// NOTE: Enumerate all CPUID results for the known function counts
{
DN_AssertF((STANDARD_FUNC_MAX_EAX + 1) <= DN_ArrayCountI(fn_0000_),
"Max standard count is %d",
@@ -199,14 +247,14 @@ DN_API DN_CPUReport DN_CPUGetReport()
}
}
// NOTE: Query CPU vendor //////////////////////////////////////////////////////////////////////
// NOTE: Query CPU vendor
{
DN_Memcpy(result.vendor + 0, &fn_8000_[0x0000].reg.ebx, REGISTER_SIZE);
DN_Memcpy(result.vendor + 4, &fn_8000_[0x0000].reg.edx, REGISTER_SIZE);
DN_Memcpy(result.vendor + 8, &fn_8000_[0x0000].reg.ecx, REGISTER_SIZE);
}
// NOTE: Query CPU brand ///////////////////////////////////////////////////////////////////////
// NOTE: Query CPU brand
if (EXTENDED_FUNC_MAX_EAX >= (EXTENDED_FUNC_BASE_EAX + 4)) {
DN_Memcpy(result.brand + 0, &fn_8000_[0x0002].reg.eax, REGISTER_SIZE);
DN_Memcpy(result.brand + 4, &fn_8000_[0x0002].reg.ebx, REGISTER_SIZE);
@@ -226,7 +274,7 @@ DN_API DN_CPUReport DN_CPUGetReport()
DN_Assert(result.brand[sizeof(result.brand) - 1] == 0);
}
// NOTE: Query CPU features //////////////////////////////////////////////////////////////////
// NOTE: Query CPU features
for (DN_USize ext_index = 0; ext_index < DN_CPUFeature_Count; ext_index++) {
bool available = false;
@@ -288,7 +336,7 @@ DN_API DN_CPUReport DN_CPUGetReport()
case DN_CPUFeature_TscInvariant: available = (fn_8000_[0x0007].reg.edx & (1 << 8)); break;
case DN_CPUFeature_VAES: available = (fn_0000_[0x0007].reg.ecx & (1 << 9)); break;
case DN_CPUFeature_VPCMULQDQ: available = (fn_0000_[0x0007].reg.ecx & (1 << 10)); break;
case DN_CPUFeature_Count: DN_InvalidCodePath; break;
case DN_CPUFeature_Count: DN_AssertInvalidCodePath; break;
}
if (available)
@@ -298,7 +346,6 @@ DN_API DN_CPUReport DN_CPUGetReport()
return result;
}
// NOTE: DN_TicketMutex ////////////////////////////////////////////////////////////////////////////
DN_API void DN_TicketMutex_Begin(DN_TicketMutex *mutex)
{
DN_UInt ticket = DN_AtomicAddU32(&mutex->ticket, 1);
@@ -341,7 +388,7 @@ DN_API bool DN_TicketMutex_CanLock(DN_TicketMutex const *mutex, DN_UInt ticket)
#endif
#endif
// NOTE: DN_Bit ////////////////////////////////////////////////////////////////////////////////////
// NOTE: DN_Bit
DN_API void DN_BitUnsetInplace(DN_USize *flags, DN_USize bitfield)
{
*flags = (*flags & ~bitfield);
@@ -354,7 +401,13 @@ DN_API void DN_BitSetInplace(DN_USize *flags, DN_USize bitfield)
DN_API bool DN_BitIsSet(DN_USize bits, DN_USize bits_to_set)
{
auto result = DN_Cast(bool)((bits & bits_to_set) == bits_to_set);
bool result = DN_Cast(bool)((bits & bits_to_set) == bits_to_set);
return result;
}
DN_API bool DN_BitIsAny(DN_USize bits, DN_USize bits_to_check)
{
bool result = DN_Cast(bool)(bits & bits_to_check);
return result;
}
@@ -780,8 +833,8 @@ DN_API void DN_ASanPoisonMemoryRegion(void const volatile *ptr, DN_USize size)
__asan_poison_memory_region(ptr, size);
if (DN_ASAN_VET_POISON) {
DN_HardAssert(__asan_address_is_poisoned(ptr));
DN_HardAssert(__asan_address_is_poisoned((char *)ptr + (size - 1)));
DN_AssertAlways(__asan_address_is_poisoned(ptr));
DN_AssertAlways(__asan_address_is_poisoned((char *)ptr + (size - 1)));
}
#else
(void)ptr;
@@ -797,7 +850,7 @@ DN_API void DN_ASanUnpoisonMemoryRegion(void const volatile *ptr, DN_USize size)
#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
__asan_unpoison_memory_region(ptr, size);
if (DN_ASAN_VET_POISON)
DN_HardAssert(__asan_region_is_poisoned((void *)ptr, size) == 0);
DN_AssertAlways(__asan_region_is_poisoned((void *)ptr, size) == 0);
#else
(void)ptr;
(void)size;
@@ -873,8 +926,8 @@ static bool DN_ArenaHasPoison_(DN_MemFlags flags)
static DN_MemBlock *DN_MemBlockFromMemFuncsFlags_(DN_U64 reserve, DN_U64 commit, DN_MemFlags flags, DN_MemFuncs mem_funcs)
{
bool track_alloc = (flags & DN_MemFlags_NoAllocTrack) == 0;
bool alloc_can_leak = flags & DN_MemFlags_AllocCanLeak;
bool track_alloc = (flags & DN_MemFlags_NoAllocTrack) == 0;
bool alloc_can_leak = flags & DN_MemFlags_AllocCanLeak;
DN_MemBlock *result = DN_ArenaBlockFromMemFuncs_(reserve, commit, track_alloc, alloc_can_leak, mem_funcs);
if (result && DN_ArenaHasPoison_(flags))
DN_ASanPoisonMemoryRegion(DN_Cast(char *) result + DN_ARENA_HEADER_SIZE, result->commit - DN_ARENA_HEADER_SIZE);
@@ -1054,21 +1107,21 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem
return nullptr;
try_alloc_again:
DN_MemBlock *curr = mem->curr;
bool poison = DN_ArenaHasPoison_(mem->flags);
DN_U8 real_align = poison ? DN_Max(align, DN_ASAN_POISON_ALIGNMENT) : align;
DN_U64 offset_pos = DN_AlignUpPowerOfTwo(curr->used, real_align) + (poison ? DN_ASAN_POISON_GUARD_SIZE : 0);
DN_U64 end_pos = offset_pos + size;
DN_U64 alloc_size = end_pos - curr->used;
DN_MemBlock *curr = mem->curr;
bool poison = DN_ArenaHasPoison_(mem->flags);
DN_U8 real_align = poison ? DN_Max(align, DN_ASAN_POISON_ALIGNMENT) : align;
DN_U64 offset_pos = DN_AlignUpPowerOfTwo(curr->used, real_align) + (poison ? DN_ASAN_POISON_GUARD_SIZE : 0);
DN_U64 end_pos = offset_pos + size;
DN_U64 alloc_size = end_pos - curr->used;
if (end_pos > curr->reserve) {
if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer))
return nullptr;
DN_USize new_reserve = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_RESERVE_SIZE);
DN_USize new_commit = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_COMMIT_SIZE);
if (!DN_MemListGrow(mem, new_reserve, new_commit))
return nullptr;
goto try_alloc_again;
if (end_pos > curr->reserve) {
if (mem->flags & (DN_MemFlags_NoGrow | DN_MemFlags_UserBuffer))
return nullptr;
DN_USize new_reserve = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_RESERVE_SIZE);
DN_USize new_commit = DN_Max(DN_ARENA_HEADER_SIZE + alloc_size, DN_ARENA_COMMIT_SIZE);
if (!DN_MemListGrow(mem, new_reserve, new_commit))
return nullptr;
goto try_alloc_again;
}
DN_USize prev_arena_commit = curr->commit;
@@ -1088,8 +1141,8 @@ DN_API void *DN_MemListAlloc(DN_MemList *mem, DN_U64 size, DN_U8 align, DN_ZMem
mem->stats.hwm.commit = DN_Max(mem->stats.hwm.commit, mem->stats.info.commit);
}
void *result = DN_Cast(char *) curr + offset_pos;
curr->used += alloc_size;
void *result = DN_Cast(char *) curr + offset_pos;
curr->used += alloc_size;
mem->stats.info.used += alloc_size;
mem->stats.hwm.used = DN_Max(mem->stats.hwm.used, mem->stats.info.used);
@@ -1159,7 +1212,19 @@ DN_API void DN_MemListPopTo(DN_MemList *mem, DN_U64 init_used)
if (DN_SCRUB_UNINIT_MEM_BYTE) {
if (old_used > curr->used) {
char *discarded = (char *)curr + curr->used;
DN_Memset(discarded, DN_SCRUB_UNINIT_MEM_BYTE, old_used - curr->used);
DN_USize scrub_size = old_used - curr->used;
// NOTE: If we allocated memory unaligned then the pointer given to the user was aligned up
// and unpoisoned. If the user snapped a memory list position before that allocation then
// attempts to revert it, scrubbing from the memory position (which is before alignment was
// applied!) will cause this code to accidentally scrub the our poison guard bytes. So we
// unpoison the region unconditionally to ensure that is cleaned up before scrubbing. Since
// scrubbing is a debug feature and, you have it turned on _with_ ASAN then we let that
// performance penalty slide.
if (DN_ArenaHasPoison_(mem->flags))
DN_ASanUnpoisonMemoryRegion(discarded, scrub_size);
DN_Memset(discarded, DN_SCRUB_UNINIT_MEM_BYTE, scrub_size);
}
}
DN_MSVC_WARNING_POP
@@ -1310,7 +1375,7 @@ static void DN_ArenaUAFCheck_(DN_Arena *arena, DN_ArenaUAFCheckReportType_ type)
DN_AssertF(mem->uaf_guard_active_id == arena->uaf_guard_id,
"%.*s\n\nThe originating temporary memory region (id: %'u) was created at:"
"\n\n %.*s\n\nThe active temporary memory region (id: %'u) was created at:\n\n %.*s",
"\n\n %.*s\n\nThe active temporary memory region (id: %'u) was created at:\n\n %.*s\n",
DN_Str8PrintFmt(prefix),
arena->uaf_guard_id,
DN_Str8PrintFmt(curr_stack_trace),
@@ -1697,7 +1762,7 @@ DN_API bool DN_ErrSinkEndLogError_(DN_ErrSink *err, DN_CallSite call_site, DN_St
// NOTE: Log the error
DN_Str8 log = DN_Str8FromStr8BuilderArena(&builder, err->arena);
DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), call_site, DN_LogFlags_Nil, "%.*s", DN_Str8PrintFmt(log));
DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Error), call_site, DN_LogFlags_Nil, "%.*s", DN_Str8PrintFmt(log));
if (node->mode == DN_ErrSinkMode_DebugBreakOnErrorLog)
DN_DebugBreak;
@@ -1827,7 +1892,7 @@ DN_API void DN_TCEquip(DN_TCCore *tc)
DN_API DN_TCCore *DN_TCGet()
{
DN_RawAssert(g_dn_thread_context &&
DN_AssertRaw(g_dn_thread_context &&
"This thread's thread context has not been equipped yet. Ensure that DN_TCInit(...) "
"has been called to create a thread context and call DN_TCEquip(...) in the current "
"thread to make it retrievable via this function");
@@ -5797,22 +5862,25 @@ DN_API void DN_LogSetPrintFunc(DN_LogPrintFunc *print_func, void *user_data)
dn->print_func_context = user_data;
}
DN_API void DN_LogPrint(DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...)
DN_API void DN_LogPrintFV(DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args)
{
DN_Core *dn = DN_Get();
if (type.is_u32_enum) {
DN_Assert(dn->log_level_to_show_from >= 0);
if (type.u32 < DN_Cast(DN_U32)dn->log_level_to_show_from)
if (type.u32 < DN_Cast(DN_U32) dn->log_level_to_show_from)
return;
}
DN_LogPrintFunc *func = dn->print_func;
if (func) {
va_list args;
va_start(args, fmt);
if (func)
func(type, dn->print_func_context, call_site, flags, fmt, args);
va_end(args);
}
}
DN_API void DN_LogPrintF(DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...)
{
va_list args;
va_start(args, fmt);
DN_LogPrintFV(type, call_site, flags, fmt, args);
va_end(args);
}
DN_API DN_LogTypeParam DN_LogTypeParamFromType(DN_LogType type)
@@ -7743,7 +7811,7 @@ DN_API void *DN_ArrayMakeArray(void *data, DN_USize *size, DN_USize max, DN_USiz
DN_API void *DN_ArrayMakeArrayAssert(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, DN_USize make_count, DN_ZMem z_mem, DN_CallSite call_site)
{
void *result = DN_ArrayMakeArray(data, size, max, elem_size, make_count, z_mem);
DN_AssertArgsF(result, call_site, "array=%p size=%zu max=%zu", data, *size, max);
DN_AssertCallSiteF(result, call_site, "Array out of space, failed to add %zu items: array=%p size=%zu max=%zu", make_count, data, *size, max);
return result;
}
@@ -7766,7 +7834,7 @@ DN_API void *DN_ArrayAddArray(void *data, DN_USize *size, DN_USize max, DN_USize
DN_API void *DN_ArrayAddArrayAssert(void *data, DN_USize *size, DN_USize max, DN_USize elem_size, void const *elems, DN_USize elems_count, DN_ArrayAdd add, DN_CallSite call_site)
{
void *result = DN_ArrayAddArray(data, size, max, elem_size, elems, elems_count, add);
DN_AssertArgsF(result, call_site, "array=%p size=%zu max=%zu", data, *size, max);
DN_AssertCallSiteF(result, call_site, "Array out of space, failed to add %zu items: array=%p size=%zu max=%zu", elems_count, data, *size, max);
return result;
}
@@ -8002,7 +8070,7 @@ DN_U32 DN_DSMapHash(DN_DSMap<T> const *map, DN_DSMapKey key)
DN_U32 h = seed;
switch (key.type) {
case DN_DSMapKeyType_BufferAsU64NoHash: /*FALLTHRU*/
case DN_DSMapKeyType_U64NoHash: DN_InvalidCodePath; /*FALLTHRU*/
case DN_DSMapKeyType_U64NoHash: DN_AssertInvalidCodePath; /*FALLTHRU*/
case DN_DSMapKeyType_Invalid: break;
case DN_DSMapKeyType_Buffer:
@@ -8894,7 +8962,7 @@ DN_API void DN_LeakTrackAlloc_(DN_LeakTracker *leak, void *ptr, DN_USize size, b
if ((alloc->flags & DN_LeakAllocFlag_Freed) == 0) {
DN_Str8x32 alloc_size = DN_Str8x32FromByteCountU64Auto(alloc->size);
DN_Str8x32 new_alloc_size = DN_Str8x32FromByteCountU64Auto(size);
DN_HardAssertF(
DN_AssertAlwaysF(
alloc->flags & DN_LeakAllocFlag_Freed,
"This pointer is already in the leak tracker, however it has not been freed yet. This "
"same pointer is being ask to be tracked twice in the allocation table, e.g. one if its "
@@ -8942,7 +9010,7 @@ DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr)
DN_Str8 stack_trace = DN_Str8FromStackTraceNowHeap(128, 3 /*skip*/);
DN_DSMap<DN_LeakAlloc> *alloc_table = &leak->alloc_table;
DN_DSMapResult<DN_LeakAlloc> alloc_entry = DN_DSMapFindKeyU64(alloc_table, DN_Cast(uintptr_t) ptr);
DN_HardAssertF(alloc_entry.found,
DN_AssertAlwaysF(alloc_entry.found,
"Allocated pointer can not be removed as it does not exist in the "
"allocation table. When this memory was allocated, the pointer was "
"not added to the allocation table [ptr=%p]",
@@ -8951,7 +9019,7 @@ DN_API void DN_LeakTrackDealloc_(DN_LeakTracker *leak, void *ptr)
DN_LeakAlloc *alloc = alloc_entry.value;
if (alloc->flags & DN_LeakAllocFlag_Freed) {
DN_Str8x32 freed_size = DN_Str8x32FromByteCountU64Auto(alloc->freed_size);
DN_HardAssertF((alloc->flags & DN_LeakAllocFlag_Freed) == 0,
DN_AssertAlwaysF((alloc->flags & DN_LeakAllocFlag_Freed) == 0,
"Double free detected, pointer to free was already marked "
"as freed. Either the pointer was reallocated but not "
"traced, or, the pointer was freed twice.\n"
+181 -108
View File
@@ -3,6 +3,7 @@
#if defined(_CLANGD)
#define DN_STR8_AVX512F 1
#define DN_PARANOIA_LEVEL 1
#include "../dn.h"
#endif
@@ -147,99 +148,160 @@
#define DN_ZeroInit {0}
#endif
// NOTE: Address sanitizer
#if !defined(DN_ASAN_POISON)
#define DN_ASAN_POISON 0
#endif
// NOTE: Macros
#define DN_Stringify(x) #x
#define DN_TokenCombine2(x, y) x ## y
#define DN_TokenCombine(x, y) DN_TokenCombine2(x, y)
#if !defined(DN_ASAN_VET_POISON)
#define DN_ASAN_VET_POISON 0
#endif
// NOTE: Error Checking/Validating
// Asserts are useful to verify invariants in the codebase, but there's sometimes the ambiguous
// question of what should be asserted, what happens when we should have triggered an assert
// in a release build (where they are canonically turned off), what alternative mechanisms should we
// use for error checking that should be visible to non-developers.
//
// The following is an excerpt from Tom Forsyth's assertion article which he references Chris
// Hargrove's guidelines on how asserts show be used. It is quite reasonable and we model our
// primitives after based on those concepts:
//
// Logging, asserts and unit tests (https://tomforsyth1000.github.io/blog.wiki.html
//
// Assert: Immediately fatal, and not ignorable. Fundamental assumption by an engineer has been
// disproven and needs immediate handling. Requires discipline on the part of the engineer to not
// add them in situations that are actually non-fatal (rule of thumb being that if a crash would
// be almost certain to happen anyway due to the same condition, then youre no worse off making
// an assert).
//
// Errors: Probably fatal soon, but not necessarily immediately. Basically a marker for “you are
// now in a f*cked state, you might limp along a bit, but assume nothing”. Game continues, but an
// ugly red number gets displayed onscreen for how many of these have been encountered (so when
// people send you screenshots of bugs you can then point to the red error count and blame
// accordingly). Savegames are disabled from this point so as not to make the error effectively
// permanent; you should also deliberately violate a few other TCRs as soon as an error is
// encountered in order to ensure that all parties up and down the publisher/developer chain are
// aware of how bad things are. Errors are technically “ignorable” but everyone knows that it
// might only buy you a little bit of borrowed time; these are only a small step away from the
// immediately-blocking nature of an assert, but sometimes that small step can have a big impact
// on productivity.
//
// Warnings: Used for “you did something bad, but we caught it so its fine (the game state is
// still okay), however it might not be fine in the future so if you want to save yourself some
// headache you should fix this sooner rather than later”. Great for content problems. Also
// displayed onscreen as a yellow number (near the red error number). You can keep these around
// for a while and triage them when their utility is called into question.
//
// Crumbs: The meta-category for a large number of “verbose” informational breadcrumb categories
// that must be explicitly enabled so you dont clutter everything up and obscure stuff that
// matters. Note that the occurrance of certain Errors should automatically enable relevant
// categories of crumbs so that more detailed information about the aforementioned f*cked state
// will be provided during the limp-along timeframe.
//
// In the excerpt, their domain (games programming) prioritises continuity over immediate failure
// on warning and error as this allows non-developer clientele to continue using the application
// despite error laden states. This is useful in general as not all failures are critical to the
// use case that the end user is dealing with.
//
// We model `Errors` and `Warnings` as `DN_Verify` and `DN_VerifyWarning` respectively. The verify
// variants check the expression to test, log and a message and allow the developer to branch on the
// result and "recover" where appropriate. Verify checks are never compiled out. We have traditional
// `Asserts` as `DN_Assert` which can be compiled out.
//
// The article also defines what it calls a paranoia level. We `#define DN_PARANOIA_LEVEL <Integer>`
// to customise the validation layers of the codebase. See DN_PARANOIA_LEVEL in the customisation
// section for more information.
//
// In summary use each of the primitives in these situation:
//
// `DN_Assert`: Fatal and immediately needs attention and can be compiled out
//
// `DN_Verify`: Fatal or eventually fatal but not necessarily immediately, program is or will
// degenerate into an incorrect state. Is always compiled in and is visible in non-debug
// environments.
//
// `DN_VerifyWarning`: Something bad happened, but we caught it and recovered from it. Program
// state remains consistent. It is always compiled in and is visible in non-debug environments.
#define DN_ASAN_POISON_ALIGNMENT 8
#if !defined(DN_ASAN_POISON_GUARD_SIZE)
#define DN_ASAN_POISON_GUARD_SIZE 128
#if !defined(DN_PARANOIA_LEVEL)
#if defined(NDEBUG)
#define DN_PARANOIA_LEVEL 0
#else
#define DN_PARANOIA_LEVEL 1
#endif
#endif
#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
#include <sanitizer/asan_interface.h>
#endif
// NOTE: Memory
#define DN_ASAN_POISON_ALIGNMENT 8
#if !defined(DN_ASAN_VET_POISON)
#define DN_ASAN_VET_POISON 0
#endif
#if !defined(DN_ASAN_POISON)
#if DN_PARANOIA_LEVEL >= 1
#define DN_ASAN_POISON 1
#else
#define DN_ASAN_POISON 0
#endif
#endif
#if !defined(DN_ASAN_POISON_GUARD_SIZE)
#define DN_ASAN_POISON_GUARD_SIZE 128
#endif
#if !defined(DN_ARENA_TEMP_MEM_UAF_GUARD)
#define DN_ARENA_TEMP_MEM_UAF_GUARD 0
#if DN_PARANOIA_LEVEL >= 1
#define DN_ARENA_TEMP_MEM_UAF_GUARD 1
#else
#define DN_ARENA_TEMP_MEM_UAF_GUARD 0
#endif
#endif
#if !defined(DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT)
#define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 0
#if DN_PARANOIA_LEVEL >= 2
#define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 1
#else
#define DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT 0
#endif
#endif
#if !defined(DN_SCRUB_UNINIT_MEM_BYTE)
#define DN_SCRUB_UNINIT_MEM_BYTE 0
#if DN_PARANOIA_LEVEL >= 1
#define DN_SCRUB_UNINIT_MEM_BYTE 0xCD
#else
#define DN_SCRUB_UNINIT_MEM_BYTE 0x00
#endif
#endif
// NOTE: Macros
#define DN_Stringify(x) #x
#define DN_TokenCombine2(x, y) x ## y
#define DN_TokenCombine(x, y) DN_TokenCombine2(x, y)
// NOTE: Asserts
#define DN_HardAssertF(expr, fmt, ...) \
do { \
if (!(expr)) { \
DN_Str8 stack_trace_ = DN_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \
DN_LogErrorF("Hard assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \
DN_Str8PrintFmt(stack_trace_), \
##__VA_ARGS__); \
DN_DebugBreak; \
} \
#define DN_AssertRaw(expr) do { if (!(expr)) DN_DebugBreak; } while (0)
#define DN_AssertAlwaysCallSiteF(expr, call_site, fmt, ...) \
do { \
if (!(expr)) { \
DN_Str8 trace_ = DN_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \
DN_LogTypeParam log_type_ = DN_LogTypeParamFromType(DN_LogType_Error); \
DN_LogPrintF(log_type_, call_site, DN_LogFlags_Nil, "Assertion triggered [" #expr "]. " fmt "\nTrace:\n%.*s", ## __VA_ARGS__, DN_Str8PrintFmt(trace_)); \
DN_DebugBreak; \
} \
} while (0)
#define DN_HardAssert(expr) DN_HardAssertF(expr, "")
// NOTE: Our default assert requires stack traces which has a bit of a chicken-and-egg problem if
// we're trying to detect some code related to the DN startup sequence. If we try to assert before
// the OS layer is initialised stack-traces will try to use temporary memory which requires TLS to
// be setup which belongs to the OS.
//
// This causes recursion errors as they call into each other. We use RawAsserts for these kind of
// checks.
#if defined(DN_NO_ASSERT)
#define DN_RawAssert(...)
#define DN_Assert(...)
#define DN_AssertOnce(...)
#define DN_AssertArgsF(...)
#define DN_AssertF(...)
#define DN_AssertFOnce(...)
#define DN_AssertAlwaysF(expr, fmt, ...) DN_AssertAlwaysCallSiteF(expr, (DN_CallSiteNow), fmt, ##__VA_ARGS__)
#define DN_AssertAlways(expr) DN_AssertAlwaysF(expr, "")
#define DN_AssertInvalidCodePathF(fmt, ...) DN_AssertAlwaysF(0, fmt, ##__VA_ARGS__)
#define DN_AssertInvalidCodePath DN_AssertInvalidCodePathF("Invalid code path")
#if DN_PARANOIA_LEVEL >= 1
#define DN_AssertCallSiteF(expr, call_site, fmt, ...) DN_AssertAlwaysCallSiteF(expr, call_site, fmt, ## __VA_ARGS__)
#define DN_AssertF(expr, fmt, ...) DN_AssertCallSiteF(expr, (DN_CallSiteNow), fmt, ## __VA_ARGS__)
#define DN_Assert(expr) DN_AssertAlways(expr)
#else
#define DN_RawAssert(expr) do { if (!(expr)) DN_DebugBreak; } while (0)
#define DN_AssertArgsF(expr, call_site, fmt, ...) \
do { \
if (!(expr)) { \
DN_Str8 stack_trace_ = DN_Str8FromStackTraceNowHeap(128 /*limit*/, 3 /*skip*/); \
DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), \
call_site, \
DN_LogFlags_Nil, \
"Assertion [" #expr "], stack trace was:\n\n%.*s\n\n" fmt, \
DN_Str8PrintFmt(stack_trace_), \
##__VA_ARGS__); \
DN_DebugBreak; \
} \
} while (0)
#define DN_AssertF(expr, fmt, ...) DN_AssertArgsF(expr, DN_CALL_SITE, fmt, ## __VA_ARGS__)
#define DN_AssertFOnce(expr, fmt, ...) \
do { \
for (static bool once_ = true; !(expr) && once_; once_ = false) \
DN_AssertF(expr, fmt, ## __VA_ARGS__); \
} while (0)
#define DN_Assert(expr) DN_AssertF((expr), "")
#define DN_AssertOnce(expr) DN_AssertFOnce((expr), "")
#define DN_AssertCallSiteF(expr, call_site, fmt, ...) (void)(expr); (void)call_site
#define DN_AssertF(expr, fmt, ...) (void)(expr)
#define DN_Assert(expr) (void)(expr)
#endif
#define DN_VerifyF(expr, fmt, ...) DN_VerifyArgsF(DN_VerifyType_Nil, expr, (DN_CallSiteNow), DN_Str8Lit(#expr), fmt, ##__VA_ARGS__)
#define DN_VerifyWarningF(expr, fmt, ...) DN_VerifyArgsF(DN_VerifyType_Warning, expr, (DN_CallSiteNow), DN_Str8Lit(#expr), fmt, ##__VA_ARGS__)
#define DN_Verify(expr) DN_VerifyF(expr, 0)
#define DN_VerifyWarning(expr) DN_VerifyWarningF(expr, 0)
#define DN_InvalidCodePathF(fmt, ...) DN_HardAssertF(0, fmt, ##__VA_ARGS__)
#define DN_InvalidCodePath DN_InvalidCodePathF("Invalid code path triggered")
#define DN_StaticAssert(expr) \
DN_GCC_WARNING_PUSH \
DN_GCC_WARNING_DISABLE(-Wunused-local-typedefs) \
@@ -481,6 +543,12 @@ typedef DN_I32 DN_B32;
#define DN_CountLeadingZerosUSize(value) DN_CountLeadingZerosU32(value)
#endif
enum DN_VerifyType
{
DN_VerifyType_Nil,
DN_VerifyType_Warning,
};
enum DN_ZMem
{
DN_ZMem_No, // Memory can be handed out without zero-ing it out
@@ -679,7 +747,7 @@ struct DN_CallSite
DN_U32 line;
};
#define DN_CALL_SITE DN_CallSite { DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ }
#define DN_CallSiteNow DN_Literal(DN_CallSite){DN_Str8Lit(__FILE__), DN_Str8Lit(__func__), __LINE__ }
#if defined(__cplusplus)
template <typename Procedure>
@@ -1632,6 +1700,9 @@ DN_GCC_WARNING_DISABLE(-Wunused-function)
DN_GCC_WARNING_POP
DN_MSVC_WARNING_POP
DN_API bool DN_VerifyArgsF (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8, char const *fmt, ...);
DN_API bool DN_VerifyArgs (DN_VerifyType type, bool expr, DN_CallSite call_site, DN_Str8 expr_str8);
#define DN_SPrintF(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__)
#define DN_SNPrintF(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__)
#define DN_VSPrintF(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__)
@@ -1641,8 +1712,8 @@ DN_API bool DN_MemStartsWith
DN_API bool DN_MemEq (void const *lhs, DN_USize lhs_size, void const *rhs, DN_USize rhs_size);
DN_API bool DN_MemEqUnsafe (void const *lhs, void const *rhs, DN_USize size);
#if defined(__cplusplus)
template <typename T> T* DN_TMemCopyObj (T *dest, T const *src, DN_USize count);
#define DN_MemCopyObj(dest, src, count) DN_TMemCopyObj(dest, src, count)
template <typename T> T* DN_MemCopyObjT (T *dest, T const *src, DN_USize count);
#define DN_MemCopyObj(dest, src, count) DN_MemCopyObjT(dest, src, count)
#else
#define DN_MemCopyObj(dest, src, count) DN_Memcpy(dest, src, sizeof(*src) * count)
#endif
@@ -1703,6 +1774,7 @@ DN_API void DN_BitUnsetInplace
DN_API void DN_BitSetInplace (DN_USize *flags, DN_USize bitfield);
DN_API bool DN_BitIsSet (DN_USize bits, DN_USize bits_to_set);
DN_API bool DN_BitIsNotSet (DN_USize bits, DN_USize bits_to_check);
DN_API bool DN_BitIsAny (DN_USize bits, DN_USize bits_to_check);
#define DN_BitClearNextLSB(value) (value) & ((value) - 1)
DN_API DN_I64 DN_SafeAddI64 (DN_I64 a, DN_I64 b);
@@ -1875,26 +1947,26 @@ DN_API void * DN_PoolCopy
#define DN_PoolNewArrayCopy(pool, T, src, count) (T *)DN_PoolCopy (pool, (src), sizeof(T) * (count), alignof(T))
DN_API DN_ErrSink* DN_ErrSinkBegin_ (DN_ErrSink *err, DN_ErrSinkMode mode, DN_CallSite call_site);
#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CALL_SITE)
#define DN_ErrSinkBegin(err, mode) DN_ErrSinkBegin_(err, mode, DN_CallSiteNow)
#define DN_ErrSinkBeginDefault(err) DN_ErrSinkBegin(err, DN_ErrSinkMode_Nil)
DN_API bool DN_ErrSinkHasError (DN_ErrSink *err);
DN_API DN_ErrSinkMsg* DN_ErrSinkEnd (DN_Arena *arena, DN_ErrSink *err);
DN_API DN_Str8 DN_ErrSinkEndStr8 (DN_Arena *arena, DN_ErrSink *err);
DN_API void DN_ErrSinkEndIgnore (DN_ErrSink *err);
DN_API bool DN_ErrSinkEndLogError_ (DN_ErrSink *err, DN_CallSite call_site, DN_Str8 msg);
#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CALL_SITE, err_msg)
#define DN_ErrSinkEndLogError(err, err_msg) DN_ErrSinkEndLogError_(err, DN_CallSiteNow, err_msg)
DN_API bool DN_ErrSinkEndLogErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CALL_SITE, fmt, args)
#define DN_ErrSinkEndLogErrorFV(err, fmt, args) DN_ErrSinkEndLogErrorFV_(err, DN_CallSiteNow, fmt, args)
DN_API bool DN_ErrSinkEndLogErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...);
#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_ErrSinkEndLogErrorF(err, fmt, ...) DN_ErrSinkEndLogErrorF_(err, DN_CallSiteNow, fmt, ##__VA_ARGS__)
DN_API void DN_ErrSinkEndExitIfErrorF_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...);
#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__)
#define DN_ErrSinkEndExitIfErrorF(err, exit_val, fmt, ...) DN_ErrSinkEndExitIfErrorF_(err, DN_CallSiteNow, exit_val, fmt, ##__VA_ARGS__)
DN_API void DN_ErrSinkEndExitIfErrorFV_ (DN_ErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args);
#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args)
#define DN_ErrSinkEndExitIfErrorFV(err, exit_val, fmt, args) DN_ErrSinkEndExitIfErrorFV_(err, DN_CallSiteNow, exit_val, fmt, args)
DN_API void DN_ErrSinkAppendFV_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CALL_SITE, fmt, args)
#define DN_ErrSinkAppendFV(error, error_code, fmt, args) DN_ErrSinkAppendFV_(error, error_code, DN_CallSiteNow, fmt, args)
DN_API void DN_ErrSinkAppendF_ (DN_ErrSink *err, DN_U32 error_code, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...);
#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_ErrSinkAppendF(error, error_code, fmt, ...) DN_ErrSinkAppendF_(error, error_code, DN_CallSiteNow, fmt, ##__VA_ARGS__)
DN_API DN_TCInitArgs DN_TCInitArgsDefault ();
DN_API void DN_TCInit (DN_TCCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_Arena *temp_arenas, DN_USize temp_arenas_count, DN_Arena *err_sink_arena);
@@ -2283,20 +2355,21 @@ DN_API DN_Str8 DN_Str8FromFmtANSIColourV3F32RGB255Arena
// OS functionality enabled, the log callback is by default set to outputting via standard out.
DN_API DN_LogPrefixSize DN_LogMakePrefix (DN_LogStyle style, DN_LogTypeParam type, DN_CallSite call_site, DN_LogDate date, char *dest, DN_USize dest_size);
DN_API void DN_LogSetPrintFunc (DN_LogPrintFunc *print_func, void *user_data);
DN_API void DN_LogPrint (DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_LogPrintF (DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_LogPrintFV (DN_LogTypeParam type, DN_CallSite call_site, DN_LogFlags flags, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API DN_LogTypeParam DN_LogTypeParamFromType (DN_LogType type);
#define DN_LogF(type, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogF(type, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(type), DN_CallSiteNow, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogDebugF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogInfoF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogWarningF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogErrorF(fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogDebugF(fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CallSiteNow, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogInfoF(fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Info), DN_CallSiteNow, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogWarningF(fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CallSiteNow, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogErrorF(fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Error), DN_CallSiteNow, DN_LogFlags_Nil, fmt, ##__VA_ARGS__)
#define DN_LogFlagF(type, flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(type), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagDebugF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagInfoF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Info), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagWarningF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagErrorF(flags, fmt, ...) DN_LogPrint(DN_LogTypeParamFromType(DN_LogType_Error), DN_CALL_SITE, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagF(type, flags, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(type), DN_CallSiteNow, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagDebugF(flags, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Debug), DN_CallSiteNow, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagInfoF(flags, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Info), DN_CallSiteNow, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagWarningF(flags, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Warning), DN_CallSiteNow, flags, fmt, ##__VA_ARGS__)
#define DN_LogFlagErrorF(flags, fmt, ...) DN_LogPrintF(DN_LogTypeParamFromType(DN_LogType_Error), DN_CallSiteNow, flags, fmt, ##__VA_ARGS__)
// NOTE: OS primitives that the OS layer can provide for the base layer but is optional.
@@ -2850,22 +2923,22 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2
#define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, count, z_mem)
#define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_Yes)
#define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArray(ptr, ptr_size, max, count, DN_ZMem_No)
#define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem, DN_CallSiteNow)
#define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_Yes, DN_CallSiteNow)
#define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, count, DN_ZMem_No, DN_CallSiteNow)
#define DN_PArrayMake(ptr, ptr_size, max, z_mem) DN_TArrayMakeArray(ptr, ptr_size, max, 1, z_mem)
#define DN_PArrayMakeZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_Yes)
#define DN_PArrayMakeNoZ(ptr, ptr_size, max) DN_TArrayMakeArray(ptr, ptr_size, max, 1, DN_ZMem_No)
#define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CALL_SITE)
#define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CALL_SITE)
#define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CALL_SITE)
#define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, z_mem, DN_CallSiteNow)
#define DN_PArrayMakeAssertZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_Yes, DN_CallSiteNow)
#define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) DN_TArrayMakeArrayAssert(ptr, ptr_size, max, 1, DN_ZMem_No, DN_CallSiteNow)
#define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) DN_TArrayAddArray(ptr, ptr_size, max, items, count, add)
#define DN_PArrayAdd(ptr, ptr_size, max, item, add) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, add)
#define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_ArrayAdd_Append)
#define DN_PArrayAppend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_ArrayAdd_Append)
#define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_ArrayAdd_Append, DN_CALL_SITE)
#define DN_PArrayAppendAssert(ptr, ptr_size, max, item) DN_TArrayAddArrayAssert(ptr, ptr_size, max, &item, 1, DN_ArrayAdd_Append, DN_CallSiteNow)
#define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) DN_TArrayAddArray(ptr, ptr_size, max, items, count, DN_ArrayAdd_Prepend)
#define DN_PArrayPrepend(ptr, ptr_size, max, item) DN_TArrayAddArray(ptr, ptr_size, max, &item, 1, DN_ArrayAdd_Prepend)
@@ -2888,22 +2961,22 @@ DN_API DN_RaycastV2 DN_RaycastLineIntersectV2
#define DN_PArrayMakeArray(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem)
#define DN_PArrayMakeArrayZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes)
#define DN_PArrayMakeArrayNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No)
#define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CALL_SITE)
#define DN_PArrayMakeArrayAssert(ptr, ptr_size, max, count, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, z_mem, DN_CallSiteNow)
#define DN_PArrayMakeArrayAssertZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_Yes, DN_CallSiteNow)
#define DN_PArrayMakeArrayAssertNoZ(ptr, ptr_size, max, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), count, DN_ZMem_No, DN_CallSiteNow)
#define DN_PArrayMake(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem)
#define DN_PArrayMakeZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes)
#define DN_PArrayMakeNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArray(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No)
#define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CALL_SITE)
#define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CALL_SITE)
#define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CALL_SITE)
#define DN_PArrayMakeAssert(ptr, ptr_size, max, z_mem) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, z_mem, DN_CallSiteNow)
#define DN_PArrayMakeAssertZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_Yes, DN_CallSiteNow)
#define DN_PArrayMakeAssertNoZ(ptr, ptr_size, max) (DN_CppDeclType(&(ptr)[0]))DN_ArrayMakeArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), 1, DN_ZMem_No, DN_CallSiteNow)
#define DN_PArrayAddArray(ptr, ptr_size, max, items, count, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, add)
#define DN_PArrayAdd(ptr, ptr_size, max, item, add) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, add)
#define DN_PArrayAppendArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Append)
#define DN_PArrayAppend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append)
#define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append, DN_CALL_SITE)
#define DN_PArrayAppendAssert(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArrayAssert(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Append, DN_CallSiteNow)
#define DN_PArrayPrependArray(ptr, ptr_size, max, items, count) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), items, count, DN_ArrayAdd_Prepend)
#define DN_PArrayPrepend(ptr, ptr_size, max, item) (DN_CppDeclType(&(ptr)[0]))DN_ArrayAddArray(ptr, ptr_size, max, sizeof((ptr)[0]), &item, 1, DN_ArrayAdd_Prepend)
@@ -3312,7 +3385,7 @@ DN_API void DN_LeakDump_ (DN_LeakTracker *leak);
// NOTE: Template implementations
#if defined(__cplusplus)
template <typename T> T *DN_TMemCopyObj(T *dest, T const *src, DN_USize count)
template <typename T> T *DN_MemCopyObjT(T *dest, T const *src, DN_USize count)
{
T* result = dest;
DN_Memcpy(dest, src, sizeof(T) * count);
+3 -3
View File
@@ -211,7 +211,7 @@ static int32_t DN_NET_CurlThreadEntryPoint_(DN_OSThread *thread)
int running_handles = 0;
CURLMcode perform_result = curl_multi_perform(curl->thread_curlm, &running_handles);
if (perform_result != CURLM_OK)
DN_InvalidCodePath;
DN_AssertInvalidCodePath;
// NOTE: Check pump result
for (;;) {
@@ -498,7 +498,7 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D
// NOTE: Setup handle for protocol
switch (req->type) {
case DN_NETRequestType_Nil: DN_InvalidCodePath; break;
case DN_NETRequestType_Nil: DN_AssertInvalidCodePath; break;
case DN_NETRequestType_WS: {
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L);
@@ -518,7 +518,7 @@ static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, D
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->args.payload.size);
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, req->args.payload.data);
} else {
DN_InvalidCodePathF("Unimplemented");
DN_AssertInvalidCodePathF("Unimplemented");
}
} break;
}
+2 -3
View File
@@ -281,14 +281,13 @@ void DN_NET_EmcDoWSSend(DN_NETRequestHandle handle, DN_Str8 data, DN_NETWSSend s
{
DN_AssertF(send == DN_NETWSSend_Binary || send == DN_NETWSSend_Text || send == DN_NETWSSend_Close,
"Unimplemented, Emscripten only supports some of the available operations");
int result = 0;
int result = 0;
DN_NETRequest *request_ptr = DN_Cast(DN_NETRequest *) handle.handle;
if (request_ptr && request_ptr->gen == handle.gen) {
DN_Assert(request_ptr->type == DN_NETRequestType_WS);
DN_NETEmcRequest *emc_request = DN_Cast(DN_NETEmcRequest *) request_ptr->context[1];
switch (send) {
default: DN_InvalidCodePath; break;
default: DN_AssertInvalidCodePath; break;
case DN_NETWSSend_Text: {
DN_U64 pos = DN_MemListPos(request_ptr->start_response_arena.mem);
DN_Str8 data_null_terminated = DN_Str8FromStr8Arena(data, &request_ptr->start_response_arena);
+15 -20
View File
@@ -31,7 +31,7 @@ static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect)
DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, DN_U32 page_flags)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Emscripten does not support virtual memory, you should use DN_OS_MemAlloc");
DN_AssertInvalidCodePathF("Emscripten does not support virtual memory, you should use DN_OS_MemAlloc");
#endif
unsigned long os_page_flags = DN_OS_MemConvertPageToOSFlags_(page_flags);
@@ -50,7 +50,7 @@ DN_API void *DN_OS_MemReserve(DN_USize size, DN_MemCommit commit, DN_U32 page_fl
DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, DN_U32 page_flags)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Emscripten does not support virtual memory");
DN_AssertInvalidCodePathF("Emscripten does not support virtual memory");
#endif
bool result = false;
if (!ptr || size == 0)
@@ -66,7 +66,7 @@ DN_API bool DN_OS_MemCommit(void *ptr, DN_USize size, DN_U32 page_flags)
DN_API void DN_OS_MemDecommit(void *ptr, DN_USize size)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Emscripten does not support virtual memory");
DN_AssertInvalidCodePathF("Emscripten does not support virtual memory");
#endif
mprotect(ptr, size, PROT_NONE);
madvise(ptr, size, MADV_FREE);
@@ -75,7 +75,7 @@ DN_API void DN_OS_MemDecommit(void *ptr, DN_USize size)
DN_API void DN_OS_MemRelease(void *ptr, DN_USize size)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Emscripten does not support virtual memory");
DN_AssertInvalidCodePathF("Emscripten does not support virtual memory");
#endif
munmap(ptr, size);
}
@@ -83,7 +83,7 @@ DN_API void DN_OS_MemRelease(void *ptr, DN_USize size)
DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, DN_U32 page_flags)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Emscripten does not support virtual memory");
DN_AssertInvalidCodePathF("Emscripten does not support virtual memory");
#endif
if (!ptr || size == 0)
return 0;
@@ -199,7 +199,7 @@ DN_API DN_Date DN_OS_DateUnixTimeSToDate(DN_U64 time)
DN_API void DN_OS_GenBytesSecure(void *buffer, DN_U32 size)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePath;
DN_AssertInvalidCodePath;
(void)buffer;
(void)size;
#else
@@ -219,7 +219,7 @@ DN_API void DN_OS_GenBytesSecure(void *buffer, DN_U32 size)
DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value)
{
DN_AssertFOnce(false, "Unimplemented");
DN_VerifyWarning(false, "Unimplemented function");
(void)name;
(void)value;
bool result = false;
@@ -445,18 +445,14 @@ DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path,
return result;
if ((access & ~(DN_OSFileAccess_All) || ((access & DN_OSFileAccess_All) == 0))) {
DN_InvalidCodePath;
DN_AssertInvalidCodePath;
return result;
}
if (access & DN_OSFileAccess_Execute) {
result.error = true;
DN_ErrSinkAppendF(
error,
1,
"Failed to open file '%.*s': File access flag 'execute' is not supported",
DN_Str8PrintFmt(path));
DN_InvalidCodePath; // TODO: Not supported via fopen
DN_ErrSinkAppendF(error, 1, "Failed to open file '%.*s': File access flag 'execute' is not supported", DN_Str8PrintFmt(path));
DN_AssertInvalidCodePath; // TODO: Not supported via fopen
return result;
}
@@ -470,7 +466,7 @@ DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path,
case DN_OSFileOpen_CreateAlways: handle = fopen(path.data, "w"); break;
case DN_OSFileOpen_OpenIfExist: handle = fopen(path.data, "r"); break;
case DN_OSFileOpen_OpenAlways: handle = fopen(path.data, "a"); break;
default: DN_InvalidCodePath; break;
default: DN_AssertInvalidCodePath; break;
}
if (!handle) { // TODO(doyle): FileOpen flag to string
@@ -747,7 +743,7 @@ DN_API DN_OSExecResult DN_OS_ExecWait(DN_OSExecAsyncHandle handle,
}
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Unsupported operation");
DN_AssertInvalidCodePathF("Unsupported operation");
#endif
static_assert(sizeof(pid_t) <= sizeof(handle.process),
@@ -834,10 +830,9 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line,
DN_ErrSink *error)
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
DN_InvalidCodePathF("Unsupported operation");
DN_AssertInvalidCodePathF("Unsupported operation");
#endif
DN_AssertFOnce(args->environment.count == 0, "Unimplemented in POSIX");
DN_VerifyWarningF(args->environment.count == 0, "Environment variables are unimplemented in POSIX");
DN_OSExecAsyncHandle result = {};
if (cmd_line.count == 0)
return result;
@@ -1025,7 +1020,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle,
DN_U32 timeout_ms,
DN_ErrSink *err)
{
DN_InvalidCodePath;
DN_AssertInvalidCodePath;
DN_OSExecResult result = {};
return result;
}
+5 -5
View File
@@ -100,7 +100,7 @@ DN_API int DN_OS_MemProtect(void *ptr, DN_USize size, DN_U32 page_flags)
DN_API void *DN_OS_MemAlloc(DN_USize size, DN_ZMem z_mem)
{
DN_Core *dn = DN_Get();
DN_RawAssert(dn->init_flags & DN_InitFlags_OS && "DN must be initialised with the OS flag");
DN_AssertRaw(dn->init_flags & DN_InitFlags_OS && "DN must be initialised with the OS flag");
DN_U32 flags = z_mem == DN_ZMem_Yes ? HEAP_ZERO_MEMORY : 0;
DN_Assert(size <= DN_Cast(DWORD)(-1));
void *result = HeapAlloc(GetProcessHeap(), flags, DN_Cast(DWORD) size);
@@ -340,7 +340,7 @@ DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFile
return result;
if ((access & ~DN_OSFileAccess_All) || ((access & DN_OSFileAccess_All) == 0)) {
DN_InvalidCodePath;
DN_AssertInvalidCodePath;
return result;
}
@@ -348,8 +348,8 @@ DN_API DN_OSFile DN_OS_FileOpen(DN_Str8 path, DN_OSFileOpen open_mode, DN_OSFile
switch (open_mode) {
case DN_OSFileOpen_CreateAlways: create_flag = CREATE_ALWAYS; break;
case DN_OSFileOpen_OpenIfExist: create_flag = OPEN_EXISTING; break;
case DN_OSFileOpen_OpenAlways: create_flag = OPEN_ALWAYS; break;
default: DN_InvalidCodePath; return result;
case DN_OSFileOpen_OpenAlways: create_flag = OPEN_ALWAYS; break;
default: DN_AssertInvalidCodePath; return result;
}
unsigned long access_mode = 0;
@@ -499,7 +499,7 @@ DN_API DN_OSPathInfo DN_OS_PathInfo(DN_Str8 path)
}
result.exists = true;
result.create_time_in_s = DN_OS_W32FileTimeToSeconds_(&attrib_data.ftCreationTime);
result.create_time_in_s = DN_OS_W32FileTimeToSeconds_(&attrib_data.ftCreationTime);
result.last_access_time_in_s = DN_OS_W32FileTimeToSeconds_(&attrib_data.ftLastAccessTime);
result.last_write_time_in_s = DN_OS_W32FileTimeToSeconds_(&attrib_data.ftLastWriteTime);
+68 -20
View File
@@ -2,7 +2,8 @@
#define DN_H
// NOTE: DN
// Getting Started
// NOTE: Getting Started
// Include this mega header `dn.h` and define the following symbols to `1` to conditionally
// enable the interfaces for those features. Additionally in the same or different translation
// unit, include `dn.cpp` with the same symbols defined to enable the implementation of these
@@ -33,9 +34,10 @@
// synchronisation, memory allocation. This layer is OPTIONAL.
//
// - Extra layer provides helper utilities that are opt-in. These layers are OPTIONAL.
//
// Configuration
// Platform Target
// NOTE: Configuration
// NOTE: Platform Target
// Define one of the following directives to configure this library to compile for that
// platform. By default, the library will auto-detect the current host platform and select that
// as the target platform.
@@ -50,8 +52,8 @@
//
// Will ensure that <Windows.h> is included and the OS layer is implemented using Win32
// primitives.
//
// Static functions
// NOTE: Static functions
// All public functions in the DN library are prefixed with the macro '#define DN_API'. By
// default 'DN_API' is not defined to anything. Define
//
@@ -60,8 +62,8 @@
// To replace all the functions prefixed with DN_API to be prefixed with 'static' ensuring that
// the functions in the library do not export an entry into the linking table.
// translation units.
//
// Disabling the in-built <Windows.h> (if #define DN_H_WITH_OS 1)
// NOTE: Disabling the in-built <Windows.h> (if #define DN_H_WITH_OS 1)
// If you are building DN for the Windows platform, <Windows.h> is a large legacy header that
// applications have to include to use Windows APIs. By default this library uses a replacement
// header for all the Windows functions that it uses in the OS layer removing the need to
@@ -74,16 +76,16 @@
// To instead use <Windows.h>. DN automatically detects if <Windows.h> is included in an earlier
// translation unit and will automatically disable the in-built replacement header in which case
// this does not need to be defined.
//
// Freestanding
// NOTE: Freestanding
// The base layer can be used without an OS implementation by defining DN_FREESTANDING like:
//
// #define DN_FREESTANDING
//
// This means functionality that relies on the OS like printing, memory allocation, stack traces
// and so forth are disabled.
//
// ASAN Arena Poisoning
// NOTE: ASAN Arena Poisoning
// When compiled with address sanitizer (.e.g -fsanitize=address) you can optionally enable
// memory region poisoning on the inbuilt arena's to catch in certain scenarios, use-after-free
//
@@ -93,8 +95,8 @@
// memory markup that ASAN does and so it is implemented manually by using the ASAN user-level
// poisoning APIs. Similarly, since the arena recycles its own memory rather than release back
// to the OS, poisoning is not as effective for arenas but every little bit helps.
//
// Scrub Uninitialised Memory
// NOTE: Scrub Uninitialised Memory
// If this macro is defined, temp memory that is returned to an arena, or allocations freed by
// a pool are scrubbed to this specified byte, in absence of this bytes returned to the
// allocators are left as-is or memset to 0. For example to scrub bytes to 0xCD (MSVC's
@@ -105,8 +107,8 @@
// Due to the recycling of memory in arenas and pool, similarly to ASAN poisoning this reduces
// the window in which a use-after-free can be detected using this guard, however every little
// bit helps.
//
// Arena temp memory use-after-free (UAF) tooling
// NOTE: Arena temp memory use-after-free (UAF) tooling
// UAF Guard
// Set the following preprocessor value to 1 to enable UAF protection when using
// scratch/temporary memory functionality. Defaults to off, or 0 if not specified
@@ -127,7 +129,7 @@
// memory block and additional book-keeping fields on each arena and their temp memory
// instances.
//
// UAF Tracing
// NOTE: UAF Tracing
// Set the following preprocessor value to 1 to enable tracing when the UAF guard triggers.
// Defaults to off, or 0 if not specified.
//
@@ -141,11 +143,57 @@
// Tracing incurs an additional much heavier performance penalty than the UAF guard due to
// the stacktrace that is stored per region to report to the user when a UAF guard violation
// occurs.
// NOTE: Paranoia Level
// Set the `DN_PARANOIA_LEVEL` to an integer value to enable various validation layers and
// error checking mechanisms in the codebase and primitives exposed by the library. Defaults to
// paranoia level 0 in release builds and level 1 for debug.
//
// Str8 AVX512F variants
// We have some AVX512 string functions that can be enabled by defining the following
// #define DN_PARANOIA_LEVEL 1
//
// #define DN_STR8_AVX512F 1
// Each level activates the following debug mechanisms. Note that any of the following #defines
// enabled by a paranoia level can be overridden by defining the preprocessor definition before
// the inclusion of this file.
//
// Level 0
// `DN_Assert` calls are compiled out
//
// `DN_Verify` calls logs an error and continues
//
// `DN_VerifyWarning` calls logs a warning and continues
//
// Level 1
// `DN_Assert` calls are compiled in
//
// `DN_Verify` calls a debug trap rather than just logging and continuing
//
// `DN_Verify` calls dump a stack trace when triggered
//
// `DN_ASAN_POISON` is set. When an arena allocates memory unallocated bytes from the
// memory owned by the arena are manually poisoned using ASAN. A fault will be triggered if
// the memory is written to (UAF e.g. use-after-free). Address sanitizer must be enabled or
// otherwise this is a no-op. This incurs a performance penalty on-top of the overhead of
// running ASAN on your binary as recycling memory calls into ASAN to poison the region.
//
// `DN_ARENA_TEMP_MEM_UAF_GUARD` is set. When an arena uses temporary memory it will record
// the active temporary memory region and compare them when allocating to ensure that
// memory is allocated in the active region otherwise a UAF fault is triggered. This has a
// small runtime performance penalty.
//
// `DN_SCRUB_UNINIT_MEM_BYTE` is set to `0xCD`. When memory is cleared in an arena or a
// pool backed by an arena upon deallocation if the `DN_ZMem_Yes` flag is passed then the
// bytes are scrubbed to this byte to make UAF more salient.
//
// Level 2
// `DN_ARENA_TEMP_MEM_UAF_TRACE_ON_BY_DEFAULT` is set. When an arena uses temporary memory
// regions that region's a stack trace of the call site is recorded. This is very expensive
// but when a temporary memory region is used after it has been deallocated, a full stack
// trace diagnostic is available of where the various regions where created and freed.
//
// NOTE: Str8 AVX512F variants
// We have some AVX512 string functions that can be enabled by defining the following
//
// #define DN_STR8_AVX512F 1
#include "Base/dn_base.h"