Skip to content

Assertion failure in scheduleCorpusImport with --jobs>=2 #551

@monsterd0n

Description

@monsterd0n

Summary

Using --jobs=2 (or higher) with the v8Sandbox profile causes a crash due to an assertion failure at Fuzzer.swift:703:

assert(state == .uninitialized)

The child worker calls scheduleCorpusImport after the main fuzzer has already transitioned from .uninitialized to .corpusGeneration, violating the precondition.

Steps to Reproduce

FuzzilliCli   --profile=v8Sandbox   --storagePath=/opt/v8-fuzz   --overwrite   --timeout=500,1200   --corpus=markov   --jobs=2   --logLevel=info   /path/to/d8

Observed Behavior

Fuzzilli starts, completes corpus generation on the main instance, then crashes with:

Fuzzilli/Fuzzer.swift:703: Assertion failed

*** Signal 4: Backtracing from 0x7ee9132e2a30...

This occurs consistently within a few minutes of startup. --jobs=1 works fine. --jobs=2 and --jobs=4 both trigger the crash.

Expected Behavior

Multi-worker mode should work without assertion failures. The assertion at line 703 could be relaxed to allow corpus import during states other than .uninitialized, or the state transition should be synchronized so child workers don't race with the main fuzzer's initialization.

Environment

  • Commit: cbade79 (Apr 8, 2026)
  • Profile: v8Sandbox
  • Target: V8 d8 (built with v8_fuzzilli=true, v8_enable_sandbox=true, is_asan=true, sanitizer_coverage_flags="trace-pc-guard")
  • OS: Ubuntu 22.04, 4 cores, 8GB RAM
  • Swift: 6.1

Analysis

The comment at line 701-702 acknowledges this limitation:

// Currently we only allow corpus import when the fuzzer is still uninitialized.
// If necessary, this can be changed, but we'd need to be able to correctly handle
// the .waiting -> .corpusImport state transition.

In multi-worker mode, the main fuzzer transitions to .corpusGeneration before child workers have finished initializing. When a child worker then tries to synchronize its corpus with the main instance via scheduleCorpusImport, the assertion fails because the fuzzer is no longer in .uninitialized state.

A possible fix would be to either:

  1. Allow scheduleCorpusImport during .corpusGeneration / .fuzzing states
  2. Delay the main fuzzer's state transition until all workers have completed initialization
  3. Use a different synchronization path for child workers that doesn't go through scheduleCorpusImport

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions