Skip to content

Avoid possible UAF in rendering complete notification#894

Merged
sbooth merged 3 commits intomainfrom
delegate
Mar 22, 2026
Merged

Avoid possible UAF in rendering complete notification#894
sbooth merged 3 commits intomainfrom
delegate

Conversation

@sbooth
Copy link
Copy Markdown
Owner

@sbooth sbooth commented Mar 22, 2026

No description provided.

Copilot AI review requested due to automatic review settings March 22, 2026 15:39
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpp-linter Review

Used clang-format v21.1.8

Click here for the full clang-format patch
diff --git a/Sources/CSFBAudioEngine/Player/AudioPlayer.mm b/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
index f7251b3..132bd8e 100644
--- a/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
+++ b/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
@@ -2107,2 +2107,2 @@ void sfb::AudioPlayer::handleRenderingWillCompleteEvent(Decoder decoder, uint64_
-                if (didStopEngine &&
-                    [player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
+                if (didStopEngine && [player.delegate respondsToSelector:@selector(audioPlayer:
+                                                                                 playbackStateChanged:)]) {

Have any feedback or feature suggestions? Share it here.

Comment on lines +2107 to +2108
if (didStopEngine &&
[player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-format suggestion

Suggested change
if (didStopEngine &&
[player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
if (didStopEngine && [player.delegate respondsToSelector:@selector(audioPlayer:
playbackStateChanged:)]) {

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces the risk of use-after-free during the “rendering complete” async notification path by ensuring delegate callbacks use the block’s strongly-retained SFBAudioPlayer *player rather than the AudioPlayer’s weak player_ back-pointer.

Changes:

  • Use the strong local player reference (promoted from weakPlayer) for playbackStateChanged: delegate notifications in the rendering-complete dispatch block.
  • Minor formatting cleanup of the @selector(audioPlayer:playbackStateChanged:) check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions Bot dismissed their stale review March 22, 2026 15:50

outdated suggestion

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpp-linter Review

Used clang-format v21.1.8

Click here for the full clang-format patch
diff --git a/Sources/CSFBAudioEngine/Player/AudioPlayer.mm b/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
index 2e3b3c5..132bd8e 100644
--- a/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
+++ b/Sources/CSFBAudioEngine/Player/AudioPlayer.mm
@@ -667,2 +667,2 @@ bool sfb::AudioPlayer::play(NSError **error) noexcept {
-    if ((didStartEngine || !wasPlaying) &&
-        [player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
+    if ((didStartEngine || !wasPlaying) && [player_.delegate respondsToSelector:@selector(audioPlayer:
+                                                                                        playbackStateChanged:)]) {
@@ -1786,2 +1786,2 @@ bool sfb::AudioPlayer::processDecoderCanceledEvent() noexcept {
-    } else if (error != nil &&
-               [player_.delegate respondsToSelector:@selector(audioPlayer:decodingAborted:error:framesRendered:)]) {
+    } else if (error != nil && [player_.delegate respondsToSelector:@selector(audioPlayer:
+                                                                            decodingAborted:error:framesRendered:)]) {
@@ -2107,2 +2107,2 @@ void sfb::AudioPlayer::handleRenderingWillCompleteEvent(Decoder decoder, uint64_
-                if (didStopEngine &&
-                    [player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
+                if (didStopEngine && [player.delegate respondsToSelector:@selector(audioPlayer:
+                                                                                 playbackStateChanged:)]) {
@@ -2247,2 +2247,2 @@ void sfb::AudioPlayer::handleAudioSessionInterruption(NSDictionary *userInfo) no
-        if (preInterruptState_ != 0 &&
-            [player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
+        if (preInterruptState_ != 0 && [player_.delegate respondsToSelector:@selector(audioPlayer:
+                                                                                    playbackStateChanged:)]) {

Have any feedback or feature suggestions? Share it here.

Comment on lines +667 to +668
if ((didStartEngine || !wasPlaying) &&
[player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-format suggestion

Suggested change
if ((didStartEngine || !wasPlaying) &&
[player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
if ((didStartEngine || !wasPlaying) && [player_.delegate respondsToSelector:@selector(audioPlayer:
playbackStateChanged:)]) {

Comment on lines +1786 to +1787
} else if (error != nil &&
[player_.delegate respondsToSelector:@selector(audioPlayer:decodingAborted:error:framesRendered:)]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-format suggestion

Suggested change
} else if (error != nil &&
[player_.delegate respondsToSelector:@selector(audioPlayer:decodingAborted:error:framesRendered:)]) {
} else if (error != nil && [player_.delegate respondsToSelector:@selector(audioPlayer:
decodingAborted:error:framesRendered:)]) {

Comment on lines +2107 to +2108
if (didStopEngine &&
[player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-format suggestion

Suggested change
if (didStopEngine &&
[player.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
if (didStopEngine && [player.delegate respondsToSelector:@selector(audioPlayer:
playbackStateChanged:)]) {

Comment on lines +2247 to +2248
if (preInterruptState_ != 0 &&
[player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-format suggestion

Suggested change
if (preInterruptState_ != 0 &&
[player_.delegate respondsToSelector:@selector(audioPlayer:playbackStateChanged:)]) {
if (preInterruptState_ != 0 && [player_.delegate respondsToSelector:@selector(audioPlayer:
playbackStateChanged:)]) {

@github-actions github-actions Bot dismissed their stale review March 22, 2026 15:50

outdated suggestion

@sbooth sbooth merged commit 29d3f9f into main Mar 22, 2026
2 checks passed
@sbooth sbooth deleted the delegate branch March 22, 2026 15:52
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.

2 participants