McRogueFace/tests/fuzz/fuzz_grid_entity.py
John McCardle 90a2945a9f Add native libFuzzer fuzz harness for Python API, addresses #283
Pivots away from atheris (which lacks Python 3.14 support) to a single
libFuzzer-linked executable that embeds CPython, registers mcrfpy, and
dispatches each iteration to a Python fuzz_one_input(data: bytes) function
loaded from tests/fuzz/fuzz_<target>.py by MCRF_FUZZ_TARGET env var.

libFuzzer instruments the C++ engine code where all #258-#278 bugs live;
Python drives the fuzzing logic via an in-house ByteStream replacement
for atheris.FuzzedDataProvider. Python-level exceptions are caught; only
ASan/UBSan signal real bugs.

CMake
- MCRF_FUZZER=ON builds mcrfpy_fuzz from all src/*.cpp except main.cpp
  plus tests/fuzz/fuzz_common.cpp, linked with -fsanitize=fuzzer,address,
  undefined. Asset+lib post-build copy added so the embedded interpreter
  finds its stdlib and default_font/default_texture load.

Makefile
- fuzz-build builds only mcrfpy_fuzz (fast iterate)
- fuzz loops over six targets setting MCRF_FUZZ_TARGET for each
- fuzz-long TARGET=x SECONDS=n for deep manual runs
- fuzz-repro TARGET=x CRASH=path for crash reproduction
- Shared ASAN_OPTIONS / PYTHONHOME env via FUZZ_ENV define

tests/fuzz
- fuzz_common.cpp: LLVMFuzzerInitialize bootstraps Python, imports target,
  resolves fuzz_one_input. LLVMFuzzerTestOneInput wraps bytes as PyBytes,
  calls target, swallows Python errors.
- fuzz_common.py: ByteStream byte consumer + safe_reset() + EXPECTED_EXCEPTIONS
- Six target stubs (grid_entity, property_types, anim_timer_scene,
  maps_procgen, fov, pathfinding_behavior) to be fleshed out in follow-up
- README with build/run/triage instructions

Verified end-to-end: make fuzz-build produces build-fuzz/mcrfpy_fuzz,
make fuzz FUZZ_SECONDS=3 ran all six targets (~2400-9800 exec/s each,
667-1883 coverage edges), make fuzz-repro loaded and replayed a corpus
input cleanly. No crashes from the stubs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:05:04 -04:00

23 lines
808 B
Python

"""fuzz_grid_entity - stub. Wave 2 agent W4 will implement.
Target bugs: #258-#263 (gridstate overflow on entity transfer between
differently-sized grids), #273 (entity.die during iteration), #274
(set_grid spatial hash). See /home/john/.claude/plans/abundant-gliding-hummingbird.md.
Contract: define fuzz_one_input(data: bytes) -> None. The C++ harness
(tests/fuzz/fuzz_common.cpp) calls this for every libFuzzer iteration.
Use ByteStream to consume bytes. Wrap work in try/except EXPECTED_EXCEPTIONS.
"""
import mcrfpy
from fuzz_common import ByteStream, EXPECTED_EXCEPTIONS
def fuzz_one_input(data):
stream = ByteStream(data)
try:
# Minimal smoke: create one grid so the harness verifies end to end.
mcrfpy.Grid(grid_size=(4, 4))
except EXPECTED_EXCEPTIONS:
pass