Skip to main content

lafleur

A feedback-driven, evolutionary fuzzer for the CPython JIT compiler.

lafleur is a specialized fuzzer designed to find crashes, correctness bugs, and hangs in CPython's experimental JIT compiler. Unlike traditional fuzzers that generate code randomly, lafleur uses a coverage-guided, evolutionary approach. It executes test cases, observes their effect on the JIT's behavior by analyzing verbose trace logs, and uses that feedback to guide its mutations, becoming progressively smarter at finding interesting code paths over time.

Features

  • Coverage-Guided: Uses uop-edge coverage to intelligently guide the fuzzing process.
  • AST-Based Mutation: Mutates the structure of Python code directly, enabling complex and syntactically correct transformations.
  • JIT-Specific Mutators: Includes a library of mutation strategies specifically designed to attack common JIT compiler weaknesses like type speculation, inline caching, and guard handling.
  • Differential Testing: Features a mode to find silent correctness bugs by comparing the output of JIT-compiled code against the standard interpreter.
  • Intelligent Scheduling: Employs a multi-factor scoring system to prioritize fuzzing test cases that are fast, small, and have discovered rare or fertile code paths.

Installation and Setup

lafleur is a tool that requires a specific CPython build environment. Follow these steps carefully.

Step 1: CPython Prerequisite

lafleur must be run with a debug build of CPython that has the experimental JIT compiler enabled.

  1. Clone CPython:
    git clone https://github.com/python/cpython.git
    cd cpython
    
  2. Configure & Build (First Pass):
    ./configure --with-pydebug --enable-experimental-jit
    make -j$(nproc)
    
  3. Create Virtual Environment:
    ./python -m venv ~/venvs/lafleur_venv
    

Step 2: Install lafleur and Tune the JIT

With the venv created, you can now install lafleur and use its JIT-tuning tool.

  1. Activate Your Virtual Environment:
    source ~/venvs/lafleur_venv/bin/activate
    
  2. Install lafleur from PyPI:
    pip install lafleur
    
  3. Tune the JIT: Run the lafleur tuning script, pointing it at your CPython source directory. This modifies C header files to make the JIT more aggressive, which is ideal for fuzzing.
    lafleur-jit-tweak /path/to/your/cpython
    
  4. Rebuild CPython: Recompile CPython to apply the tuned settings.
    cd /path/to/your/cpython
    make -j$(nproc)
    

Step 3: fusil Seeder (Optional)

lafleur can use the classic fusil fuzzer to generate an initial set of interesting seed files. This is recommended but optional.

  1. Install fusil:
    git clone https://github.com/fusil-fuzzer/fusil.git
    cd fusil
    pip install .
    
  • Alternative: Manual Seeding: If you prefer not to install fusil, you can create a directory named corpus/jit_interesting_tests/ in your working directory and place your own hand-crafted Python seed files inside it.

Usage

Once installed, you can run lafleur from any directory. It will create its output subdirectories (corpus/, crashes/, etc.) in the current working directory.

Basic Usage (Resuming a Run)

If a corpus already exists, this command will load the state and resume the fuzzing session.

# Don't forget to activate your venv first!
lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded

Seeding a New Corpus

Use --min-corpus-files to instruct lafleur to call the fusil seeder until the corpus has at least 20 files before starting.

lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded --min-corpus-files 20

Differential Testing

Use --differential-testing to enable the mode for finding silent correctness bugs.

lafleur --fusil-path /path/to/fusil/fuzzers/fusil-python-threaded --differential-testing

Analysis & Triage

lafleur includes a suite of tools for monitoring fuzzing progress, aggregating campaign results, and managing crash discoveries over time.

Tool Purpose
lafleur-report Check the pulse of a running fuzzer. Generates health, coverage, and crash summaries for a single instance.
lafleur-campaign Aggregate results from 50+ cores into one dashboard. Deduplicates crashes, produces fleet-wide metrics, and generates HTML reports.
lafleur-triage Track regressions and known issues with a built-in SQLite database. Link crashes to GitHub issues and manage their lifecycle.

Quick Examples

# Single instance report
lafleur-report /path/to/instance

# Campaign dashboard with HTML output
lafleur-campaign runs/ --html report.html --registry crashes.db

# Interactive crash triage
lafleur-triage interactive

For detailed usage, see docs/TOOLING.md.


Interpreting the Results

The most important findings from a fuzzing run will be saved in four directories:

  • crashes/: Contains scripts that caused a hard crash (e.g., SegFault) or raised a critical error. Each .py file is accompanied by a .log file containing the output from the crash.
  • timeouts/: Contains scripts that ran for too long (default > 10 seconds), often indicating an infinite loop bug.
  • divergences/: When in --differential-testing mode, this contains scripts where the JIT's behavior differed from the standard interpreter's.
  • regressions/: When in --timing-fuzz mode, this contains scripts where the JIT-compiled execution was significantly slower than the standard interpreter.

A helpful command to filter out low-value crashes and find potentially interesting ones is:

grep -L -E "(statically|indentation|unsupported|formatting|invalid syntax)" crashes/*.log | sed 's/\.log$/.py/'

Contributing & Filing Issues

lafleur is an open-source project, and contributions are welcome.

To file a bug report or a feature request, please use the project's GitHub Issues page. When filing a bug, please include:

  1. The crashing test case (.py file).
  2. The full log file (.log).
  3. The commit hash of the CPython version you are fuzzing (you can paste the output of python -VV).

History and the Name

lafleur began as an advanced feature set within the fusil project, which was created by Victor Stinner.

The name comes from the expression "la fleur au fusil", which matches the spirit with which the project was started.

Release files for lafleur 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lafleur 0.1.0
File Size Uploaded
lafleur-0.1.0.tar.gz 204.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lafleur 0.1.0
File Interpreter ABI Platform
lafleur-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 363.0 kB

Release files / lafleur-0.1.0.tar.gz

Download URL lafleur-0.1.0.tar.gz
Size 204.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d4ac4dd545804600dd7a8c6ebf85e26128494016c2ff9e3e1e23349bedd589d4
BLAKE2b-256 checksum
How to use checksums
3377810c5da41ce9d018ba062be0f740ace0f0293bfe3fb26ceb75fb3c915767
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.15.0a3+

Release files / lafleur-0.1.0-py3-none-any.whl

Download URL lafleur-0.1.0-py3-none-any.whl
Size 158.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
72bd0da871a07b2810bdcc526ec50b82b49fbe689309ca3b594d43dff2049074
BLAKE2b-256 checksum
How to use checksums
ca97239eb1df47adbd61facb08c760f6805848769f9eba14a8a10fa3040bff32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.15.0a3+

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page