3#if !defined(CWIST_PLATFORM_HOSTED)
6#include <cjson/cJSON.h>
14 return calloc(1, size ? size : 1);
23 if (elem_size > SIZE_MAX /
count)
return NULL;
29 return realloc(ptr, new_size ? new_size : 1);
33 if (!src)
return NULL;
34 size_t len = strlen(src);
36 if (!dst)
return NULL;
37 memcpy(dst, src, len + 1);
42 if (!src)
return NULL;
44 while (len < n && src[len]) len++;
46 if (!dst)
return NULL;
47 memcpy(dst, src, len);
56static void *cwist_cjson_malloc(
size_t size) {
60static void cwist_cjson_free(
void *ptr) {
64__attribute__((constructor))
static void cwist_install_cjson_hooks(
void) {
65 cJSON_Hooks hooks = {.malloc_fn = cwist_cjson_malloc, .free_fn = cwist_cjson_free};
66 cJSON_InitHooks(&hooks);
71#include <ttak/mem/mem.h>
72#include <ttak/timing/timing.h>
73#include <ttak/sync/sync.h>
74#include <cjson/cJSON.h>
87#ifndef ATOMIC_VAR_INIT
88#define ATOMIC_VAR_INIT(value) (value)
91#define CWIST_OWNER_RESOURCE "cwist_mem_resource"
92#define CWIST_OWNER_ALLOC_FUNC "cwist_mem_alloc"
93#define CWIST_OWNER_FREE_FUNC "cwist_mem_free"
94#define CWIST_OWNER_REALLOC_FUNC "cwist_mem_realloc"
100static inline uint64_t cwist_mem_now(
void) {
101 return ttak_get_tick_count();
105 ttak_mem_flags_t flags;
106} cwist_owner_policy_t;
111} cwist_owner_alloc_args_t;
115} cwist_owner_free_args_t;
121} cwist_owner_realloc_args_t;
123static ttak_mutex_t g_owner_lock;
124#if defined(__TINYC__)
125static atomic_bool g_owner_lock_ready =
false;
127static atomic_bool g_owner_lock_ready = ATOMIC_VAR_INIT(
false);
129static ttak_owner_t *g_owner = NULL;
130static cwist_owner_policy_t g_owner_policy = {.flags = TTAK_MEM_DEFAULT | TTAK_MEM_STRICT_CHECK};
131static bool g_owner_enabled =
false;
136static void cwist_owner_lock_init(
void) {
137 if (atomic_load_explicit(&g_owner_lock_ready, memory_order_acquire)) {
140 static atomic_flag init_flag = ATOMIC_FLAG_INIT;
141 while (atomic_flag_test_and_set_explicit(&init_flag, memory_order_acquire)) {
144 if (!atomic_load_explicit(&g_owner_lock_ready, memory_order_relaxed)) {
145 ttak_mutex_init(&g_owner_lock);
146 atomic_store_explicit(&g_owner_lock_ready,
true, memory_order_release);
148 atomic_flag_clear_explicit(&init_flag, memory_order_release);
156static void cwist_owner_alloc(
void *ctx,
void *args) {
157 cwist_owner_policy_t *policy = (cwist_owner_policy_t *)ctx;
158 cwist_owner_alloc_args_t *req = (cwist_owner_alloc_args_t *)args;
160 size_t actual = req->size ? req->size : 1;
161 ttak_mem_flags_t flags = policy ? policy->flags : TTAK_MEM_DEFAULT;
162 req->result = ttak_mem_alloc_safe(actual, __TTAK_UNSAFE_MEM_FOREVER__, cwist_mem_now(),
false,
163 false,
true,
true, flags);
171static void cwist_owner_free(
void *ctx,
void *args) {
173 cwist_owner_free_args_t *req = (cwist_owner_free_args_t *)args;
174 if (!req || !req->ptr)
return;
175 ttak_mem_free(req->ptr);
184static void cwist_owner_realloc(
void *ctx,
void *args) {
185 cwist_owner_policy_t *policy = (cwist_owner_policy_t *)ctx;
186 cwist_owner_realloc_args_t *req = (cwist_owner_realloc_args_t *)args;
188 size_t actual = req->size ? req->size : 1;
189 ttak_mem_flags_t flags = policy ? policy->flags : TTAK_MEM_DEFAULT;
190 req->result = ttak_mem_realloc_safe(req->ptr, actual, __TTAK_UNSAFE_MEM_FOREVER__,
191 cwist_mem_now(),
true, flags);
199 cwist_owner_lock_init();
200 ttak_mutex_lock(&g_owner_lock);
202 ttak_owner_t *owner =
203 ttak_owner_create(TTAK_OWNER_SAFE_DEFAULT | TTAK_OWNER_DENY_DANGEROUS_MEM);
206 ok &= ttak_owner_register_resource(owner, CWIST_OWNER_RESOURCE, &g_owner_policy);
207 ok &= ttak_owner_register_func(owner, CWIST_OWNER_ALLOC_FUNC, cwist_owner_alloc);
208 ok &= ttak_owner_register_func(owner, CWIST_OWNER_FREE_FUNC, cwist_owner_free);
209 ok &= ttak_owner_register_func(owner, CWIST_OWNER_REALLOC_FUNC, cwist_owner_realloc);
211 ttak_owner_destroy(owner);
213 fprintf(stderr,
"[CWIST] Failed to register owner guards\n");
216 fprintf(stderr,
"[CWIST] Failed to create owner context\n");
220 ttak_owner_t *owner = g_owner;
221 ttak_mutex_unlock(&g_owner_lock);
231static bool cwist_owner_call(
const char *func_name,
void *args) {
234 fprintf(stderr,
"[CWIST] Owner unavailable for %s\n", func_name);
237 if (!ttak_owner_execute(owner, func_name, CWIST_OWNER_RESOURCE, args)) {
238 fprintf(stderr,
"[CWIST] Owner rejected call: %s\n", func_name);
248static void cwist_owner_abort(
const char *func_name) {
249 fprintf(stderr,
"[CWIST] Unable to honor %s; aborting to prevent unsafe memory access\n",
260 size_t actual = size ? size : 1;
261 if (!g_owner_enabled) {
262 void *ptr = calloc(1, actual);
265 cwist_owner_alloc_args_t args = {.size = actual, .result = NULL};
266 if (!cwist_owner_call(CWIST_OWNER_ALLOC_FUNC, &args)) {
292 if (
count == 0 || elem_size == 0) {
295 if (elem_size > SIZE_MAX /
count) {
308 size_t actual = new_size ? new_size : 1;
326 if (!g_owner_enabled) {
327 void *res = realloc(ptr, actual);
335 cwist_owner_realloc_args_t args = {.ptr = ptr, .size = actual, .result = NULL};
336 if (!cwist_owner_call(CWIST_OWNER_REALLOC_FUNC, &args) || !args.result) {
350 if (!src)
return NULL;
351 size_t len = strlen(src);
353 if (!dst)
return NULL;
354 memcpy(dst, src, len + 1);
364static size_t cwist_strnlen(
const char *src,
size_t max_len) {
366 while (len < max_len && src[len]) {
379 if (!src)
return NULL;
380 size_t len = cwist_strnlen(src, n);
382 if (!dst)
return NULL;
383 memcpy(dst, src, len);
405 if (!g_owner_enabled) {
409 cwist_owner_free_args_t args = {.ptr = ptr};
410 if (!cwist_owner_call(CWIST_OWNER_FREE_FUNC, &args)) {
411 cwist_owner_abort(CWIST_OWNER_FREE_FUNC);
424 void *ptr = malloc(size ? size : 1);
435 void *ptr = calloc(nmemb ? nmemb : 1, size ? size : 1);
450 size_t actual = size ? size : 1;
454 bool was_tracked =
false;
458 void *new_ptr = realloc(ptr, actual);
483static void *cwist_cjson_malloc(
size_t size) {
491static void cwist_cjson_free(
void *ptr) {
498__attribute__((constructor))
static void cwist_install_cjson_hooks(
void) {
499 cJSON_Hooks hooks = {.malloc_fn = cwist_cjson_malloc, .free_fn = cwist_cjson_free};
500 cJSON_InitHooks(&hooks);
506static void cwist_destroy_owner(
void) {
507 if (!atomic_load_explicit(&g_owner_lock_ready, memory_order_acquire)) {
510 ttak_mutex_lock(&g_owner_lock);
512 ttak_owner_destroy(g_owner);
515 ttak_mutex_unlock(&g_owner_lock);
521__attribute__((destructor))
static void cwist_owner_cleanup(
void) {
522 cwist_destroy_owner();
__attribute__((constructor))
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
void * cwist_realloc(void *ptr, size_t new_size)
Resize an existing allocation (libttak tracked).
char * cwist_strdup(const char *src)
Duplicate a string using libttak-backed storage.
void * cwist_malloc(size_t size)
Allocate zeroed memory via the CWIST owner context.
void * cwist_alloc_array(size_t count, size_t elem_size)
Allocate zeroed memory for count elements.
char * cwist_strndup(const char *src, size_t n)
Duplicate up to n bytes of a string (libttak-backed).
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Memory allocation wrappers backed by libttak.
ttak_owner_t * cwist_create_owner(void)
Lazily create (or return) the shared CWIST owner context.
bool cwist_gc_reg_untrack(void *ptr)
Detach ptr from whichever GC context tracks it, without freeing.
Epoch-based garbage collection wrapper.
bool cwist_full_gc_enabled(void)
Check whether full-GC mode is currently enabled.
bool cwist_gc_scope_untrack(void *ptr)
Remove a block from the current thread's pending-sweep list.
void cwist_gc_scope_track(void *ptr)
Register a cwist_alloc() block with the current thread's pending-sweep list (full-GC mode only).
Internal bridge between the allocator and the epoch GC wrapper.
void * cwist_calloc_shim(size_t nmemb, size_t size)
calloc() replacement: real libc calloc() (zeroed), registered with the full-GC pending-sweep list whe...
void * cwist_realloc_shim(void *ptr, size_t size)
realloc() replacement. Tracking follows the incoming pointer: if ptr was tracked (shimmed-and-full-GC...
void cwist_free_shim(void *ptr)
free() replacement: untracks ptr first if it was tracked (safe no-op if it wasn't - same contract as ...
void * cwist_malloc_shim(size_t size)
malloc() replacement: real libc malloc() (uninitialized memory, exactly like malloc - unlike cwist_al...