The Half-Life Unified SDK replaces the engine’s default string allocation mechanism with a dedicated string pool that interns strings, meaning that allocating the same string multiple times returns the same stored copy rather than creating a new allocation each time. This eliminates a class of memory exhaustion bugs that could occur in the original SDK and makes string allocation safe to call in frequently-executed code paths such as player frame logic.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/twhl-community/halflife-unified-sdk/llms.txt
Use this file to discover all available pages before exploring further.
The Problem with the Original Approach
The original SDK used the engine’spfnAllocString function (via the ALLOC_STRING macro) to allocate string_t values. This function allocated memory from the engine’s internal heap on every call, even when the exact same string had already been allocated. Because the heap is fixed in size, repeatedly calling ALLOC_STRING with the same string — for example, inside entity think or touch functions — causes heap usage to grow linearly over time.
Eventually the engine heap runs out of space and the game crashes with the fatal error:
<size> is the size of the string that could not be allocated.
How the String Pool Fixes This
The new string pool is detached from the engine’s heap entirely. When a string is allocated, the pool checks whether an identical string already exists. If it does, the existing entry is returned; no new memory is allocated. If it does not, the string is stored once and the pool entry is returned for all future requests. In practice, most strings are allocated for the first time during map spawn. After that point the pool’s memory usage levels off, regardless of how many times those strings are requested later in the map’s lifetime.The string pool is cleared at the start of each map. Strings allocated during one map are not carried over to the next.
Read-Only Strings
Because everystring_t now refers to a shared, pooled entry, all string_t strings are read-only. This was always implicitly true in the original SDK (modifying one instance would corrupt any code that expected the original value), but the pool makes it an explicit requirement: modifying a pooled string would change the value seen by every piece of code holding a reference to that entry.
Escape Sequence Handling
The engine’s originalpfnAllocString implementation also processed escape sequences in a limited and often incorrect way:
\n(backslash followed byn) was converted to a newline character (\n).- Any other occurrence of
\followed by a character caused the backslash to be dropped and the following character to be kept.
\ is the default path separator on Windows, strings like maps\mymap.bsp would be silently corrupted on allocation, turning into mapsXmymap.bsp (where X is whatever character followed the backslash).
If the escape-sequence conversion behaviour is intentionally needed, the ALLOC_ESCAPED_STRING macro provides it explicitly. Using this macro makes the intent clear at the call site and keeps normal string allocation free of unintended transformations.
Allocating from String Views
TheALLOC_STRING_VIEW macro allows a string_t to be allocated from a string view — a reference to a character sequence that does not necessarily end with a null terminator. This is useful when working with substrings or string parsing code where null-terminated copies would otherwise need to be constructed first.
Summary of Macros
| Macro | Description |
|---|---|
ALLOC_STRING(str) | Allocates a pooled string_t. No escape processing. |
ALLOC_ESCAPED_STRING(str) | Allocates a pooled string_t with escape-sequence processing matching the original engine behaviour: \\n is converted to a newline, and other \\<char> sequences have the backslash removed. |
ALLOC_STRING_VIEW(view) | Allocates a pooled string_t from a string view (does not require null termination). |