Skip to content

CoreMIDI: replace variable-length array with std::vector - #381

Open
insolace wants to merge 1 commit into
thestk:masterfrom
Muse-Kinetics:pr/compiler-warnings
Open

insolace wants to merge 1 commit into
thestk:masterfrom
Muse-Kinetics:pr/compiler-warnings

Conversation

@insolace

Copy link
Copy Markdown
Collaborator

MidiOutCore::sendMessage() allocates its MIDIPacketList backing store as a variable-length array:

ByteCount bufsize = nBytes > 65535 ? 65535 : nBytes;
Byte buffer[bufsize+16]; // pad for other struct members
ByteCount listSize = sizeof( buffer );
MIDIPacketList *packetList = (MIDIPacketList*)buffer;

VLAs are not standard C++ — Clang warns under -Wvla-cxx-extension and MSVC rejects them outright. bufsize is also caller-derived, up to 64K + 16, which is more than is comfortable to place on the stack.

This uses a std::vector<Byte> instead, taking listSize from the vector and pointing packetList at data(). Behaviour is unchanged: the buffer is still allocated once and reused across every iteration of the chunking loop.

Relationship to PR #350

PR #350 proposes alloca() for the same warning. That keeps the allocation on the stack, avoiding a heap allocation in the send path, but alloca() is non-standard and unbounded for a large SysEx; std::vector is portable and heap-safe.

Both fix the warning. The choice is yours — if you prefer the alloca() approach, this should be dropped in favour of #350, which was filed first.

Verification

macOS, Clang: compiles clean, no warnings.

Tested against real MIDI 2.0 hardware (MIDI-CI Discovery, Property Exchange Get of a 1129-byte resource list, a 366-byte multi-chunk PE Get with reassembly, and PE Set plus verify) — byte-identical results to the unpatched baseline.

The buffer-reuse loop across the 64K chunking boundary was exercised specifically, since that is the only part this change could plausibly break: a 70000-byte payload through MidiOutCore::sendMessage() over a virtual CoreMIDI port pair round-tripped 70002/70002 bytes byte-identical, F0..F7 intact.

Addresses #350.

MidiOutCore::sendMessage allocates its MIDIPacketList backing store as
'Byte buffer[bufsize+16]', a variable-length array. VLAs are not standard
C++; Clang warns under -Wvla-cxx-extension and MSVC rejects them outright.
The size is caller-controlled, up to 64K + 16, which is also more than is
comfortable to place on the stack.

Use a std::vector<Byte> instead, taking listSize from the vector and
pointing packetList at data(). Behaviour is unchanged: the buffer is still
allocated once and reused across every iteration of the chunking loop.

Addresses thestk#350. Note that PR thestk#350 proposes alloca() for the same warning.
That keeps the allocation on the stack, which avoids a heap allocation in
the send path, but alloca() is non-standard and unbounded for a large
SysEx. std::vector is portable and heap-safe. Both fix the warning; the
choice is the maintainer's, and this change should be dropped if alloca()
is preferred.
@insolace
insolace marked this pull request as ready for review September 11, 2026 09:42
@insolace

Copy link
Copy Markdown
Collaborator Author

One more data point, from testing this change on current macOS.

While checking whether unrelated CoreMIDI work affected #366 ("SysEx Not Delivered to RtMidi Virtual Ports on macOS"), we could not reproduce that issue at all on macOS 26.4.1 — with either this branch or unmodified master — using the reporter's own repro.

Worth noting as a hypothesis rather than a claim: the VLA this PR removes predates #366 and was live when it was filed. A VLA sized from a caller-derived value at runtime is exactly the kind of construct whose behaviour can vary by compiler, OS version and architecture, in a way that a fixed small buffer for a 3-byte message never would. That would explain a report of "short messages work, SysEx does not" without needing a CoreMIDI-level explanation.

Not confirmed — it would need the reporter's original toolchain and macOS version to test properly, and we have asked them on #366 for exactly that. Mentioning it here only because if that hypothesis holds, this change may incidentally address #366 as well. It is not claimed as a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant