원클릭으로
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.