Waveform capability buffers — 2026-09-23

Following the MMIOINFO sparse-buffer fix, inspection found two more caller buffer errors in src/09a3-handlers-audio.wat:

Microsoft's archived waveOutGetDevCaps and waveInGetDevCaps references explicitly include Windows 95/98/Me and specify a caller-length bounded copy, with a zero-length query succeeding without copying anything. These are API-documentation evidence, not a native Windows execution result.

Implementation

One $wave_dev_caps_fill handles the shared header, A/W name encoding, formats and channel count, plus output-only support flags. It takes a span of min(cbCaps, sizeof(structure)), initializes only that prefix, bounds every nonzero byte store and writes the span back once. It accepts truncated fields and odd UTF-16 byte prefixes without touching the next byte. Zero length returns before pointer translation; nonzero length with NULL returns MMSYSERR_INVALPARAM, consistent with the previous capture-side null policy. Contiguous backing uses the existing direct span path.

The advertised names, formats and device capabilities are unchanged. The existing input test's short-buffer rejection assertion was corrected. Device ID/mapper/open-handle validation is not completed by this change: input still accepts only ID zero, and output still does not validate its selector. The existing W entry points remain compatibility functionality; the archived documentation does not establish native Win98 Unicode support.

Regression evidence

test-wave-caps-bounds.js tests both APIs and both encodings with every size from zero through eight bytes beyond the structure, plus UINT_MAX, across direct memory and two noncontiguous sparse-page placements. It checks the exact prefix, unchanged suffix/leading guards/unrelated backing, stdcall cleanup, and released span scratch. NULL/zero and NULL/nonzero are separate cases. The original implementation fails at the first zero-byte output query: waveOutGetDevCapsA tail 0 (/private/tmp/wa-wave-caps-red.log).

Current isolated verification — 2026-10-02 UTC

Coordinator revalidated only the two capability hunks, the input assertion, and this new regression in /private/tmp/wa-mig-audio-20261002, based on committed 9b4f9b3f. The unrelated timeSetEvent change in the shared audio file was excluded. Shared dirty source and the canonical build were untouched.

This verifies the bounded capability-write slice on the stated committed base; it is not a claim that the entire shared dirty checkout was tested. Device-ID, mapper and live-handle semantics remain outside this slice.