Skip to content

Commit 14c406c

Browse files
author
LoneWandererProductions
committed
Improve utillites
Add Canary
1 parent 421c4f4 commit 14c406c

4 files changed

Lines changed: 227 additions & 77 deletions

File tree

MemoryManager.Core/AllocationPriority.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,24 @@
88

99
namespace MemoryManager.Core
1010
{
11+
/// <summary>
12+
/// Priority of the Allocation, this can be used to determine the order in which allocations are made when multiple allocations are requested at the same time. This can be useful for optimizing performance and ensuring that critical allocations are made first.
13+
/// </summary>
1114
public enum AllocationPriority
1215
{
16+
/// <summary>
17+
/// The critical Priority, these allocations are the most important and should be allocated first. They are likely to be used for critical game systems or performance-sensitive code.
18+
/// </summary>
1319
Critical = 0,
20+
21+
/// <summary>
22+
/// The normal, Priority, these allocations are important but not as critical as the critical ones. They may be used for general game logic or less performance-sensitive code.
23+
/// </summary>
1424
Normal = 1,
25+
26+
/// <summary>
27+
/// The low, Priority, these allocations are the least important and should be allocated last. They may be used for non-essential game features or background tasks that can tolerate delays in allocation.
28+
/// </summary>
1529
Low = 2
1630
}
1731
}

MemoryManager.Core/BlobEntry.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: MemoryManager.Core
44
* FILE: BlobEntry.cs
5-
* PURPOSE: Your file purpose here
5+
* PURPOSE: A struct representing metadata for a blob allocation within the memory arena, tracking its identifier, offset, size, allocation frame, and version for management and debugging purposes.
66
* PROGRAMMER: Peter Geinitz (Wayfarer)
77
*/
88

@@ -11,10 +11,29 @@ namespace MemoryManager.Core
1111
// A separate struct for tracking Blob metadata
1212
public struct BlobEntry
1313
{
14+
/// <summary>
15+
/// The identifier
16+
/// </summary>
1417
public int Id;
18+
19+
/// <summary>
20+
/// The offset
21+
/// </summary>
1522
public int Offset;
23+
24+
/// <summary>
25+
/// The size
26+
/// </summary>
1627
public int Size;
28+
29+
/// <summary>
30+
/// The allocation frame
31+
/// </summary>
1732
public int AllocationFrame;
33+
34+
/// <summary>
35+
/// The version
36+
/// </summary>
1837
public byte Version;
1938
}
2039
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* COPYRIGHT: See COPYING in the top level directory
3+
* PROJECT: MemoryManager.Lanes
4+
* FILE: MemoryCanary.cs
5+
* PURPOSE: Centralized unmanaged guard band validation with zero RELEASE overhead.
6+
* PROGRAMMER: Peter Geinitz (Wayfarer)
7+
*/
8+
9+
using System.Runtime.CompilerServices;
10+
11+
namespace MemoryManager.Lanes
12+
{
13+
/// <summary>
14+
/// Canary class provides a simple mechanism for detecting buffer overruns and underruns in debug builds by placing known "canary" values before and after user allocations.
15+
/// In release builds, the canary logic is completely stripped out to ensure zero overhead,
16+
/// making it an effective tool for catching memory corruption issues during development without impacting performance in production.
17+
/// </summary>
18+
internal static class MemoryCanary
19+
{
20+
/// <summary>
21+
/// The size
22+
/// </summary>
23+
public const int Size = 4; // 4 bytes for a uint marker
24+
25+
/// <summary>
26+
/// The magic
27+
/// </summary>
28+
private const uint Magic = 0xDEADBEEF;
29+
30+
/// <summary>
31+
/// Calculates the total physical footprint needed in the allocator block pool.
32+
/// </summary>
33+
/// <param name="userSize">Size of the user.</param>
34+
/// <returns></returns>
35+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
36+
public static int GetPhysicalSize(int userSize)
37+
{
38+
#if DEBUG
39+
return userSize + Size * 2;
40+
#else
41+
return userSize;
42+
#endif
43+
}
44+
45+
/// <summary>
46+
/// Maps a raw physical block offset to a user-facing offset past the pre-canary.
47+
/// </summary>
48+
/// <param name="physicalOffset">The physical offset.</param>
49+
/// <returns></returns>
50+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
51+
public static int GetUserOffset(int physicalOffset)
52+
{
53+
#if DEBUG
54+
return physicalOffset + Size;
55+
#else
56+
return physicalOffset;
57+
#endif
58+
}
59+
60+
/// <summary>
61+
/// Maps a user data offset back to the absolute physical block start coordinate.
62+
/// </summary>
63+
/// <param name="userOffset">The user offset.</param>
64+
/// <returns></returns>
65+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
66+
public static int GetPhysicalOffset(int userOffset)
67+
{
68+
#if DEBUG
69+
return userOffset - Size;
70+
#else
71+
return userOffset;
72+
#endif
73+
}
74+
75+
/// <summary>
76+
/// Writes the invariant magic signatures around the user space allocation boundaries.
77+
/// </summary>
78+
/// <param name="buffer">The buffer.</param>
79+
/// <param name="userOffset">The user offset.</param>
80+
/// <param name="userSize">Size of the user.</param>
81+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
82+
public static unsafe void WriteGuardBands(nint buffer, int userOffset, int userSize)
83+
{
84+
#if DEBUG
85+
// Write Pre-Canary directly before the user offset space
86+
*(uint*)(buffer + userOffset - Size) = Magic;
87+
// Write Post-Canary directly at the tail index end of user size space
88+
*(uint*)(buffer + userOffset + userSize) = Magic;
89+
#endif
90+
}
91+
92+
/// <summary>
93+
/// Inspects the boundaries to verify that no adjacent buffer underruns/overruns occurred.
94+
/// </summary>
95+
/// <param name="buffer">The buffer.</param>
96+
/// <param name="userOffset">The user offset.</param>
97+
/// <param name="userSize">Size of the user.</param>
98+
/// <param name="handleId">The handle identifier.</param>
99+
/// <exception cref="AccessViolationException">CRITICAL HEAP CORRUPTION DETECTED: Buffer boundary breach on Handle ID {handleId}. " +
100+
/// $"Expected Canary: 0x{Magic:X}, Pre-Site: 0x{preCanary:X}, Post-Site: 0x{postCanary:X}</exception>
101+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
102+
public static unsafe void Validate(nint buffer, int userOffset, int userSize, int handleId)
103+
{
104+
#if DEBUG
105+
uint preCanary = *(uint*)(buffer + userOffset - Size);
106+
uint postCanary = *(uint*)(buffer + userOffset + userSize);
107+
108+
if (preCanary != Magic || postCanary != Magic)
109+
{
110+
throw new AccessViolationException(
111+
$"CRITICAL HEAP CORRUPTION DETECTED: Buffer boundary breach on Handle ID {handleId}. " +
112+
$"Expected Canary: 0x{Magic:X}, Pre-Site: 0x{preCanary:X}, Post-Site: 0x{postCanary:X}");
113+
}
114+
#endif
115+
}
116+
}
117+
}

0 commit comments

Comments
 (0)