80 Commits

Author SHA1 Message Date
Ryan Liptak 3252a05531 Prefer <err> => |e| return e over <err> => return <err>
Avoids the potential for a typo on the `return <err>` side of the prong
2026-04-20 18:03:14 -07:00
Mason Remaley 5984d5dbde Fixes compiler error in fuzz tester due to stack trace and error trace separation 2026-04-15 22:52:57 +02:00
Mason Remaley 87fb7df257 Updates stack trace vs error return trace in more places 2026-04-12 04:01:30 -07:00
Kendall Condon d8ba173e5e multiprocess fuzzing
- New Features

-- Multiprocess Fuzzing

The fuzzer now is able to utilize multiple cores. This is controllable
with the `-j` build option. Limited fuzzing still uses one core.

-- Fuzzing Infinite Mode

When provided multiple tests, the fuzzer now switches between them and
prioritizes the most effective and interesting ones. Over time already
explored tests will become barely run compared to tests yielding new
inputs.

-- Crash Dumps

Crashing inputs are now saved to a file indicated by the crash message.
It is recommended to use these files to reproduce the crash using
`std.testing.FuzzInputOptions.corpus` and @embedFile.

- Design

Each fuzzing process is assigned an instance id which has the following
uses:
* In conjunction with the pc hash and running test index, they uniquely
  identify input files in the case of a crash.
* It is combined with the test seed for a unique rng seed.
* Instance 0 is solely responsible for syncing the filesystem corpus.

When new inputs are found, they are sent to the build server. It then
distributes the new input to the other instances. Each instance has a
concurrent poller managed by the test runner which sends received
inputs to libfuzzer. (note that this is affected by #31718 and so can
(rarely) deadlock)

For fuzzing infinite mode, the test runner now receives a list of tests
from the build server. The fuzzer runs tests in batches of one second,
approximated in cycles by the previous batch's run speed. Tests finding
new inputs or with few runs are given a higher run chance. The baseline
run chance is based off the recency of the last find and the number of
pcs the test has hit.
2026-04-03 12:27:34 +02:00
Kendall Condon 5ecef2934a rerun fuzz tests from name instead of index
The indexes can change between recompilation due to conditional
compilation and compiler quirks. While unit test names are still not a
perfect solution, they are better than indexes.
2026-03-11 21:19:22 -04:00
Kendall Condon c3e6ff7206 libfuzzer: use error.SkipZigTest 2026-03-11 21:14:46 -04:00
Alex Rønne Petersen 502cab9ae3 test_runner: actually print the error that caused a runner failure
part of the Stop Throwing Away Useful Information initiative
2026-03-10 11:28:36 +00:00
Andrew Kelley 80625990d5 std: different mechanism for disabling network dependency
On Windows, it is sometimes problematic to depend on ws2_32.dll. Before,
users of std.Io.Threaded would have to call ioBasic() rather than io()
in order to avoid unnecessary dependencies on ws2_32.dll. Now, the
application can disable networking with std.Options.

This change is necessary due to moving networking functionality to
be based on Io.Operation, which is a tagged union.
2026-03-08 19:20:34 -07:00
Kendall Condon 5d58306162 rework fuzz testing to be smith based
-- On the standard library side:

The `input: []const u8` parameter of functions passed to `testing.fuzz`
has changed to `smith: *testing.Smith`. `Smith` is used to generate
values from libfuzzer or input bytes generated by libfuzzer.

`Smith` contains the following base methods:
* `value` as a generic method for generating any type
* `eos` for generating end-of-stream markers. Provides the additional
  guarantee `true` will eventually by provided.
* `bytes` for filling a byte array.
* `slice` for filling part of a buffer and providing the length.

`Smith.Weight` is used for giving value ranges a higher probability of
being selected. By default, every value has a weight of zero (i.e. they
will not be selected). Weights can only apply to values that fit within
a u64. The above functions have corresponding ones that accept weights.
Additionally, the following functions are provided:
* `baselineWeights` which provides a set of weights containing every
  possible value of a type.
* `eosSimpleWeighted` for unique weights for `true` and `false`
* `valueRangeAtMost` and `valueRangeLessThan` for weighing only a range
  of values.

-- On the libfuzzer and abi side:

--- Uids

These are u32s which are used to classify requested values. This solves
the problem of a mutation causing a new value to be requested and
shifting all future values; for example:

1. An initial input contains the values 1, 2, 3 which are interpreted
as a, b, and c respectively by the test.

2. The 1 is mutated to a 4 which causes the test to request an extra
value interpreted as d. The input is now 4, 2, 3, 5 (new value) which
the test corresponds to a, d, b, c; however, b and c no longer
correspond to their original values.

Uids contain a hash component and type component. The hash component
is currently determined in `Smith` by taking a hash of the calling
`@returnAddress()` or via an argument in the corresponding `WithHash`
functions. The type component is used extensively in libfuzzer with its
hashmaps.

--- Mutations

At the start of a cycle (a run), a random number of values to mutate is
selected with less being exponentially more likely. The indexes of the
values are selected from a selected uid with a logarithmic bias to uids
with more values.

Mutations may change a single values, several consecutive values in a
uid, or several consecutive values in the uid-independent order they
were requested. They may generate random values, mutate from previous
ones, or copy from other values in the same uid from the same input or
spliced from another.

For integers, mutations from previous ones currently only generates
random values. For bytes, mutations from previous mix new random data
and previous bytes with a set number of mutations.

--- Passive Minimization

A different approach has been taken for minimizing inputs: instead of
trying a fixed set of mutations when a fresh input is found, the input
is instead simply added to the corpus and removed when it is no longer
valuable.

The quality of an input is measured based off how many unique pcs it
hit and how many values it needed from the fuzzer. It is tracked which
inputs hold the best qualities for each pc for hitting the minimum and
maximum unique pcs while needing the least values.

Once all an input's qualities have been superseded for the pcs it hit,
it is removed from the corpus.

-- Comparison to byte-based smith

A byte-based smith would be much more inefficient and complex than this
solution. It would be unable to solve the shifting problem that Uids
do. It is unable to provide values from the fuzzer past end-of-stream.
Even with feedback, it would be unable to act on dynamic weights which
have proven essential with the updated tests (e.g. to constrain values
to a range).

-- Test updates

All the standard library tests have been updated to use the new smith
interface. For `Deque`, an ad hoc allocator was written to improve
performance and remove reliance on heap allocation. `TokenSmith` has
been added to aid in testing Ast and help inform decisions on the smith
interface.
2026-02-13 22:12:19 -05:00
murtaza b5770541bd testing: ability to read environment variables from unit tests 2026-01-17 00:40:22 +01:00
Andrew Kelley 08447ca47e std.fs.path: make relative a pure function
Instead of querying the operating system for current working directory
and environment variables, this function now accepts those things as
inputs.
2026-01-04 00:27:08 -08:00
Andrew Kelley 9009ab2495 std.Io.Threaded: make environ init non-optional
and argv0 on systems that need it too.

fixes surprising behavior for applications that forget to initialize the
environment field.
2026-01-04 00:27:08 -08:00
Andrew Kelley 3e6d6150d9 std.process.Environ: fix compile errors on POSIX 2026-01-04 00:27:08 -08:00
PeterMcKinnis 96ba0ab930 fix lockStderr API calls in test_runner fuzz code 2025-12-30 15:09:17 -05:00
Michael Dusan 1ea2d5692d openbsd: init Io.Threaded.argv0 for tests
Some tests (eg. std.process.openExecutable) require argv0 for OpenBSD,
otherwise error.OperationUnsupported is encountered.
2025-12-29 21:06:08 -05:00
Andrew Kelley b0691df5ba test_runner: fix simple runner compilation 2025-12-26 19:58:56 -08:00
Andrew Kelley a29d79313a std.Io.Threaded: accept argv and environ on init
This is needed unfortunately for OpenBSD and Haiku for process
executable path.

I made it so that you can omit the options usually, but you get a
compile error if you omit the options on those targets.
2025-12-23 22:15:12 -08:00
Andrew Kelley 77d2ad8c92 std: consolidate all instances of std.Io.Threaded into a singleton
It's better to avoid references to this global variable, but, in the
cases where it's needed, such as in std.debug.print and collecting stack
traces, better to share the same instance.
2025-12-23 22:15:11 -08:00
Andrew Kelley 54865e0483 compiler: fix compilation when linking libc 2025-12-23 22:15:10 -08:00
Andrew Kelley 608145c2f0 fix more fallout from locking stderr 2025-12-23 22:15:10 -08:00
Andrew Kelley 1925e0319f update lockStderrWriter sites
use the application's Io implementation where possible. This correctly
makes writing to stderr cancelable, fallible, and participate in the
application's event loop. It also removes one more hard-coded
dependency on a secondary Io implementation.
2025-12-23 22:15:09 -08:00
Andrew Kelley e68ae8d7a1 update uses of std.debug.lockStdErr 2025-12-23 22:15:09 -08:00
Andrew Kelley 03526c59d4 std.debug: fix printLineFromFile 2025-12-23 22:15:09 -08:00
Andrew Kelley 3204fb7569 update all occurrences of std.fs.File to std.Io.File 2025-12-23 22:15:07 -08:00
Ali Cheraghi dec1163fbb all: replace all @Type usages
Co-authored-by: Matthew Lugg <mlugg@mlugg.co.uk>
2025-11-22 22:42:38 +00:00
Benjamin Jurk 4b5351bc0d update deprecated ArrayListUnmanaged usage (#25958) 2025-11-20 14:46:23 -08:00
Matthew Lugg 010dcd6a9b fuzzer: account for runtime address slide
This is relevant to PIEs, which are notably enabled by default on macOS.
The build system needs to only see virtual addresses, that is, those
which do not have the slide applied; but the fuzzer itself naturally
sees relocated addresses (i.e. with the slide applied). We just need to
subtract the slide when we communicate addresses to the build system.
2025-11-20 10:42:20 +00:00
Andrew Kelley aadd8d4a3e std: back out the StackTrace byval changes
Let's keep passing this thing by pointer
2025-10-29 06:20:50 -07:00
Andrew Kelley 10b1eef2d3 std: fix compilation errors on Windows 2025-10-29 06:20:50 -07:00
Andrew Kelley 47aa5a70a5 std: updating to std.Io interface
got the build runner compiling
2025-10-29 06:20:48 -07:00
Andrew Kelley d801a71d29 add std.testing.io 2025-10-29 06:20:48 -07:00
mlugg d0b92a8022 std.Build: do not expect server protocol for tests using immature backends
For instance, when running a Zig test using the self-hosted aarch64
backend, this logic was previously expecting `std.zig.Server` to be
used, but the default test runner intentionally does not do this because
the backend is too immature to handle it. On 'master', this is causing
sporadic failures; on this branch, they became consistent failures.
2025-10-18 09:28:42 +01:00
mlugg e4456d03f3 std.Build.Step.Run: many enhancements
This is a major refactor to `Step.Run` which adds new functionality,
primarily to the execution of Zig tests.

* All tests are run, even if a test crashes. This happens through the
  same mechanism as timeouts where the test processes is repeatedly
  respawned as needed.
* The build status output is more precise. For each unit test, it
  differentiates pass, skip, fail, crash, and timeout. Memory leaks are
  reported separately, as they do not indicate a test's "status", but
  are rather an additional property (a test with leaks may still pass!).
* The number of memory leaks is tracked and reported, both per-test and
  for a whole `Run` step.
* Reporting is made clearer when a step is failed solely due to error
  logs (`std.log.err`) where every unit test passed.
2025-10-18 09:28:41 +01:00
mlugg 7e7d7875b9 std.Build: implement unit test timeouts
For now, there is a flag to `zig build` called `--test-timeout-ms` which
accepts a value in milliseconds. If the execution time of any individual
unit test exceeds that number of milliseconds, the test is terminated
and marked as timed out.

In the future, we may want to increase the granularity of this feature
by allowing timeouts to be specified per-step or even per-test. However,
a global option is actually very useful. In particular, it can be used
in CI scripts to ensure that no individual unit test exceeds some
reasonable limit (e.g. 60 seconds) without having to assign limits to
every individual test step in the build script.

Also, individual unit test durations are now shown in the time report
web interface -- this was fairly trivial to add since we're timing tests
(to check for timeouts) anyway.

This commit makes progress on #19821, but does not close it, because
that proposal includes a more sophisticated mechanism for setting
timeouts.

Co-Authored-By: David Rubin <david@vortan.dev>
2025-10-18 09:28:39 +01:00
mlugg 51d08f4b9b fix compile errors and minor bugs 2025-09-30 13:44:54 +01:00
Loris Cro 9bb0b43ea3 implement review suggestions 2025-09-25 18:20:19 +02:00
Loris Cro 0feacc2b81 fuzzing: implement limited fuzzing
Adds the limit option to `--fuzz=[limit]`. the limit expresses a number
of iterations that *each fuzz test* will perform at maximum before
exiting. The limit argument supports also 'K', 'M', and 'G' suffixeds
(e.g. '10K').

Does not imply `--web-ui` (like unlimited fuzzing does) and prints a
fuzzing report at the end.

Closes #22900 but does not implement the time based limit, as after
internal discussions we concluded to be problematic to both implement
and use correctly.
2025-09-24 12:46:48 +02:00
Kendall Condon e66b269333 greatly improve capabilities of the fuzzer
This PR significantly improves the capabilities of the fuzzer.

The changes made to the fuzzer to accomplish this feat mostly include
tracking memory reads from .rodata to determine fresh inputs, new
mutations (especially the ones that insert const values from .rodata
reads and __sanitizer_conv_const_cmp), and minimizing found inputs.
Additionally, the runs per second has greatly been increased due to
generating smaller inputs and avoiding clearing the 8-bit pc counters.

An additional feature added is that the length of the input file is now
stored and the old input file is rerun upon start.

Other changes made to the fuzzer include more logical initialization,
using one shared file `in` for inputs, creating corpus files with
proper sizes, and using hexadecimal-numbered corpus files for
simplicity.

Furthermore, I added several new fuzz tests to gauge the fuzzer's
efficiency. I also tried to add a test for zstandard decompression,
which it crashed within 60,000 runs (less than a second.)

Bug fixes include:
* Fixed a race conditions when multiple fuzzer processes needed to use
the same coverage file.
* Web interface stats now update even when unique runs is not changing.
* Fixed tokenizer.testPropertiesUpheld to allow stray carriage returns
since they are valid whitespace.
2025-09-18 18:56:10 -04:00
Jacob Young 5060ab99c9 aarch64: add new from scratch self-hosted backend 2025-07-22 19:43:47 -07:00
Andrew Kelley c40fb96ca3 std.Io.Writer: fix writeSliceSwap
tried to be too clever, wrote bad code
2025-07-19 22:12:37 -07:00
Andrew Kelley 93378e2e7b std.zig: finish updating to new I/O API 2025-07-19 19:57:37 -07:00
Andrew Kelley 0e37ff0d59 std.fmt: breaking API changes
added adapter to AnyWriter and GenericWriter to help bridge the gap
between old and new API

make std.testing.expectFmt work at compile-time

std.fmt no longer has a dependency on std.unicode. Formatted printing
was never properly unicode-aware. Now it no longer pretends to be.

Breakage/deprecations:
* std.fs.File.reader -> std.fs.File.deprecatedReader
* std.fs.File.writer -> std.fs.File.deprecatedWriter
* std.io.GenericReader -> std.io.Reader
* std.io.GenericWriter -> std.io.Writer
* std.io.AnyReader -> std.io.Reader
* std.io.AnyWriter -> std.io.Writer
* std.fmt.format -> std.fmt.deprecatedFormat
* std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape
* std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape
* std.fmt.fmtSliceHexLower -> {x}
* std.fmt.fmtSliceHexUpper -> {X}
* std.fmt.fmtIntSizeDec -> {B}
* std.fmt.fmtIntSizeBin -> {Bi}
* std.fmt.fmtDuration -> {D}
* std.fmt.fmtDurationSigned -> {D}
* {} -> {f} when there is a format method
* format method signature
  - anytype -> *std.io.Writer
  - inferred error set -> error{WriteFailed}
  - options -> (deleted)
* std.fmt.Formatted
  - now takes context type explicitly
  - no fmt string
2025-07-07 22:43:51 -07:00
Andrew Kelley 0b3f0124dc std.io: move getStdIn, getStdOut, getStdErr functions to fs.File
preparing to rearrange std.io namespace into an interface

how to upgrade:

std.io.getStdIn() -> std.fs.File.stdin()
std.io.getStdOut() -> std.fs.File.stdout()
std.io.getStdErr() -> std.fs.File.stderr()
2025-07-07 22:43:51 -07:00
Bingwu Zhang ff06de4c89 riscv64: enable test summary printing 2025-06-28 06:47:09 +08:00
Bingwu Zhang 5db395f20b compiler: test runner: fix tests never fails on crippled architectures 2025-06-27 19:12:16 +08:00
Alex Rønne Petersen 999777e73a compiler: Scaffold stage2_powerpc backend.
Nothing interesting here; literally just the bare minimum so I can work on this
on and off in a branch without worrying about merge conflicts in the non-backend
code.
2025-05-20 10:23:16 +02:00
Linus Groh 79460d4a3e Remove uses of deprecated callconv aliases 2025-03-05 03:01:43 +00:00
Ali Cheraghi 181a89e728 build: add spirv to test matrix
Signed-off-by: Ali Cheraghi <alichraghi@proton.me>
2025-02-24 19:12:38 +01:00
Andrew Kelley d789f1e5cf fuzzer: write inputs to shared memory before running
breaking change to the fuzz testing API; it now passes a type-safe
context parameter to the fuzz function.

libfuzzer is reworked to select inputs from the entire corpus.

I tested that it's roughly as good as it was before in that it can find
the panics in the simple examples, as well as achieve decent coverage on
the tokenizer fuzz test.

however I think the next step here will be figuring out why so many
points of interest are missing from the tokenizer in both Debug and
ReleaseSafe modes.

does not quite close #20803 yet since there are some more important
things to be done, such as opening the previous corpus, continuing
fuzzing after finding bugs, storing the length of the inputs, etc.
2025-02-11 13:39:20 -08:00
mlugg f83bb94ca6 test_runner: replace ugly hack with @FieldType 2024-11-11 09:05:51 +00:00