microsoft / microsoft/MIDI

[BUG]: Session context handles can collide after vector erase and slot reuse

Open
#1,152 6 comments 1 reaction 2 assignees View on GitHub

@garydan42 is already working on this.

Since Sep 1, 2026.

area-service-or-api :desktop_computer: bug :lady_beetle:
Dominant language
C++
Stars
680
Forks
73
Avg merge
4h 51m
Merged PRs (30d)
59

Description

Summary

Following Pete's request to recheck current source and track separately, this report focuses specifically on context-handle identity in CMidiSessionTracker, not on establishing the cause of #564 or my application's MIDI failure.

AI Generated Content: The technical analysis and standalone model below were prepared with OpenAI Codex. The model was compiled and executed locally with MSVC and rerun for this report. The personal observations below are verbatim excerpts of my own messages from the original incident. No real-service reproduction or installed-binary/source equivalence is claimed.

The new src/in-box/Service/Exe path was inspected at current main commit 4c8444661b1cc6ee7c88f2a083459baf6bf8508d. In that revision, session context handles still derive from addresses of entries in a std::vector. Erasing an earlier entry and then adding another session can give two live sessions the same saved context token. Lookup during context rundown can consequently select the wrong session.

Pete mentioned forthcoming changes that remove pointer-based identity and address locking. If a different commit or branch already replaces this particular session-context mechanism, please point us to it; this report is scoped to the public revision above.

Your personal observation that led to the bug report

Verbatim excerpts from my original incident notes/messages, not AI-written observations:

My current running app stopped responding to midi inputs. The app shows as ready, the vst looks loaded, I can open the vst editor, but no indication it is responding to the midi inputs. I have not tried changing patches or anything to restore it. I have left it in this state to try and troubleshoot

yes, fully closing and relaunching has cleared the failure

Source-level finding (AI Generated Content)

Pinned source references:

Steps to reproduce the identity collision

This is a standalone model of the container/identity operations, not a call into the actual tracker, MIDI APIs, or RPC runtime.

  1. Add sessions A and B, with context tokens taken from their vector-entry addresses.
  2. Remove A normally. B moves to an earlier vector slot but retains its original context token.
  3. Add C. It occupies B's former slot and receives the same token B still holds.
  4. Look up C's token using the tracker's first-match lookup. B is selected instead of C.

Expected: a cleanup token identifies only its owning live session; cleaning up C cannot select B.

Observed in the model: B and C have equal tokens, and cleanup using C's token selects/removes B. This is sequential, so locking alone would not remove the collision. Reserved capacity excludes reallocation as a necessary cause.

Self-contained C++17 model (AI Generated Content)
#include <algorithm>
#include <iostream>
#include <vector>

// Models the address/token operations still present at
// microsoft/MIDI 4c8444661b1cc6ee7c88f2a083459baf6bf8508d.
// No MIDI APIs, services, or application processes are touched.
struct Session
{
    int id;
    void* context = nullptr;
};

int main()
{
    std::vector<Session> sessions;
    sessions.reserve(8); // Exclude reallocation: erase alone is sufficient.
    const auto add = [&](int id)
    {
        sessions.push_back({id});
        auto& entry = sessions.back();
        entry.context = &entry;
        return entry.context;
    };

    add(1);
    void* longLivedContext = add(2);
    sessions.erase(sessions.begin());
    void* newClientContext = add(3);

    const bool collision = longLivedContext == newClientContext;
    std::cout << "Distinct live sessions share a context token: " << collision << '\n';

    const auto victim = std::find_if(sessions.begin(), sessions.end(),
        [&](const Session& s) { return s.context == newClientContext; });
    if (victim == sessions.end())
        return 2;
    const int removed = victim->id;
    sessions.erase(victim);
    std::cout << "Cleanup for session 3 removed session: " << removed << '\n';
    std::cout << "Remaining session: " << sessions.front().id << '\n';
    std::cout << "Model only; not a reproduction against the installed Windows service.\n";
    return collision && removed == 2 && sessions.front().id == 3 ? 0 : 1;
}

In an MSVC Developer Command Prompt:

cl /nologo /EHsc /std:c++17 main.cpp /Fe:session-model.exe
session-model.exe

Output (exit code 0):

Distinct live sessions share a context token: 1
Cleanup for session 3 removed session: 2
Remaining session: 3
Model only; not a reproduction against the installed Windows service.

Scope and remaining validation

  • This demonstrates duplicate identity in the modeled source operations. It does not reproduce actual service registration/rundown, validate RPC behavior with duplicate context values, or establish which Windows binaries contain this code.
  • An upstream regression test against CMidiSessionTracker, followed by a real RPC lifecycle test, would be stronger validation. Neither has been performed here.
  • The original application incident prompted the investigation, but the causal connection remains unconfirmed. In particular, the service session list was not captured during that failure.
  • Existing issue searches for session/context and session/pointer reports found #564 and other runtime reports, but no separate report of this specific vector-erase/slot-reuse mechanism. This issue is filed separately as requested, not asserted to be the same defect as #564.

Environment / diagnostics

  • Windows at the original incident: Windows 11 25H2, build 26200.9168. This is background context, not an assertion that the installed service matches the inspected source.
  • Standalone model: C++17, MSVC 19.51.36256.0; no MIDI hardware or SDK required.
  • Type/location: source-level session-tracker identity issue in the in-box MIDI service.
  • Application/device/vendor driver: not required for the standalone model. The original runtime incident involved a custom JUCE/WinMM app and an S88 mk2; it is not used as proof of the source mechanism.
  • MIDI Diagnostics Tool output: not available for the original incident. No new diagnostic-tool collection or real-service reproduction was performed for this source-focused report.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.