// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package rpc import ( "bytes" "testing" ) // FuzzReadRecord feeds arbitrary fragment streams into the reassembler: // no input may panic, allocate without bound or return anything but a // record, io.EOF, ErrRecordTooLarge or a truncation error. func FuzzReadRecord(f *testing.F) { f.Add([]byte{0x80, 0, 0, 4, 'a', 'b', 'c', 'd'}) f.Add([]byte{0, 0, 0, 4, 'a', 'b', 'c', 'd', 0x80, 0, 0, 0}) f.Add([]byte{0xff, 0xff, 0xff, 0xff}) f.Add([]byte{0, 0, 0, 1}) f.Fuzz(func(t *testing.T, data []byte) { rec, err := ReadRecord(bytes.NewReader(data), 1<<16) if err == nil && len(rec) > 1<<16 { t.Fatalf("a record of %d bytes against a limit of %d", len(rec), 1<<16) } }) } // FuzzDecodeMessage feeds arbitrary records through the call and reply // decoders: no input may panic, and every failure arrives as an error. func FuzzDecodeMessage(f *testing.F) { call, err := AppendCall(nil, Call{XID: 1, Program: 100003, Version: 4, Procedure: 1, Cred: Auth{Flavor: FlavorSys, Body: []byte{1, 2}}}) if err != nil { f.Fatal(err) } reply, err := AppendAcceptedReply(nil, 1, AuthNull, AcceptSuccess, Mismatch{}) if err != nil { f.Fatal(err) } reply = append(reply, 0, 0, 0, 42) f.Add(call) f.Add(reply) f.Add(AppendRejectedReply(nil, 2, AuthBadVerf)) f.Add([]byte{0, 0, 0, 1, 0, 0, 0, 1}) f.Add([]byte{0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2}) f.Fuzz(func(t *testing.T, data []byte) { // The property under test is that none of these panics; every // malformed input must arrive as an ordinary error. _, _, _ = DecodeCall(data) _, _ = DecodeReply(data) _, _, _ = PeekHeader(data) _, _ = DecodeAuthSysBody(data) _, _ = DecodeGSSCred(data) _, _, _, _, _, _ = DecodeGSSInitRes(data) }) }