Files
JaySynth/tools/testhost/tests/scenarios/nrpn_out_of_range.json
T
jensandClaude Sonnet 5 f54689f071 Add regression suite testing JaySynth's TODO.md findings via testhost
tools/testhost/tests/run_tests.sh dynamically exercises the tracked
hardening findings using testhost itself - no GUI, sub-second wall
time:

- oversized_blocksize (Critical #5): --blockSize 16384 under a
  timeout, catching either the overflow or the deadlock the original
  bug could cause.
- nrpn_out_of_range/nrpn_in_range (Critical #1): JSON scenarios
  sending the 5-message MIDI NRPN CC sequence, once targeting the
  max 14-bit ID (16383) and once a legitimate in-range ID (500), so
  a regression that made the bounds check too aggressive would also
  show up.
- patch_save_load_roundtrip / bank_save_load_roundtrip: save a
  distinctive continuous parameter value, reload in a fresh process,
  check it round-trips within tolerance - covers the
  setCurrentProgramStateInformation no-op bug and the
  patchDecodeXml/patchImportXml fixes.
- stability_sweep: loads every bundled .fxp under extras/sounds/ and
  renders a held note through each, as a broad crash/NaN net.

Added --printParams to main.cpp (prints every parameter's index and
value) to make the round-trip tests possible - this was also already
a noted nice-to-have in testhost/TODO.md.

While building the oversized_blocksize test, found and fixed (on the
hardening branch, commit d713ca5) a second, previously-unknown bug:
VCF_CalcCoeff_LPF/_HPF/_BPF advance the coefficient buffer pointer
once per (sample, filter-section) pair, but the buffer was only ever
allocated for bufsize samples, not bufsize*sections - a 4th-order
filter overflowed it for any block between 4097 and 8192 samples.
Found via bisecting the crashing block size then confirming with an
ASan build; see tests/README.md's debugging-notes section for exactly
how, including the ASan symbolizer hang encountered along the way and
the workaround.

Also discovered (documented in tools/testhost/TODO.md's Investigate
section, not fixed - out of scope): JaySynth's compiled VST2 wrapper
never advertises chunk support to the host, so real .fxp/.fxb sample
files have no effect when loaded through the generic AudioProcessor
state API. The round-trip tests work around this by using testhost's
own save output as the fixture rather than an external sample file.

All 10 checks pass against the current hardening-branch build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011dhtwRLARk4eiPngcQykLJ
2026-07-27 20:06:44 +02:00

17 lines
1.5 KiB
JSON

{
"_comment": "Regression test for the fixed NRPN out-of-bounds write (TODO.md Critical finding #1: JaySynth::handleController wrote last_midiCC_info[midiCC_info.ID] with no bounds check; NRPN IDs assemble to up to 16383 but the array is sized NUM_MIDI_CONTROLLERS=1024). This sends the maximum possible 14-bit NRPN ID (127<<7 | 127 = 16383) via the standard MIDI NRPN CC sequence (99=NRPN MSB, 98=NRPN LSB, 6=Data Entry MSB, 38=Data Entry LSB, 98 again to complete/trigger the sequence - see MidiNrpn::process). Before the fix this reliably wrote far outside the array; after the fix, handleController returns immediately for any out-of-range ID. Success = process completes without crashing/hanging and produces valid, NaN-free audio.",
"sampleRate": 44100,
"blockSize": 512,
"durationSeconds": 1.0,
"events": [
{ "sample": 0, "type": "controller", "channel": 1, "controllerNumber": 99, "controllerValue": 127 },
{ "sample": 1, "type": "controller", "channel": 1, "controllerNumber": 98, "controllerValue": 127 },
{ "sample": 2, "type": "controller", "channel": 1, "controllerNumber": 6, "controllerValue": 64 },
{ "sample": 3, "type": "controller", "channel": 1, "controllerNumber": 38, "controllerValue": 0 },
{ "sample": 4, "type": "controller", "channel": 1, "controllerNumber": 98, "controllerValue": 127 },
{ "sample": 10, "type": "noteOn", "channel": 1, "note": 60, "velocity": 100 },
{ "sample": 44050, "type": "noteOff", "channel": 1, "note": 60 }
],
"recordWav": "out_nrpn_out_of_range.wav"
}