Fix ASan null pointer in StartAecDump

Adds a null check to PeerConnectionFactory::StartAecDump to prevent
passing a null FILE* to WebRtcVoiceEngine, which ultimately passes it to
a _Nonnull argument in AudioProcessing::CreateAndAttachAecDump, causing
an ASan/UBSan invalid_null_argument runtime error.

Also updates PeerConnectionFactoryDependenciesTest's
CreatesAudioProcessingWithProvidedBuilder to use a valid temporary file
instead of relying on undefined behavior.

Fixed: webrtc:505372808
Change-Id: I129eb0b650c0dda508e0c99cecaf33892f348bf8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/468260
Reviewed-by: Jeremy Leconte <jleconte@google.com>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#47580}
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index e7151c2..6442497 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -781,6 +781,7 @@
 
 bool WebRtcVoiceEngine::StartAecDump(FileWrapper file, int64_t max_size_bytes) {
   RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+  RTC_DCHECK(file.is_open());
 
   AudioProcessing* ap = apm();
   if (!ap) {
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 280421c..8126afd 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -2889,6 +2889,7 @@
       "../rtc_base:socket_address",
       "../rtc_base:socket_server",
       "../rtc_base:threading",
+      "../test:fileutils",
       "../test:run_loop",
       "../test:test_support",
     ]
diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc
index 299d151..d36b766 100644
--- a/pc/peer_connection_factory.cc
+++ b/pc/peer_connection_factory.cc
@@ -191,6 +191,10 @@
 
 bool PeerConnectionFactory::StartAecDump(FILE* file, int64_t max_size_bytes) {
   RTC_DCHECK_RUN_ON(worker_thread());
+  if (!file) {
+    RTC_LOG(LS_ERROR) << "Cannot start AEC dump with null file pointer.";
+    return false;
+  }
   if (media_engine_ref_) {
     RTC_LOG(LS_WARNING) << "Replacing ongoing AEC dump.";
   } else {
diff --git a/pc/peer_connection_factory_unittest.cc b/pc/peer_connection_factory_unittest.cc
index 346125c..14debc7 100644
--- a/pc/peer_connection_factory_unittest.cc
+++ b/pc/peer_connection_factory_unittest.cc
@@ -14,6 +14,7 @@
 #include <cstddef>
 #include <cstdio>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -69,6 +70,7 @@
 #include "test/gmock.h"
 #include "test/gtest.h"
 #include "test/run_loop.h"
+#include "test/testsupport/file_utils.h"
 
 #ifdef WEBRTC_ANDROID
 #include "pc/test/android_test_initializer.h"
@@ -762,7 +764,14 @@
 
   scoped_refptr<PeerConnectionFactoryInterface> pcf =
       CreateModularPeerConnectionFactory(std::move(pcf_dependencies));
-  pcf->StartAecDump(nullptr, 24'242);
+  // Provide a valid file to avoid triggering the null pointer guard.
+  // The AEC dump machinery takes ownership of the file and closes it.
+  std::string temp_filename =
+      test::TempFilename(test::OutputPath(), "aec_dump");
+  pcf->StartAecDump(fopen(temp_filename.c_str(), "wb"), 24'242);
+  // Destroy the PCF to ensure the file is closed before attempting removal.
+  pcf = nullptr;
+  test::RemoveFile(temp_filename);
 }
 
 TEST(PeerConnectionFactoryDependenciesTest, RepeatMediaEngineInitialization) {