Memory ​
When your plugin follows pointers through game objects, a stale or wrong pointer must not crash the game. swofty/mem.hpp checks that the bytes are committed and readable before it touches them. It also tells game objects from garbage and reads C strings only when they are real text. The header is self-contained: it needs no core table and works with any loader.
| Header | swofty/mem. |
| Namespace | swofty::mem |
| Table | none |
| Thread | Any |
Calls ​
| Call | Returns |
|---|---|
readable(p, n) | true when n bytes at p are committed and readable |
read<T>(addr, T &out) | true and copies a T when its bytes are readable |
in_image(p) | true when p lies in the game exe's image (code, vtables, static data) |
object_like(p) | true for a readable, 8-byte aligned pointer whose first word is a vtable in the image |
c_string(p, std::string &out, max = 256) | true for 1 to max - 1 bytes of printable UTF-8 ending in a NUL |
printable_utf8(s, n) | true for valid UTF-8 without control characters (tab, newline and carriage return pass) |
invalidate() | drops every thread's cached region answers |
Each call takes an address as uintptr_t or as a pointer. c_string rejects text that isn't valid UTF-8, contains control characters or has no NUL within max, so it never accepts a pointer's own bytes as a name.
Cost ​
Each thread caches the region answers of VirtualQuery for 64 pages and keeps each for ttl_ms (250 ms). Most checks in a per-frame walk hit the cache, so the guards are cheap enough to run every frame. Memory the game frees can stay marked readable in the cache until the entry expires. If you know the game has just freed or remapped memory you were reading, call invalidate().
Example ​
#include <cstddef>
#include <swofty/mem.hpp>
struct Named {
void **vtable;
const char *name;
};
bool name_of(uintptr_t obj, std::string &out)
{
uintptr_t text = 0;
return swofty::mem::object_like(obj) && swofty::mem::read(obj + offsetof(Named, name), text) &&
swofty::mem::c_string(text, out, 64);
}In a real addon, Named is a struct from the Game API: take field offsets from those structs rather than writing them by hand.