Fuzz (nightly exploratory) #47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Fuzz (nightly exploratory) | |
| # Exploratory libFuzzer run, NOT a PR gate. Each int8 kernel harness mutates | |
| # for MAX_TIME seconds under ASan+UBSan. A new crash uploads the minimized | |
| # reproducer as an artifact; triage then archives it into fuzz/corpus/<kernel>/ | |
| # so the deterministic fuzz-replay gate (analysis.yml) guards the fix forever. | |
| # | |
| # Targets run as a matrix so wall-clock is one harness, not the sum. | |
| # | |
| # The working corpus accumulates across nights via actions/cache: each run | |
| # restores the previous night's corpus (falling back to the committed seeds on | |
| # a cache miss) and saves the grown corpus afterwards -- including on crash | |
| # nights, so the input that reached the crash is not lost. Without this, every | |
| # night re-derives the same shallow coverage from the committed seeds inside | |
| # its MAX_TIME budget instead of pushing the frontier deeper. The cache is | |
| # runner-side state only: the PR replay gate replays just the *committed* | |
| # corpus and never sees it. Periodically fold the accumulated corpus back into | |
| # fuzz/corpus/ with `./fuzz_<kernel> -merge=1 corpus/<kernel> <accumulated>` | |
| # and commit, so the replay gate inherits the coverage. Deleting the cache key | |
| # is always safe -- it regrows from the committed seeds. | |
| on: | |
| schedule: | |
| - cron: "0 5 * * *" # 05:00 UTC daily | |
| workflow_dispatch: | |
| inputs: | |
| max_time: | |
| description: "Seconds per target" | |
| default: "300" | |
| permissions: | |
| contents: read | |
| jobs: | |
| fuzz: | |
| name: Fuzz ${{ matrix.target }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: [fuzz_qlayernorm, fuzz_qsoftmax, fuzz_qfft1d, fuzz_requantize, | |
| fuzz_qattention_softmax, fuzz_qmha, fuzz_qlstm, fuzz_qgru, | |
| fuzz_qcfc, fuzz_simd_avx2_diff] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - name: Install Clang | |
| uses: ./.github/actions/apt-install | |
| with: | |
| packages: clang | |
| - name: Derive kernel name | |
| id: kernel | |
| run: | | |
| k="${{ matrix.target }}" | |
| echo "kernel=${k#fuzz_}" >> "$GITHUB_OUTPUT" | |
| # Key is unique per run so the post-run save never collides; restore | |
| # falls back to the newest previous night via the prefix restore-key. | |
| # The restore overlays the checked-out committed seeds, so a cache miss | |
| # just means starting from the seeds alone. | |
| - name: Restore accumulated corpus | |
| uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: fuzz/corpus/${{ steps.kernel.outputs.kernel }} | |
| key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} | |
| restore-keys: | | |
| fuzz-corpus-${{ matrix.target }}- | |
| - name: Build ${{ matrix.target }} | |
| run: make -C fuzz ${{ matrix.target }} FUZZ_CXX=clang++ | |
| - name: Fuzz ${{ matrix.target }} (time-boxed, ASan+UBSan) | |
| run: | | |
| cd fuzz | |
| k="${{ steps.kernel.outputs.kernel }}" | |
| mkdir -p "corpus/$k" | |
| ./${{ matrix.target }} -max_total_time="${{ github.event.inputs.max_time || 300 }}" \ | |
| -print_final_stats=1 "corpus/$k" | |
| # if: always() -- a crash night must still save the grown corpus; the | |
| # units leading up to the crash are the most valuable ones. | |
| - name: Save accumulated corpus | |
| if: always() | |
| uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: fuzz/corpus/${{ steps.kernel.outputs.kernel }} | |
| key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} | |
| - name: Upload crash reproducers | |
| if: failure() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: crash-${{ matrix.target }} | |
| path: | | |
| fuzz/crash-* | |
| fuzz/timeout-* | |
| fuzz/leak-* | |
| fuzz/oom-* | |
| if-no-files-found: ignore |