[ 
https://issues.apache.org/jira/browse/THRIFT-6211?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jens Geyer resolved THRIFT-6211.
--------------------------------
    Fix Version/s: 0.25.0
         Assignee: Jens Geyer
       Resolution: Fixed

> Go: add native go test -fuzz targets and a committed seed corpus that runs in 
> CI
> --------------------------------------------------------------------------------
>
>                 Key: THRIFT-6211
>                 URL: https://issues.apache.org/jira/browse/THRIFT-6211
>             Project: Thrift
>          Issue Type: Improvement
>          Components: Go - Library
>            Reporter: Jens Geyer
>            Assignee: Jens Geyer
>            Priority: Minor
>             Fix For: 0.25.0
>
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> h2. Where Go fuzzing stands today
> {{lib/go/test/fuzz}} holds go-fuzz (dvyukov) style targets — {{func 
> FuzzX(data []byte) int}} behind the {{gofuzz}} build tag — which is what the 
> OSS-Fuzz build consumes. Nothing in this repository actually fuzzes them. 
> {{make -C lib/go check}} recurses into {{lib/go/test/fuzz}} and runs {{go 
> test -tags gofuzz}}, and the only test in that package is:
> {code}
> func TestFuzz(t *testing.T) {
>       FuzzTutorial([]byte{1, 2, 3})
> }
> {code}
> One call, one three-byte input. That is a compile check, and a useful one — 
> it catches build drift against the generated code — but it finds nothing.
> There is also no {{testdata/fuzz}} corpus anywhere in the tree. So when 
> OSS-Fuzz finds an input and it gets fixed, the input has nowhere to land in 
> this repository, and nothing replays it afterwards.
> h2. Proposal: add native Go fuzz targets alongside the existing ones
> Native fuzzing ({{func FuzzX(f *testing.F)}}) has been in the Go toolchain 
> since 1.18, and it buys one thing the current arrangement cannot:
> *{{go test}} without {{-fuzz}} replays every {{f.Add}} seed and every file 
> under {{testdata/fuzz/<Target>/}} as an ordinary unit test.*
> So a committed corpus becomes a regression suite that costs milliseconds, 
> needs no fuzzing infrastructure in CI, and runs on both Go versions in the 
> existing {{lib-go}} matrix. {{go test -fuzz=FuzzX -fuzztime=Nm}} then does 
> real fuzzing on demand or on a schedule.
> This is an addition, not a replacement — the go-fuzz targets stay as they are 
> and OSS-Fuzz keeps consuming them.
> Concretely:
> # *Library-only targets, no generated code.* The protocol and transport read 
> paths can be driven through {{ReadMessageBegin}} plus {{thrift.Skip}}, which 
> is what generated struct-read code amounts to: dispatch on the wire-supplied 
> type, read containers at wire-supplied sizes. Targets written that way need 
> nothing but {{lib/go/thrift}}, so they can live there as ordinary 
> {{*_test.go}} files and run in the existing CI job with no build-system 
> change and no compiler dependency.
> # *Generated-code targets.* Native equivalents of the existing struct and 
> round-trip targets in {{lib/go/test/fuzz}}, which do need {{gen-go}} and 
> therefore stay behind the current make wiring.
> # *A committed {{testdata/fuzz}} seed corpus*, so fixed inputs stay fixed. 
> This is the "add corpora" item from THRIFT-5855.
> # *Optionally a scheduled workflow* that runs {{-fuzz}} for a few minutes per 
> target, separate from the PR build. Or simply document the command in 
> FUZZING.md and leave scheduled fuzzing to OSS-Fuzz.
> h2. Coverage the current targets do not reach
> A sweep run while investigating THRIFT-6210 used twelve native targets of 
> exactly this shape, about 28 million executions against master @ 
> {{5c5e93e1e}}. It found no panic — the result is not the point here; what 
> matters is that the harness needed nothing except the library, and that it 
> reached code no existing target does:
> * TBinaryProtocol (strict and non-strict), TCompactProtocol, TJSONProtocol, 
> TSimpleJSONProtocol — through both the enveloped entry point and the 
> bare-struct one
> * THeaderProtocol, including client-type auto-detection, the transform-ID 
> list and info-header parsing — none of which any current target reaches
> * TFramedTransport
> * A full server-side dispatch hop through TMultiplexedProcessor, using a 
> hand-written processor rather than generated code
> * {{ParseTuuid}}
> The existing targets cover binary/compact/JSON deserialization and round-trip 
> of one generated struct. The header and framed transports, 
> TSimpleJSONProtocol, and the dispatch path are not covered at all today.
> h2. Notes
> FUZZING.md already states the intent: "To ensure fuzzing can find issues as 
> soon as possible, we will enable fuzzing support in CI once the fuzzers are 
> stable." This is a cheap way to get most of that for Go without running a 
> fuzzer in the PR path — the corpus replay is just {{go test}}.
> Related: THRIFT-5855 (fuzzing epic; "adding corpora" and testing the 
> networking code are both listed there), THRIFT-6210 (the investigation this 
> came out of).
> Investigation and this description were AI-assisted (Claude Opus 5); the 
> coverage claims were verified by execution against master.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to