بنقرة واحدة
memory
talloc-based memory management and ownership rules for ikigai
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
talloc-based memory management and ownership rules for ikigai
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Automated quality check loops with escalation and fix sub-agents
JSON-based end-to-end test format, runner, and mock provider
Jujutsu (jj) skill for the ikigai project
How to write effective Ralph goals for Ikigai-driven workflows
Create and manage Ralph goals from Ikigai using the real ralph-pipeline scripts
Create repositories using the real ralph-pipeline repo-create script
| name | memory |
| description | talloc-based memory management and ownership rules for ikigai |
talloc hierarchical memory allocator for ikigai. Use this for all new code.
Always use zero-initialized allocations (talloc_zero, talloc_zero_array) unless you intentionally choose not to for performance reasons. Uninitialized memory is a source of bugs.
// PREFER: Zero-initialized
foo_t *foo = talloc_zero(ctx, foo_t);
int *arr = talloc_zero_array(ctx, int, 100);
// ONLY when performance-critical and you will initialize all fields:
foo_t *foo = talloc(ctx, foo_t);
// Context creation
TALLOC_CTX *talloc_new(const void *parent);
// Allocation (children of ctx)
void *talloc(const void *ctx, type);
void *talloc_zero(const void *ctx, type);
void *talloc_array(const void *ctx, type, count);
char *talloc_strdup(const void *ctx, const char *str);
char *talloc_asprintf(const void *ctx, const char *fmt, ...);
// Deallocation
int talloc_free(void *ptr); // Frees ptr and ALL children
// Hierarchy manipulation
void *talloc_steal(const void *new_parent, const void *ptr);
void *talloc_reference(const void *ctx, const void *ptr);
void handle_request(const char *input) {
TALLOC_CTX *req_ctx = talloc_new(NULL);
// All allocations are children of req_ctx
res_t res = ik_protocol_msg_parse(req_ctx, input);
if (is_err(&res)) {
talloc_free(req_ctx);
return;
}
ik_protocol_msg_t *msg = res.ok;
// ... process message ...
talloc_free(req_ctx); // Frees msg and all children at once
}
res_t ik_cfg_load(TALLOC_CTX *ctx, const char *path) {
// Allocate config as child of caller's context
ik_cfg_t *config = talloc_zero_(ctx, sizeof(ik_cfg_t));
if (!config) PANIC("Out of memory");
// Strings are children of config
config->openai_api_key = talloc_strdup(config, key_from_file);
config->listen_address = talloc_strdup(config, addr_from_file);
return OK(config);
}
// Caller owns and frees
TALLOC_CTX *ctx = talloc_new(NULL);
res_t res = ik_cfg_load(ctx, "config.json");
ik_cfg_t *config = res.ok;
// ... use config ...
talloc_free(ctx); // Frees config and all strings
Correct - Fields are children of struct:
res_t foo_init(TALLOC_CTX *ctx, foo_t **out) {
foo_t *foo = talloc_zero_(ctx, sizeof(foo_t));
// Allocate fields on foo (not on ctx)
foo->name = talloc_strdup(foo, "example"); // Child of foo
foo->data = talloc_array(foo, char, 1024); // Child of foo
*out = foo;
return OK(*out);
}
// Now talloc_free(foo) frees name and data automatically
Wrong - Fields as siblings:
// DON'T DO THIS
foo_t *foo = talloc_zero_(ctx, sizeof(foo_t));
foo->name = talloc_strdup(ctx, "example"); // Sibling, not child!
// Now talloc_free(foo) does NOT free name - memory leak
res_t process(TALLOC_CTX *ctx, input_t *in) {
// Temporary context for intermediate work
TALLOC_CTX *tmp = talloc_new(ctx);
// Intermediate allocations on tmp
char *buf = talloc_array(tmp, char, 4096);
parsed_t *p = talloc_zero(tmp, parsed_t);
// ... process ...
// If keeping result, steal it to parent context
result_t *result = process_internal(tmp, in);
if (keep_result) {
talloc_steal(ctx, result);
}
talloc_free(tmp); // Cleans all intermediates
return OK(result);
}
CRITICAL: Never use fixed-size allocations unless you know the exact size of the data.
// NEVER: char buffer[1024]; sprintf(buffer, "%s: %s", key, value);
// ALWAYS: char *str = talloc_asprintf(ctx, "%s: %s", key, value);
Strategies for unknown sizes:
Common cases:
talloc_asprintf(ctx, fmt, ...)talloc_asprintf(ctx, "%s/%s", dir, file)stat() first, allocate st.st_size, then read()Rule: If you don't know the size, use dynamic allocation.
DANGER: Never allocate errors on temporary contexts.
// WRONG - Error allocated on tmp, then tmp freed = use-after-free
res_t bad_example(TALLOC_CTX *ctx) {
TALLOC_CTX *tmp = talloc_new(ctx);
res_t res = some_function(tmp); // Error on tmp!
if (is_err(&res)) {
talloc_free(tmp); // FREES THE ERROR!
return res; // Crash - res.err is freed
}
talloc_free(tmp);
return OK(NULL);
}
// CORRECT - Pass parent context for error allocation
res_t good_example(TALLOC_CTX *ctx) {
TALLOC_CTX *tmp = talloc_new(ctx);
res_t res = some_function(ctx); // Error on ctx (parent)
if (is_err(&res)) {
talloc_free(tmp);
return res; // Safe - error on ctx
}
talloc_free(tmp);
return OK(NULL);
}
Rule: Functions that can fail should allocate errors on the parent context (usually first parameter), not on temporary contexts.
*_init(TALLOC_CTX *ctx, foo_t **out) - Allocate on ctx, return via out parameter*_create() - Allocates and returns owned pointer*_load() - Allocates and returns owned pointer (from file/network)*_free() - Deallocates object and all children*_parse(TALLOC_CTX *ctx, ...) - Parse and allocate on ctxRare cases for plain malloc():
free()-able memoryDefault: Use talloc for everything else.
Memory allocation failures call PANIC("Out of memory") which terminates the process immediately. OOM is not a recoverable error.
void *ptr = talloc_zero(ctx, type);
if (!ptr) PANIC("Out of memory"); // LCOV_EXCL_BR_LINE
// Enable leak reporting
talloc_enable_leak_report();
talloc_enable_leak_report_full();
// Dump memory tree
talloc_report_full(context, stdout);
// Report leaks at exit
atexit(talloc_report_full_on_exit);
talloc_*(struct, ...) not talloc_*(ctx, ...)Create context:
TALLOC_CTX *ctx = talloc_new(parent); // parent=NULL for root
Allocate:
foo_t *foo = talloc_zero_(ctx, sizeof(foo_t));
char *str = talloc_strdup(ctx, "text");
int *arr = talloc_array(ctx, int, 100);
Free:
talloc_free(ctx); // Frees ctx and ALL children recursively
Move ownership:
talloc_steal(new_parent, ptr); // ptr is now child of new_parent
For full details, see project/memory.md.