SoundPlayer.Play() does not preserve in-memory WAV buffer lifetime

Đang mở
#136,991 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
csharp
Lĩnh vực
backend, desktop

Hướng nghiên cứu

Start with src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs, especially Play(), PlayLooping(), and the PlaySoundW import, to trace how _streamData is passed to asynchronous playback and how stopping or replacing playback is handled. Then find the related SoundPlayer tests and run them. Done means in-memory WAV data stays at a stable address until asynchronous playback completes or looping playback stops, while synchronous and file-path playback remain unaffected.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

area-System.IO bug untriaged
Description

For Stream and non-file URL sources, SoundPlayer copies the WAV into its private _streamData array. Play() and PlayLooping() then call PlaySoundW with SND_MEMORY | SND_ASYNC (plus SND_LOOP for looping).

The generated [LibraryImport] stub pins the managed array only for the duration of the P/Invoke call. PlaySoundW returns immediately under SND_ASYNC, ending that pin while playback may still be using the buffer. The Win32 contract requires the buffer to remain valid until playback completes.

Required:  pin [ PlaySoundW call ---------------- playback complete/stop ]
Actual:    pin [ PlaySoundW call ] return ------- playback may continue
Why this is a product bug

This occurs through a supported public API path, such as new SoundPlayer(Stream).Play() or PlayLooping(). SoundPlayer allocates and owns the private _streamData copy, selects SND_MEMORY | SND_ASYNC, and initiates the native operation. The caller cannot access or pin _streamData, and Play() exposes no completion task or callback through which the caller could maintain its address.

The lifetime obligation therefore belongs to SoundPlayer: it must satisfy the downstream WinMM contract for the operation it chose. This is not caller misuse or a general thread-safety issue.

Impact

The generated P/Invoke pins _streamData only for the duration of the PlaySoundW call. Because SND_ASYNC returns when playback starts, WinMM may continue accessing the buffer after the pin is released.

The PlaySound contract requires a buffer used with SND_MEMORY | SND_ASYNC to remain valid until playback completes. A compacting GC can move _streamData, and replacing Stream can clear the final managed reference, allowing the array to be collected and its address reused while playback is active.

A diagnostic reproduction can observe the private array moving:

using var player = new SoundPlayer(new MemoryStream(wav, writable: false));
player.Load();
player.PlayLooping();

GC.Collect(
    GC.MaxGeneration,
    GCCollectionMode.Forced,
    blocking: true,
    compacting: true);

Private reflection is needed only to compare the array's address before and after the collection, not to create the underlying lifetime condition.

Expected behavior

Keep the in-memory WAV at a stable address until one-shot playback completes or looping playback is stopped, for example through a persistent pin or native-owned stable copy.

PlaySync() is not affected by this specific issue because PlaySoundW returns only after synchronous playback completes. File-path playback is also unaffected because Windows receives a filename rather than a managed WAV pointer.

Ngôn ngữ chính
C#
Star
18.4k
Fork
5.8k
Merge trung bình
2 ngày 14 giờ
Pull request đã merge (30 ngày)
585

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của dotnet/runtime

Tất cả issue của dotnet/runtime

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.