{"id":51691409,"url":"https://github.com/ericsssan/zbc","last_synced_at":"2026-07-16T02:34:00.238Z","repository":{"id":359231389,"uuid":"1244863694","full_name":"ericsssan/zbc","owner":"ericsssan","description":"A deep static analyzer for Zig.","archived":false,"fork":false,"pushed_at":"2026-06-11T15:28:34.000Z","size":2304,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-16T02:33:59.136Z","etag":null,"topics":["lifetimes","linter","memory-safety","ownership","static-analysis","zig"],"latest_commit_sha":null,"homepage":null,"language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ericsssan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"ericsssan"}},"created_at":"2026-05-20T17:12:44.000Z","updated_at":"2026-06-14T14:37:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ericsssan/zbc","commit_stats":null,"previous_names":["ericsssan/zbc"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/ericsssan/zbc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericsssan%2Fzbc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericsssan%2Fzbc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericsssan%2Fzbc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericsssan%2Fzbc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ericsssan","download_url":"https://codeload.github.com/ericsssan/zbc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ericsssan%2Fzbc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35528482,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lifetimes","linter","memory-safety","ownership","static-analysis","zig"],"created_at":"2026-07-16T02:33:59.674Z","updated_at":"2026-07-16T02:34:00.232Z","avatar_url":"https://github.com/ericsssan.png","language":"Zig","funding_links":["https://github.com/sponsors/ericsssan"],"categories":[],"sub_categories":[],"readme":"# zbc\n\nInfers Zig lifetime, ownership, and cleanup bugs from your code — no\nannotations, no runtime instrumentation.\n\n## Example\n\n```zig\nconst Owner = struct {\n    data: []u8,\n    pub fn deinit(self: *Owner, gpa: Allocator) void { gpa.free(self.data); }\n};\n\nvar owner = Owner{ .data = try gpa.alloc(u8, 16) };\nconst x = owner.data;\nowner.deinit(gpa);   // frees self.data — zbc reads the body to know this\n_ = x;               // → heap-use-after-free\n```\n\n## Build integration\n\n```sh\nzig fetch --save https://github.com/ericsssan/zbc/archive/refs/tags/v0.1.0.tar.gz\n```\n\n```zig\n// build.zig\nconst zbc_dep = b.dependency(\"zbc\", .{\n    .target = target,\n    .optimize = .ReleaseFast,\n});\n\nconst zbc_run = b.addRunArtifact(zbc_dep.artifact(\"zbc\"));\nzbc_run.addArg(\"src/\");\n\nb.default_step.dependOn(\u0026zbc_run.step);\n```\n\n## CLI\n\nFor standalone use:\n\n```sh\nzig build -Doptimize=ReleaseFast\nzbc src/\nzbc --format=compact src/   # grep-friendly\nzbc --list-rules\nzbc --explain \u003crule-id\u003e\n```\n\nExit 0 if clean, 1 if problems found.\n\n## Rules\n\n45 rules in two families:\n\n**Flow analysis** — must-not-escape / must-not-free-twice guarantees via\nper-fn CFG and abstract interpretation:\n\n`heap-use-after-free`, `heap-double-free`, `arena-use-after-kill`,\n`arena-escape`, `stack-escape`, `use-undefined`, `allocator-mismatch`,\n`interior-pointer-destroy`\n\n**Pattern detectors** — catches recurring bug shapes from real Zig PRs:\n\n- Heap leak / aliasing: `heap-leak`, `partial-union-write`,\n  `aliased-heap-dupe`, `clobbered-by-struct-reset`, `realloc-byte-count`,\n  `asymmetric-field-free`, `free-without-null-then-check`,\n  `overwrite-without-deinit`\n- Error-path cleanup: `missing-errdefer-between-tries`,\n  `free-then-try-realloc`, `destroy-after-deinit-in-loop`,\n  `dead-errdefer-in-result-fn`, `duplicate-errdefer`,\n  `missing-errdefer-on-out-param`, `unreleased-refs-on-error`,\n  `unreleased-factory-handle`\n- Pointer / slice stability: `hashmap-getptr-rehash`,\n  `arraylist-items-slice`, `fd-write-after-close`,\n  `stack-fallback-escape`, `slice-of-arena-into-heap`,\n  `borrowed-slice-into-out-param`,\n  `borrowed-slice-into-stack-buffer-returned`,\n  `memset-undef-after-len-truncation`,\n  `sentinel-strip-free-size-mismatch`\n- Tagged-union semantics: `tagged-union-retag-with-old-payload-read`,\n  `union-deinit-without-inert-reset`, `self-undefined-after-destroy`,\n  `return-borrowed-payload`\n- Lifecycle / sibling consistency: `reset-skips-pooled-resource-release`,\n  `missing-deinit-on-composed-owner`, `owned-field-no-outer-cleanup`,\n  `deinit-order-violates-construction-dep`,\n  `defer-and-errdefer-free-overlap`, `move-out-without-restore`\n- Concurrency / hardening: `publish-then-touch-self`,\n  `assert-on-untrusted-input`\n\n`zbc --explain \u003crule-id\u003e` prints the rationale, canonical bug, and fix.\n\n## False positives and missed bugs\n\nIf zbc fires on correct code (false positive) or misses a real bug (false\nnegative), please [open an issue](https://github.com/ericsssan/zbc/issues)\nwith a minimal reproducer.  Both matter — FP reports drive suppression\nimprovements, FN reports drive new rules and deeper inference.\n\n## Suppressions\n\nSilence a false positive with a source comment:\n\n```zig\nbuf[idx - 1] // zbc-disable-line: index-minus-one-without-zero-guard\n\n// zbc-disable-next-line: heap-use-after-free\n_ = ptr;\n\n_ = val; // zbc-disable-line: *   (all rules on this line)\n```\n\n## Sponsor\n\nIf zbc saves you debugging time, consider [sponsoring development](https://github.com/sponsors/ericsssan).\n\n## Acknowledgements\n\n- [ZLS](https://github.com/zigtools/zls) — type-resolution internals\n  (`DocumentStore`, `InternPool`, `Analyser`) extracted and adapted into\n  `src/type_engine/` as zbc's embedded type engine.  Not imported as a\n  package; vendored and modified in-tree.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericsssan%2Fzbc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fericsssan%2Fzbc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fericsssan%2Fzbc/lists"}