Repository navigation
vibee_gen aborts (SIGABRT) on 18 Verilog specs and intermittently on 2 Zig specs #887
Description
Part of #851, weak point W15. Found by #885/#886. This is a compiler change (src/vibeec/), so the fix is the owner's call. Nothing here has been edited.
What is measured
vibee_gen gen <spec> <out> ends in SIGABRT (signal 6) on 19 of the 1033 specs that report behaviours.
-
Probe run 37242067946 on
exp/codegen-flake-ab, 60 passes over the corpus, removing the destination before each generation:-
18 specs abort and leave a 0-byte file, in every pass:
specs/fpga/blink.tri,counter.tri,fsm_simple.tri;specs/fpga/test_blink.tri,test_counter.tri,test_debouncer.tri,test_multi_led.tri,test_pwm.tri,test_shift_register.tri,test_values.tri;specs/tri/bitnet_mac.vibee,specs/tri/fpga/bitnet_mac.vibee,specs/tri/fpga/trinity_ai_core.vibee,specs/tri/fpga/trit_alu.vibee;specs/tri/trinity_ai_core.vibee,specs/tri/trit_alu.vibee;specs/uart/uart_mode_controller.tri,specs/uart/vsa_uart_operations.tri.
-
Two Zig-target specs abort some of the time and leave no file:
spec aborts otherwise specs/tri/long_context_system.vibee59 of 60 1 of 60 exits 0 and writes a file specs/tri/hdc_stream_classifier.vibee3 of 60 57 of 60 write the same file
-
-
fix(codegen): sample the corpus compile check from the baseline #886's own CI run 37243448031 shows the same 19 as
NO OUTPUT … signal 6, no file. -
zig ast-checkandzig testboth pass a 0-byte file, so before fix(codegen): sample the corpus compile check from the baseline #886 the corpus gate counted the 18 as clean.
The Verilog path: a borrowed slice used after its owner is freed (read from source, not measured)
src/vibeec/vibee_gen.zig on 57de4a1f5:
// 432-436
if (std.mem.eql(u8, spec.language, "varlog") or std.mem.eql(u8, spec.language, "verilog")) {
var codegen = verilog_codegen.VerilogCodeGen.init(allocator);
defer codegen.deinit(); // runs at the end of this block
generated_code = try codegen.generate(spec); // a slice into codegen's buffer
}
// ...
defer allocator.free(generated_code); // 448: frees it again
writeGenerated(output_path, generated_code) ... // 449: writes freed memoryVerilogCodeGen.generatereturnsself.builder.getOutput()(verilog_codegen.zig:321, and again at:380).getOutputreturnsself.buffer.items(:271), a borrowed slice.VerilogCodeGen.deinit(:293) frees that buffer, and thedeferruns when theifblock ends, before line 449.- Line 448 then frees the same memory a second time, with
items.lenrather than the capacity. generateSingleLangrepeats the pattern at 464-466.- The Zig path does not have this problem:
codegen/emitter.zig:1008returnsself.builder.toOwnedSlice().
Why that ends in SIGABRT with a 0-byte file is an inference:
mainusesstd.heap.page_allocator(vibee_gen.zig:84), sodeinitunmaps the buffer's pages.writeGeneratedcreates the file (:219), so the file exists at 0 bytes.- The write is then handed an unmapped address. The kernel returns
EFAULT, and the standard library treats that as unreachable. In a safety-checked build that is a panic, and the panic aborts. - Because it is a panic rather than an error, the cleanup in
writeGeneratedthat deletes a partial file never runs.
The next CI run of #886 tests this: its gate now prints the panic line instead of the last stack frame. If that line is not an unreachable or EFAULT panic in the write, the inference is wrong, and this issue will be corrected.
Proposed fix (one line, not applied): return an owned slice from VerilogCodeGen.generate, the way the Zig emitter does. That means self.builder.buffer.toOwnedSlice(self.allocator) or an allocator.dupe at the call site. Then the existing defer allocator.free(generated_code) is correct for both paths.
The Zig-path aborts: cause unknown
long_context_system and hdc_stream_classifier abort without a pattern that has been explained. Nothing above accounts for them. Next step: run each one 60 times locally with a Debug build of vibee_gen and read the full trace.
Why it mattered for CI (inference, strong)
-
Main's corpus gate counted a missing file as clean, and it sampled every 32nd entry of the run's own clean list.
-
hdc_stream_classifieris not in the baseline, and it sorts beforespecs/tri/phi_utils_multi.tri, which sits one place before a sample slot. -
When it aborts, main's gate counts one extra clean spec. That pushes
phi_utils_multiinto the sample, and its output does not compile. -
Main's codegen run was red 6 times on branch
mainfrom 09-24 to 10-04. Five of those were exactlyDOES NOT COMPILE: specs/tri/phi_utils_multi.tri:- 36027587352;
- 36029076209;
- 37016445887;
- 37088537159;
- 37225448222.
The sixth (36515512024) was the
vsa_simdbenchmark. -
5 of 66 runs is consistent with an abort rate of 3 in 60, but main's gate printed no names on red, so the runs cannot be checked after the fact. fix(codegen): sample the corpus compile check from the baseline #886 removes the mechanism whatever the trigger was.
Also found while there (probe 37242067946, compile-all)
Of the 769 outputs that are really written, 13 pass ast-check and fail zig test:
- 9 because they
@import("vsa"), which the corpus does not provide: thespecs/tri/vsa_*encoders and benchmarks; - 3 with a failure the probe recorded as blank:
codegen_engine_final_upgrade,sacred_identity,swarm_agents; phi_utils_multi, whose function with a non-void return type implicitly returns.
On 02b9958de none of these falls in #886's 24-slot compile sample: that run compiled 24 of 24. A baseline edit that moves the slots could land on one, and the gate would then name it.
The 18 Verilog specs are all language: varlog, and the two that abort intermittently are language: zig. Both were checked against 57de4a1f5.
Done when
- Owner decides on the Verilog-path fix above.
- Then the 18 Verilog specs write output, and fix(codegen): sample the corpus compile check from the baseline #886's baseline gains them back.
- Cause of the Zig-path aborts is found, or they are filed separately.
🤖 Generated with Claude Code
Activity
fix(codegen): say "empty file" when it is one, and name crash-handler…
gHashTag commentedon Oct 4, 2026
The prediction held for the 18 Verilog specs
#886's gate now prints the generator's panic line. Run 37243963781 on
d959eb722printed the same line for all 18language: varlogspecs, for example:That text comes from
errnoBugin Zig 0.16'sstd/Io/Threaded.zig. The standard library calls it for an errno it treats as a programming error, such asEFAULT. That matches the chain above: the write is handed an address whose pages were unmapped, the kernel returnsEFAULT, and the panic aborts. Step 3 of the inference is now measured.What is still read from source rather than observed: that the bad address is the freed Verilog buffer. No other freed slice reaches that write.
One nuance the issue body did not state:
errnoBugpanics only whenis_debug. In a release build it returnserror.Unexpectedinstead.writeGeneratedwould then printError writing output, delete the partial file and return the error. The caller'scatch returnswallows it, so the generator exits 0 with no file. So a release build ofvibee_genwould hide this crash rather than fix it: exit 0, no output, and the same false clean that main's gate gives a missing file.Two things this run did not settle:
specs/tri/long_context_system.vibeeprinted nopanic:line, only a stack frame (???:?:?: 0x1571064 in ??? (???)). So its abort is not a panic. Zig 0.16's segfault handler printsSegmentation fault at address 0x…and then aborts, which would fit. That is an inference.b937408cemakes the gate print such lines, so the next run will show which one it is.specs/tri/hdc_stream_classifier.vibeedid not abort in this run. That is expected at 3 in 60.A correction to the gate's own output: it said
no filefor all 18. The probe found an empty file for those 18.b937408cereportsempty fileandno fileseparately.🤖 Generated with Claude Code
gHashTag commentedon Oct 4, 2026
The Zig-path abort is a segfault
#886's tool at
b937408cenow names crash-handler lines as well aspanic:lines. Its codegen run 37244594555 shows:So
long_context_system(languagezig) does not panic. It takes a segfault, and Zig's handler then aborts, which is why the exit is signal 6. It leaves no file.The 18 Verilog specs in the same run read
signal 6, empty file, … panic: programmer bug caused syscall error: FAULT, matching the comment above.Not known: where the segfault happens. The handler printed no symbolised frame. Finding it needs a debug build with symbols, or a run under a debugger.
hdc_stream_classifierdid not abort in any of #886's 4 codegen runs, so its 3-in-60 rate from the probe has no new data.🤖 Generated with Claude Code