Files
cproof-context/patterns/memory.md
jabber.developer2 22977846a3 docs: split context into layered, agent-oriented files
Replace the single file-structure.md with a stratified layout designed
for AI/agent skill consumption: tables and concrete identifiers over
prose, files loaded on demand, content separated by churn rate.

Layers:
- architecture/  stable structural reference (overview, source-map,
                 test-map, data-flow)
- patterns/      memory, commands, autocomplete, events, xmpp,
                 encryption, ui, plugins
- testing/       unit-tests, stubs, functional-tests, bench
- build/         local, docker, ci
- playbooks/     add-command, add-test, add-autocomplete,
                 add-event-handler, add-encryption
- gotchas.md     append-only dated entries (seven seed entries)
- wip/           branch-specific notes; deleted on merge to master

Stable layers describe cproof on master only. In-flight feature
branches (currently feat/ai) get a single file under wip/.

INDEX.md is the entry map with churn labels; SKILL.md is the
always-loaded skill hint pointing to it.
2026-04-30 20:52:06 +03:00

66 lines
2.7 KiB
Markdown

# Memory management
## `auto_*` macros
GCC/Clang `__cleanup__` attribute, declared in `src/common.h` (one exception:
`auto_jid` lives in `src/xmpp/jid.h` because it needs the `Jid` type).
| Macro | Type | Cleanup | Use for |
|---|---|---|---|
| `auto_gchar` | `gchar*` | `auto_free_gchar()` | GLib strings (`g_strdup`, `g_strdup_printf`, etc.) |
| `auto_gcharv` | `gchar**` | `auto_free_gcharv()` | GLib string arrays (`g_strsplit`, `g_strjoinv` arg) |
| `auto_char` | `char*` | `auto_free_char()` | C strings (`strdup`, `malloc`'d) |
| `auto_guchar` | `guchar*` | `auto_free_guchar()` | Unsigned char buffers (e.g. `g_base64_decode`) |
| `auto_gfd` | `gint` | `auto_close_gfd()` | File descriptors held in a `gint` |
| `auto_FILE` | `FILE*` | `auto_close_FILE()` | `FILE*` from `fopen` |
| `auto_jid` | `Jid*` | `jid_auto_destroy()` | `Jid` structs (XMPP) |
Place the macro **before** the type, like `gboolean`-style attribute:
```c
auto_gchar gchar* msg = g_strdup_printf("hello %s", name);
auto_gcharv gchar** parts = g_strsplit(line, " ", -1);
```
The cleanup runs at scope exit, including early returns. Do **not** call the
matching `g_free`/`g_strfreev`/`fclose` manually — that double-frees.
## Manual cleanup helpers
In `common.h`:
| Macro | Behaviour |
|---|---|
| `FREE_SET_NULL(ptr)` | `free(ptr); ptr = NULL;` (use for `malloc`'d) |
| `GFREE_SET_NULL(ptr)` | `g_free(ptr); ptr = NULL;` (use for GLib-allocated) |
Use these when the pointer is a struct field that must remain accessible
after the free (so a later `if (x->p)` is safe).
## GLib free-function reference
| Allocator | Free with |
|---|---|
| `g_strdup`, `g_strdup_printf`, `g_strconcat`, ... | `g_free` (or `auto_gchar`) |
| `g_strsplit`, `g_strdupv` | `g_strfreev` (or `auto_gcharv`) |
| `g_list_*` of allocated items | `g_list_free_full(list, free_fn)` |
| `g_hash_table_new[_full]` | `g_hash_table_destroy` (uses key/value destroy fns if supplied) |
| `g_base64_decode` | `g_free` (or `auto_guchar`) |
| `g_key_file_*` | `g_key_file_free` |
**Common pitfall:** mixing `g_free` and `free`. GLib uses its own allocator
shim; never cross the boundary. If you got the buffer from a GLib function,
free it with the matching GLib function.
**Common pitfall:** `g_strsplit` returns `gchar**` — free with `g_strfreev`,
not `g_free`. (See `gotchas.md`.)
## Adding a new `auto_*`
1. Declare cleanup function: `void auto_close_foo(Foo** p);`
2. Define the macro: `#define auto_foo __attribute__((__cleanup__(auto_close_foo)))`
3. Place both in the header that owns the type — `common.h` for project-wide,
the type's own header otherwise.
4. The cleanup must tolerate `NULL` and idempotent re-entry; assign `*p = NULL`
inside if you keep the variable accessible after free.