Fix UAF in AndroidVideoTrackSource::SetState Tasks posted to the signaling thread could execute after destruction because the safety flag was not being marked as not alive. This caused use-after-free crashes (SIGSEGV) in callbacks like FireOnChange. This change ensures that the safety flag is marked as not alive in the destructor, preventing tasks from running post-destruction. Bug: b/403168866 Change-Id: I6ea1db070d32305725b8e7cd34d8b636f8ac70c9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/462920 Reviewed-by: Per Åhgren <peah@webrtc.org> Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org> Commit-Queue: Viktor Grönroos <wilhelmsson@google.com> Cr-Commit-Position: refs/heads/main@{#47456}
diff --git a/sdk/android/src/jni/android_video_track_source.cc b/sdk/android/src/jni/android_video_track_source.cc index 36c48e8..7ac66c7 100644 --- a/sdk/android/src/jni/android_video_track_source.cc +++ b/sdk/android/src/jni/android_video_track_source.cc
@@ -77,10 +77,30 @@ signaling_thread_(signaling_thread), is_screencast_(is_screencast), align_timestamps_(align_timestamps), - safety_(PendingTaskSafetyFlag::Create()) { + safety_(PendingTaskSafetyFlag::CreateAttachedToTaskQueue( + /*alive=*/true, + signaling_thread)) { + RTC_DCHECK(signaling_thread_); RTC_LOG(LS_INFO) << "AndroidVideoTrackSource ctor"; } -AndroidVideoTrackSource::~AndroidVideoTrackSource() = default; + +AndroidVideoTrackSource::~AndroidVideoTrackSource() { + RTC_LOG(LS_INFO) << "AndroidVideoTrackSource dtor"; + + // TODO(b/403168866): This is a workaround to ensure + // safety_flag_->SetNotAlive() is called on the signaling thread. + // + // In production code, this object should always be destroyed on the signaling + // thread. However, during teardown in instrumentation tests, calling + // VideoSource.dispose() from Java drops the last reference to this object on + // the Java test thread. This trigger destruction on the wrong thread, which + // would cause a crash due to the sequence checker DCHECK in SetNotAlive(). + if (signaling_thread_->IsCurrent()) { + safety_->SetNotAlive(); + } else { + signaling_thread_->BlockingCall([&] { safety_->SetNotAlive(); }); + } +} bool AndroidVideoTrackSource::is_screencast() const { return is_screencast_.load();