Home / Blog / Catch Go bugs that fuzzing misses with Gemini and a…
Tech News

Catch Go bugs that fuzzing misses with Gemini and a constraint solver

Google paired surviving Go compiler bounds checks with Gemini 4 Argon and the Z3 solver, uncovering latent runtime panics missed across 386,741 fuzz runs.

By Dillip Chowdary • Nov 14, 2026 • Source: Google Developers Blog

Catch Go bugs that fuzzing misses with Gemini and a constraint solver

In Google Developers Blog's report, Google Developer Relations director Karl Weinmeister detailed a verification method combining compiler bounds checks, Gemini 4 Argon, and the Z3 constraint solver to discover latent Go panics. The workflow analyzes assembly instructions after compiler optimization passes to target fragile slices, uncovering three seeded defects in test parsers and three latent bugs in the skill-lint CLI.

This teardown explains how the compilation pipeline extracts surviving bounds checks, how neural models formulate formal solver queries, and why standard fuzzing harnesses miss widespread out-of-bounds index panics. It serves systems developers, Go maintainers, and security engineers evaluating automated formal methods to harden high-throughput parsers and address slice allocation blind spots.

01Surviving compiler bounds checks and assembly

Go avoids memory corruption vulnerabilities by compiling slice and index operations into explicit runtime checks. When boundaries cannot be verified at compile time, the compiler inserts a branch targeting runtime.panicBounds. These safety traps trigger an immediate process panic whenever code accesses an out-of-bounds slice offset.

During compilation, Go's static single assignment prove pass removes checks it can guarantee are safe by tracking lengths and loop variables. Compiling with GOOS=linux GOARCH=riscv64 and flags -S and -d=ssa/check_bce/debug=1 outputs assembly while logging every surviving bounds check. This provides a focused list of potential crash sites.

Analyzing disassembly reveals low-level register behaviors such as eight-bit truncation that stay hidden in Go source code. Providing both source and disassembly to Gemini 4 Argon allows the model to map control paths to surviving traps. Argon generated solver rules in about a minute per function, while Z3 solved them in milliseconds.

02Constraint solver queries versus interactive proofs

Interactive theorem proving with tools like Rocq requires engineers to model machine semantics to prove binary safety under a 64 MB budget. In contrast, pairing Gemini 4 Argon with the Z3 constraint solver relies on satisfiability modulo theories to check individual functions. The workflow tests fresh 64-byte slices where capacity equals length.

Catch Go bugs that fuzzing misses with Gemini and a constraint solver
Illustration · Pexels

Z3 evaluates symbolic constraints to return sat for satisfiable crash conditions or unsat when no failing input exists. A sat answer provides concrete bytes that reliably trigger a runtime panic during standard go test runs. An unsat result acts like a Bloom filter, indicating plausible safety without guaranteeing complete formal correctness.

Testing three safe parsers confirmed the workflow avoids false alarms on clean code. The compiler prove pass eliminated every bounds check in a TOML key parser, while Z3 returned unsat on remaining traps in a header scanner and varint decoder. For full binary proofs, theorem-labs/oss-verify offers a deterministic Go 1.27 runtime overlay.

Advertisement

Tech Pulse Daily

Get tomorrow's pulse first

Join engineers who read Tech Pulse before stand-up. Free, weekday mornings.

03Byte truncation in frame parser assembly

Subtle integer wrapping often bypasses naive boundary checks in binary format decoders. In the experimental ParseTwoChunkFrame parser, logic reads header and body lengths from bytes two and three before validating total length. Because that calculation adds two uint8 values, the RISC-V assembly uses MOVBU, truncating the sum at 256.

While the validation guard checks the truncated sum plus four bytes, subsequent slicing operations calculate endBody using full 64-bit integers without masking. If buffer capacity is smaller than this unmasked index, execution branches to runtime.panicBounds. Argon converted these instructions into Z3 bit-vector queries targeting a 64-byte slice.

Z3 found a 59-byte counterexample with hdrLen set to 48 and bodyLen set to 236. Their uint8 sum wrapped from 284 to 28, allowing 28 plus 4 to pass the 59-byte guard. When the parser sliced buf[endHdr:endBody], it attempted to access index 288, triggering an immediate panic.

04Slice capacity blind spots during fuzzing

In the 59-byte frame parser, 19.4% of all possible header and body byte combinations trigger an out-of-bounds panic. Despite that high probability, unseeded go test -fuzz runs on Go 1.27.3 missed the bug across one 3-second run and three 60-second runs. Fresh fuzz caches confirmed that short testing times were not responsible.

This blind spot occurs because Go validates slice operations against buffer capacity rather than active slice length. Standard Go fuzzing rarely supplies slices that lack spare capacity. In a 10-second probe across 386,741 fuzz calls, 89% of generated inputs were sub-slices cut from a shared 100 MB buffer.

Only 0.07% of the tested fuzz inputs had capacity equal to length. Because endBody never exceeded 514, slicing operations never surpassed the surrounding 100 MB buffer capacity. The fuzzer read past the active slice length without triggering runtime.panicBounds, silently masking severe latent bugs that crash production systems under exact memory allocations.

05Practical static verification for developer workflows

Pairing constraint solvers with compiler trap analysis delivers immediate reliability benefits for developer tooling and agent systems. Karl Weinmeister maintains skill-lint to validate SKILL.md files and apply automated line edits across 175 agent skills in Google's catalog, supplementing go-skills. The solver pipeline identified three planted bugs in test parsers and uncovered three latent bugs inside skill-lint.

Unlike interactive theorem provers that require extensive semantic models, this automated method requires about one minute of LLM translation per function. Developers can flag unhandled bounds checks by enabling compiler diagnostic flags and passing the assembly to neural models. Generating concrete reproducer bytes guarantees that reported issues are verified directly by go test.

Engineering teams auditing network parsers should also review how their fuzzing harnesses allocate test slices. Ensuring that fuzz tests allocate buffers where capacity matches length prevents fuzzers from hiding bounds violations behind oversized backing arrays. Combining constrained fuzzing buffers with compiler-guided SMT solving offers an efficient defense against edge-case crashes in production Go services.

Catch Go bugs that fuzzing misses with Gemini FAQ

How does Gemini 4 Argon identify bounds-check bugs in Go code?

Gemini 4 Argon analyzes surviving runtime.panicBounds assembly traps left by Go's compiler and translates the control-flow paths into Z3 constraint solver rules. Z3 then solves for specific byte inputs that bypass slice guards and trigger runtime panics.

Why did go test -fuzz miss the out-of-bounds bug in ParseTwoChunkFrame?

Go evaluates slice expressions against capacity rather than length, and standard fuzzing harnesses allocate inputs from a shared 100 MB buffer. Because 89% of fuzz inputs had spare capacity and only 0.07% had capacity equal to length, out-of-bounds reads never exceeded buffer capacity to trigger panics.

Which tools and flags extract surviving bounds checks from Go programs?

Developers compile targets using GOOS=linux GOARCH=riscv64 go build with -gcflags="-S -d=ssa/check_bce/debug=1". This cross-compilation command prints the RISC-V disassembly and logs every bounds check that the compiler's SSA prove pass could not eliminate.

What real-world tools were tested using this solver pipeline?

The pipeline was tested on skill-lint, a Go CLI that checks SKILL.md files across 175 Google agent skills. It successfully caught all three planted parser bugs and uncovered three latent out-of-bounds bugs in skill-lint.

Sources

Dillip Chowdary

Author

Dillip Chowdary

Writes Tech Bytes coverage of AI, engineering, and the tools that actually ship. Editor of Tech Pulse Daily.

Related on Tech Bytes

Advertisement

5-min tech signal

Weekday briefing for engineers who skip the noise.

No spam · Unsubscribe anytime

Advertisement

✈️ CareerPilot

Your AI job-search copilot

Match your resume against live Ashby, Greenhouse & Lever openings — fit scores, job-specific resume optimization and email alerts.

Find matching jobs →

Free Tools

Browse all tools →