# HG changeset patch # User MrJuneJune # Date 1785881538 25200 # Node ID 5ec271d612ae34b4b2524cc9302f646a03d74bba # Parent 2b6e732087ff626b3179f23c402cdd25c91bc93c [dowa] Enforce arena ownership Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> diff -r 2b6e732087ff -r 5ec271d612ae .claude/skills/zenbu-bazel-c/SKILL.md --- a/.claude/skills/zenbu-bazel-c/SKILL.md Tue Aug 04 15:12:09 2026 -0700 +++ b/.claude/skills/zenbu-bazel-c/SKILL.md Tue Aug 04 15:12:18 2026 -0700 @@ -26,6 +26,10 @@ Avoid broad searches in `third_party/`, Bazel output directories, virtualenvs, `node_modules`, and generated bundles unless the task specifically requires them. +For cross-codebase audits, inspect `BUILD` files and Bazel dependencies first. +Use the dependency graph to identify actual first-party consumers before broad +text search, then audit only those targets and their transitive owners. + ## Build and test commands Use Bazel targets from the repository root: @@ -58,6 +62,16 @@ `TRUE`/`FALSE` in first-party C. Do not introduce `` `_t` aliases or `` `bool` when a Dowa type already expresses the value. - C code generally uses `Dowa_Arena` for request-scoped allocations. +- An arena owns every pointer returned by `Dowa_Arena_Allocate`, aligned arena + allocation, arena string helpers, and arena array/hash-map macros. Never pass + those pointers to libc `free()`, `Dowa_Free`, or an element-level destroy + function. +- Release a locally created arena exactly once with `Dowa_Arena_Free()` on + every return path. Do not release a borrowed request arena; its owner must + free it. +- Prefer `Dowa_Free` over raw libc `free()` for separately heap-allocated + first-party pointers. Keep the allocation source explicit when heap and arena + ownership coexist in one function. - HTTP responses are usually `Seobeo_Request_Entry *resp = NULL` maps filled with `Dowa_HashMap_Push_Arena`. - Route handlers return response maps; streaming handlers receive `Seobeo_Handle *` directly. - Existing code favors explicit status/content-type/body response fields. diff -r 2b6e732087ff -r 5ec271d612ae mrjunejune/create_html_from_md.c --- a/mrjunejune/create_html_from_md.c Tue Aug 04 15:12:09 2026 -0700 +++ b/mrjunejune/create_html_from_md.c Tue Aug 04 15:12:18 2026 -0700 @@ -126,10 +126,9 @@ Blog_Metadata meta = Parse_Blog_Frontmatter(md_file); char *md = markdown_to_html(meta.content); char *ssr_body = Dowa_Arena_Allocate(arena, buffer_sizes); - char *final_body = Dowa_Arena_Allocate(arena, buffer_sizes); snprintf(ssr_body, buffer_sizes, BLOG_HTML, meta.description, meta.title, md); + markdown_free(md); - int open_flags = O_RDWR | O_CREAT | O_EXCL; size_t md_file_path_length = strlen(md_file_path); md_file_path_length -= 3; // html char *new_file_path = Dowa_Arena_Allocate(arena, 1024); @@ -137,11 +136,14 @@ FILE *new_file_fd = fopen(new_file_path, "w+"); if (!new_file_fd) - return; + { + Dowa_Arena_Free(arena); + return 1; + } printf("Saving to %s...\n", new_file_path); fwrite(ssr_body, 1, buffer_sizes, new_file_fd); fclose(new_file_fd); } + Dowa_Arena_Free(arena); return 0; } - diff -r 2b6e732087ff -r 5ec271d612ae s3/s3_uploader.c --- a/s3/s3_uploader.c Tue Aug 04 15:12:09 2026 -0700 +++ b/s3/s3_uploader.c Tue Aug 04 15:12:18 2026 -0700 @@ -73,12 +73,12 @@ const char *content_type) { S3_Result result = {0}; - result.p_arena = Dowa_Arena_Create(S3_RESULT_ARENA_SIZE); size_t file_size = 0; uint8 *file_data = s3__load_file(local_path, &file_size); if (!file_data) { + result.p_arena = Dowa_Arena_Create(S3_RESULT_ARENA_SIZE); result.success = FALSE; result.status_code = 0; result.error_message = Dowa_String_Copy_Arena("Failed to read file", result.p_arena); @@ -86,7 +86,7 @@ } result = S3_Upload_Data(p_config, file_data, file_size, s3_key, content_type); - free(file_data); + Dowa_Free(file_data); return result; } @@ -706,7 +706,7 @@ s3__hmac_sha256(k_service, 32, (const uint8 *)S3_AWS4_REQUEST, strlen(S3_AWS4_REQUEST), out); - free(k_secret); + Dowa_Free(k_secret); } static char *s3__build_authorization_header(const char *access_key, @@ -777,7 +777,7 @@ if (read != (size_t)size) { - free(data); + Dowa_Free(data); *p_size = 0; return NULL; }