//! The `std.testing.Smith` byte encoding, shared by every fuzz corpus. //! //! `Smith` does not consume a corpus entry as raw parser input. It reads a byte //! stream in which a slice is a little-endian `u32` length followed by that many //! bytes, and an integer is a little-endian `u64`. Every corpus entry in //! `tests/fuzz/` is therefore length-prefixed, and every fuzz file used to spell //! the same encoder out. //! //! This file imports nothing but `std` on purpose. The fuzz targets root //! separate modules over different parts of `src/` — `blocklist_fuzz.zig` cannot //! import `corpus.zig`, because `corpus.zig` needs the `dns` module that the //! blocklist target's build does not have. Each fuzz module reaches this file by //! relative path and compiles its own copy, so the dedup is at the source level; //! the self-tests below run once per fuzz artifact. const std = @import("std"); /// Encodes `bytes` as a single `Smith.slice` value. pub fn sliceInput(comptime bytes: []const u8) *const [4 + bytes.len]u8 { return &struct { const value: [4 + bytes.len]u8 = blk: { var buf: [4 + bytes.len]u8 = undefined; std.mem.writeInt(u32, buf[0..4], @intCast(bytes.len), .little); buf[4..].* = bytes[0..bytes.len].*; break :blk buf; }; }.value; } /// Encodes two `Smith.slice` values back to back, which is what a target that /// reads two entities takes: the pattern and the domain, or the query string and /// the key. pub fn pairInput(comptime a: []const u8, comptime b: []const u8) *const [8 + a.len + b.len]u8 { return &struct { const value: [8 + a.len + b.len]u8 = blk: { var buf: [8 + a.len + b.len]u8 = undefined; buf[0 .. 4 + a.len].* = sliceInput(a).*; buf[4 + a.len ..].* = sliceInput(b).*; break :blk buf; }; }.value; } test "a slice input carries its own length" { const encoded = sliceInput("ads.example.com"); try std.testing.expectEqual( @as(u32, "ads.example.com".len), std.mem.readInt(u32, encoded[0..4], .little), ); try std.testing.expectEqualSlices(u8, "ads.example.com", encoded[4..]); } test "a paired input carries both lengths" { const encoded = pairInput("*.a.b", "x.a.b"); try std.testing.expectEqual(@as(u32, 5), std.mem.readInt(u32, encoded[0..4], .little)); try std.testing.expectEqualSlices(u8, "*.a.b", encoded[4..9]); try std.testing.expectEqual(@as(u32, 5), std.mem.readInt(u32, encoded[9..13], .little)); try std.testing.expectEqualSlices(u8, "x.a.b", encoded[13..]); } test "an empty slice input is four bytes of zero" { const encoded = sliceInput(""); try std.testing.expectEqualSlices(u8, &.{ 0, 0, 0, 0 }, encoded); }