mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
implement std.testing.fuzzInput
For now this returns a dummy fuzz input.
This commit is contained in:
parent
3256df2ff8
commit
6f3767862d
4 changed files with 125 additions and 53 deletions
|
|
@ -1,18 +1,26 @@
|
|||
//! Default test runner for unit tests.
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const io = std.io;
|
||||
const builtin = @import("builtin");
|
||||
const testing = std.testing;
|
||||
|
||||
pub const std_options = .{
|
||||
.logFn = log,
|
||||
};
|
||||
|
||||
var log_err_count: usize = 0;
|
||||
var cmdline_buffer: [4096]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
|
||||
var fba_buffer: [8192]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
|
||||
|
||||
const crippled = switch (builtin.zig_backend) {
|
||||
.stage2_riscv64 => true,
|
||||
else => false,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
@disableInstrumentation();
|
||||
|
||||
if (crippled) {
|
||||
return mainSimple() catch @panic("test failure\n");
|
||||
}
|
||||
|
||||
|
|
@ -25,13 +33,15 @@ pub fn main() void {
|
|||
if (std.mem.eql(u8, arg, "--listen=-")) {
|
||||
listen = true;
|
||||
} else if (std.mem.startsWith(u8, arg, "--seed=")) {
|
||||
std.testing.random_seed = std.fmt.parseUnsigned(u32, arg["--seed=".len..], 0) catch
|
||||
testing.random_seed = std.fmt.parseUnsigned(u32, arg["--seed=".len..], 0) catch
|
||||
@panic("unable to parse --seed command line argument");
|
||||
} else {
|
||||
@panic("unrecognized command line argument");
|
||||
}
|
||||
}
|
||||
|
||||
fba.reset();
|
||||
|
||||
if (listen) {
|
||||
return mainServer() catch @panic("internal test runner failure");
|
||||
} else {
|
||||
|
|
@ -40,6 +50,7 @@ pub fn main() void {
|
|||
}
|
||||
|
||||
fn mainServer() !void {
|
||||
@disableInstrumentation();
|
||||
var server = try std.zig.Server.init(.{
|
||||
.gpa = fba.allocator(),
|
||||
.in = std.io.getStdIn(),
|
||||
|
|
@ -55,24 +66,24 @@ fn mainServer() !void {
|
|||
return std.process.exit(0);
|
||||
},
|
||||
.query_test_metadata => {
|
||||
std.testing.allocator_instance = .{};
|
||||
defer if (std.testing.allocator_instance.deinit() == .leak) {
|
||||
testing.allocator_instance = .{};
|
||||
defer if (testing.allocator_instance.deinit() == .leak) {
|
||||
@panic("internal test runner memory leak");
|
||||
};
|
||||
|
||||
var string_bytes: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer string_bytes.deinit(std.testing.allocator);
|
||||
try string_bytes.append(std.testing.allocator, 0); // Reserve 0 for null.
|
||||
defer string_bytes.deinit(testing.allocator);
|
||||
try string_bytes.append(testing.allocator, 0); // Reserve 0 for null.
|
||||
|
||||
const test_fns = builtin.test_functions;
|
||||
const names = try std.testing.allocator.alloc(u32, test_fns.len);
|
||||
defer std.testing.allocator.free(names);
|
||||
const expected_panic_msgs = try std.testing.allocator.alloc(u32, test_fns.len);
|
||||
defer std.testing.allocator.free(expected_panic_msgs);
|
||||
const names = try testing.allocator.alloc(u32, test_fns.len);
|
||||
defer testing.allocator.free(names);
|
||||
const expected_panic_msgs = try testing.allocator.alloc(u32, test_fns.len);
|
||||
defer testing.allocator.free(expected_panic_msgs);
|
||||
|
||||
for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {
|
||||
name.* = @as(u32, @intCast(string_bytes.items.len));
|
||||
try string_bytes.ensureUnusedCapacity(std.testing.allocator, test_fn.name.len + 1);
|
||||
try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1);
|
||||
string_bytes.appendSliceAssumeCapacity(test_fn.name);
|
||||
string_bytes.appendAssumeCapacity(0);
|
||||
expected_panic_msg.* = 0;
|
||||
|
|
@ -86,13 +97,13 @@ fn mainServer() !void {
|
|||
},
|
||||
|
||||
.run_test => {
|
||||
std.testing.allocator_instance = .{};
|
||||
testing.allocator_instance = .{};
|
||||
log_err_count = 0;
|
||||
const index = try server.receiveBody_u32();
|
||||
const test_fn = builtin.test_functions[index];
|
||||
var fail = false;
|
||||
var skip = false;
|
||||
var leak = false;
|
||||
is_fuzz_test = false;
|
||||
test_fn.func() catch |err| switch (err) {
|
||||
error.SkipZigTest => skip = true,
|
||||
else => {
|
||||
|
|
@ -102,13 +113,14 @@ fn mainServer() !void {
|
|||
}
|
||||
},
|
||||
};
|
||||
leak = std.testing.allocator_instance.deinit() == .leak;
|
||||
const leak = testing.allocator_instance.deinit() == .leak;
|
||||
try server.serveTestResults(.{
|
||||
.index = index,
|
||||
.flags = .{
|
||||
.fail = fail,
|
||||
.skip = skip,
|
||||
.leak = leak,
|
||||
.fuzz = is_fuzz_test,
|
||||
.log_err_count = std.math.lossyCast(
|
||||
@TypeOf(@as(std.zig.Server.Message.TestResults.Flags, undefined).log_err_count),
|
||||
log_err_count,
|
||||
|
|
@ -118,7 +130,7 @@ fn mainServer() !void {
|
|||
},
|
||||
|
||||
else => {
|
||||
std.debug.print("unsupported message: {x}", .{@intFromEnum(hdr.tag)});
|
||||
std.debug.print("unsupported message: {x}\n", .{@intFromEnum(hdr.tag)});
|
||||
std.process.exit(1);
|
||||
},
|
||||
}
|
||||
|
|
@ -126,6 +138,7 @@ fn mainServer() !void {
|
|||
}
|
||||
|
||||
fn mainTerminal() void {
|
||||
@disableInstrumentation();
|
||||
const test_fn_list = builtin.test_functions;
|
||||
var ok_count: usize = 0;
|
||||
var skip_count: usize = 0;
|
||||
|
|
@ -143,18 +156,19 @@ fn mainTerminal() void {
|
|||
|
||||
var leaks: usize = 0;
|
||||
for (test_fn_list, 0..) |test_fn, i| {
|
||||
std.testing.allocator_instance = .{};
|
||||
testing.allocator_instance = .{};
|
||||
defer {
|
||||
if (std.testing.allocator_instance.deinit() == .leak) {
|
||||
if (testing.allocator_instance.deinit() == .leak) {
|
||||
leaks += 1;
|
||||
}
|
||||
}
|
||||
std.testing.log_level = .warn;
|
||||
testing.log_level = .warn;
|
||||
|
||||
const test_node = root_node.start(test_fn.name, 0);
|
||||
if (!have_tty) {
|
||||
std.debug.print("{d}/{d} {s}...", .{ i + 1, test_fn_list.len, test_fn.name });
|
||||
}
|
||||
// Track in a global variable so that `fuzzInput` can see it.
|
||||
if (test_fn.func()) |_| {
|
||||
ok_count += 1;
|
||||
test_node.end();
|
||||
|
|
@ -208,10 +222,11 @@ pub fn log(
|
|||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
@disableInstrumentation();
|
||||
if (@intFromEnum(message_level) <= @intFromEnum(std.log.Level.err)) {
|
||||
log_err_count +|= 1;
|
||||
}
|
||||
if (@intFromEnum(message_level) <= @intFromEnum(std.testing.log_level)) {
|
||||
if (@intFromEnum(message_level) <= @intFromEnum(testing.log_level)) {
|
||||
std.debug.print(
|
||||
"[" ++ @tagName(scope) ++ "] (" ++ @tagName(message_level) ++ "): " ++ format ++ "\n",
|
||||
args,
|
||||
|
|
@ -222,6 +237,7 @@ pub fn log(
|
|||
/// Simpler main(), exercising fewer language features, so that
|
||||
/// work-in-progress backends can handle it.
|
||||
pub fn mainSimple() anyerror!void {
|
||||
@disableInstrumentation();
|
||||
// is the backend capable of printing to stderr?
|
||||
const enable_print = switch (builtin.zig_backend) {
|
||||
else => false,
|
||||
|
|
@ -266,3 +282,34 @@ pub fn mainSimple() anyerror!void {
|
|||
}
|
||||
if (failed != 0) std.process.exit(1);
|
||||
}
|
||||
|
||||
const FuzzerSlice = extern struct {
|
||||
ptr: [*]const u8,
|
||||
len: usize,
|
||||
|
||||
inline fn toSlice(s: FuzzerSlice) []const u8 {
|
||||
return s.ptr[0..s.len];
|
||||
}
|
||||
};
|
||||
|
||||
var is_fuzz_test: bool = undefined;
|
||||
|
||||
extern fn fuzzer_next() FuzzerSlice;
|
||||
|
||||
pub fn fuzzInput(options: testing.FuzzInputOptions) []const u8 {
|
||||
@disableInstrumentation();
|
||||
if (crippled) {
|
||||
return "";
|
||||
} else if (builtin.fuzz) {
|
||||
return fuzzer_next().toSlice();
|
||||
} else {
|
||||
is_fuzz_test = true;
|
||||
if (options.corpus.len == 0) {
|
||||
return "";
|
||||
} else {
|
||||
var prng = std.Random.DefaultPrng.init(testing.random_seed);
|
||||
const random = prng.random();
|
||||
return options.corpus[random.uintLessThan(usize, options.corpus.len)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
export threadlocal var __sancov_lowest_stack: usize = 0;
|
||||
|
||||
export fn __sanitizer_cov_8bit_counters_init(start: [*]u8, stop: [*]u8) void {
|
||||
std.debug.print("__sanitizer_cov_8bit_counters_init start={*}, stop={*}\n", .{ start, stop });
|
||||
std.log.debug("__sanitizer_cov_8bit_counters_init start={*}, stop={*}", .{ start, stop });
|
||||
}
|
||||
|
||||
export fn __sanitizer_cov_pcs_init(pcs_beg: [*]const usize, pcs_end: [*]const usize) void {
|
||||
std.debug.print("__sanitizer_cov_pcs_init pcs_beg={*}, pcs_end={*}\n", .{ pcs_beg, pcs_end });
|
||||
std.log.debug("__sanitizer_cov_pcs_init pcs_beg={*}, pcs_end={*}", .{ pcs_beg, pcs_end });
|
||||
}
|
||||
|
||||
export fn __sanitizer_cov_trace_const_cmp1(arg1: u8, arg2: u8) void {
|
||||
|
|
@ -47,16 +48,61 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases_ptr: [*]u64) void {
|
|||
const len = cases_ptr[0];
|
||||
const val_size_in_bits = cases_ptr[1];
|
||||
const cases = cases_ptr[2..][0..len];
|
||||
std.debug.print("0x{x}: switch on value {d} ({d} bits) with {d} cases\n", .{
|
||||
std.log.debug("0x{x}: switch on value {d} ({d} bits) with {d} cases", .{
|
||||
pc, val, val_size_in_bits, cases.len,
|
||||
});
|
||||
}
|
||||
|
||||
export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {
|
||||
const pc = @returnAddress();
|
||||
std.debug.print("0x{x}: indirect call to 0x{x}\n", .{ pc, callee });
|
||||
std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });
|
||||
}
|
||||
|
||||
fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {
|
||||
std.debug.print("0x{x}: comparison of {d} and {d}\n", .{ pc, arg1, arg2 });
|
||||
std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 });
|
||||
}
|
||||
|
||||
const Fuzzer = struct {
|
||||
gpa: Allocator,
|
||||
rng: std.Random.DefaultPrng,
|
||||
input: std.ArrayListUnmanaged(u8),
|
||||
|
||||
const Slice = extern struct {
|
||||
ptr: [*]const u8,
|
||||
len: usize,
|
||||
|
||||
fn toSlice(s: Slice) []const u8 {
|
||||
return s.ptr[0..s.len];
|
||||
}
|
||||
|
||||
fn fromSlice(s: []const u8) Slice {
|
||||
return .{
|
||||
.ptr = s.ptr,
|
||||
.len = s.len,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
fn next(f: *Fuzzer) ![]const u8 {
|
||||
const gpa = f.gpa;
|
||||
const rng = fuzzer.rng.random();
|
||||
const len = rng.uintLessThan(usize, 64);
|
||||
try f.input.resize(gpa, len);
|
||||
rng.bytes(f.input.items);
|
||||
return f.input.items;
|
||||
}
|
||||
};
|
||||
|
||||
var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
|
||||
|
||||
var fuzzer: Fuzzer = .{
|
||||
.gpa = general_purpose_allocator.allocator(),
|
||||
.rng = std.Random.DefaultPrng.init(0),
|
||||
.input = .{},
|
||||
};
|
||||
|
||||
export fn fuzzer_next() Fuzzer.Slice {
|
||||
return Fuzzer.Slice.fromSlice(fuzzer.next() catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("out of memory"),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1137,32 +1137,10 @@ pub fn refAllDeclsRecursive(comptime T: type) void {
|
|||
}
|
||||
}
|
||||
|
||||
const FuzzerSlice = extern struct {
|
||||
ptr: [*]const u8,
|
||||
len: usize,
|
||||
|
||||
fn toSlice(s: FuzzerSlice) []const u8 {
|
||||
return s.ptr[0..s.len];
|
||||
}
|
||||
};
|
||||
|
||||
extern fn fuzzer_next() FuzzerSlice;
|
||||
|
||||
pub const FuzzInputOptions = struct {
|
||||
corpus: []const []const u8 = &.{},
|
||||
};
|
||||
|
||||
pub fn fuzzInput(options: FuzzInputOptions) []const u8 {
|
||||
@disableInstrumentation();
|
||||
if (builtin.fuzz) {
|
||||
return fuzzer_next().toSlice();
|
||||
} else {
|
||||
if (options.corpus.len == 0) {
|
||||
return "";
|
||||
} else {
|
||||
var prng = std.Random.DefaultPrng.init(std.testing.random_seed);
|
||||
const random = prng.random();
|
||||
return options.corpus[random.uintLessThan(usize, options.corpus.len)];
|
||||
}
|
||||
}
|
||||
pub inline fn fuzzInput(options: FuzzInputOptions) []const u8 {
|
||||
return @import("root").fuzzInput(options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub const Message = struct {
|
|||
/// - null-terminated string_bytes index
|
||||
/// * expected_panic_msg: [tests_len]u32,
|
||||
/// - null-terminated string_bytes index
|
||||
/// - 0 means does not expect pani
|
||||
/// - 0 means does not expect panic
|
||||
/// * string_bytes: [string_bytes_len]u8,
|
||||
pub const TestMetadata = extern struct {
|
||||
string_bytes_len: u32,
|
||||
|
|
@ -68,7 +68,8 @@ pub const Message = struct {
|
|||
fail: bool,
|
||||
skip: bool,
|
||||
leak: bool,
|
||||
log_err_count: u29 = 0,
|
||||
fuzz: bool,
|
||||
log_err_count: u28 = 0,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue