Check maximum buffer size in ResamplerHelper::MaybeResample

Verify that the target sample count does not exceed the maximum allowed
size for an AudioFrame. Previously, requesting a resample operation with
a high number of channels or a high sample rate could result in a target
data size that exceeded the internal limits of the AudioFrame class.

This change adds a validation check before starting the resampling
process. If the calculated target size—based on the desired sample rate
and channel count—surpasses kMaxDataSizeSamples, the operation now
safely aborts. In such cases, the error is logged, the audio frame is
muted to avoid undefined behavior, and the function returns false.

Bug: chromium:486349161
Fixes: chromium:486349161
Change-Id: Ia0d8abcd390f90a590c07c0606f9b6c968f663e6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/454000
Reviewed-by: Per Åhgren <peah@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#47076}
diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn
index 016485c..132b293 100644
--- a/modules/audio_coding/BUILD.gn
+++ b/modules/audio_coding/BUILD.gn
@@ -47,6 +47,7 @@
     "../../api/neteq:default_neteq_factory",
     "../../api/neteq:neteq_api",
     "../../api/units:timestamp",
+    "../../audio/utility:audio_frame_operations",
     "../../common_audio",
     "../../common_audio:common_audio_c",
     "../../rtc_base:buffer",
@@ -1400,6 +1401,7 @@
 
       sources = [
         "acm2/acm_remixing_unittest.cc",
+        "acm2/acm_resampler_unittest.cc",
         "acm2/audio_coding_module_unittest.cc",
         "acm2/call_statistics_unittest.cc",
         "audio_network_adaptor/audio_network_adaptor_impl_unittest.cc",
diff --git a/modules/audio_coding/DEPS b/modules/audio_coding/DEPS
index 3dc9624..be1291b 100644
--- a/modules/audio_coding/DEPS
+++ b/modules/audio_coding/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+audio/utility",
   "+call",
   "+common_audio",
   "+logging/rtc_event_log",
diff --git a/modules/audio_coding/acm2/acm_resampler.cc b/modules/audio_coding/acm2/acm_resampler.cc
index a8c4ba8..e9c2861 100644
--- a/modules/audio_coding/acm2/acm_resampler.cc
+++ b/modules/audio_coding/acm2/acm_resampler.cc
@@ -11,12 +11,15 @@
 #include "modules/audio_coding/acm2/acm_resampler.h"
 
 #include <array>
+#include <cstddef>
 #include <cstdint>
 
 #include "absl/algorithm/container.h"
 #include "api/audio/audio_frame.h"
 #include "api/audio/audio_view.h"
+#include "audio/utility/audio_frame_operations.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
 
 namespace webrtc {
 namespace acm2 {
@@ -38,6 +41,18 @@
       (desired_sample_rate_hz != -1) &&
       (current_sample_rate_hz != desired_sample_rate_hz);
 
+  if (need_resampling) {
+    const size_t target_size =
+        audio_frame->num_channels_ *
+        SampleRateToDefaultChannelSize(desired_sample_rate_hz);
+    if (target_size > AudioFrame::kMaxDataSizeSamples) {
+      RTC_LOG(LS_ERROR) << "AudioFrame cannot hold resampled data.";
+      AudioFrameOperations::Mute(audio_frame);
+      audio_frame->SetSampleRateAndChannelSize(desired_sample_rate_hz);
+      return false;
+    }
+  }
+
   if (need_resampling && !resampled_last_output_frame_) {
     // Prime the resampler with the last frame.
     InterleavedView<const int16_t> src(last_audio_buffer_.data(),
diff --git a/modules/audio_coding/acm2/acm_resampler_unittest.cc b/modules/audio_coding/acm2/acm_resampler_unittest.cc
new file mode 100644
index 0000000..f597151
--- /dev/null
+++ b/modules/audio_coding/acm2/acm_resampler_unittest.cc
@@ -0,0 +1,79 @@
+/*
+ *  Copyright (c) 2026 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_coding/acm2/acm_resampler.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "api/audio/audio_frame.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace acm2 {
+
+TEST(ResamplerHelperTest, MaybeResampleCheckForMaxSize) {
+  ResamplerHelper resampler;
+  AudioFrame audio_frame;
+
+  // Create an audio frame that requires resampling from 32kHz to 48kHz
+  // with a very high number of channels (24).
+  const int kCurrentSampleRateHz = 32000;
+  const int kDesiredSampleRateHz = 48000;
+  const size_t kChannels = 24;
+
+  // 10 ms of data at 32kHz = 320 samples per channel.
+  std::vector<int16_t> dummy_data(320 * 24, 0);
+  audio_frame.UpdateFrame(0, dummy_data.data(), 320, kCurrentSampleRateHz,
+                          AudioFrame::kNormalSpeech, AudioFrame::kVadActive,
+                          kChannels);
+
+  // The resampler prime path will attempt to allocate a buffer that is
+  // kChannels * (kDesiredSampleRateHz / 100) = 24 * 480 = 11520 samples,
+  // which exceeds AudioFrame::kMaxDataSizeSamples (7680).
+  const bool resample_success =
+      resampler.MaybeResample(kDesiredSampleRateHz, &audio_frame);
+
+  // Verify that MaybeResample correctly detects the buffer size condition and
+  // safely aborts the operation by returning false and muting the frame.
+  EXPECT_FALSE(resample_success);
+  EXPECT_TRUE(audio_frame.muted());
+  EXPECT_EQ(audio_frame.sample_rate_hz_, kDesiredSampleRateHz);
+  EXPECT_EQ(audio_frame.num_channels_, kChannels);
+}
+
+TEST(ResamplerHelperTest, MaybeResampleValidMaxSize) {
+  ResamplerHelper resampler;
+  AudioFrame audio_frame;
+
+  // Ensure that resampling within the valid buffer size does not trigger the
+  // muting behavior. We'll use a valid number of channels (e.g. 1) that will
+  // not exceed the bounds.
+  const int kCurrentSampleRateHz = 32000;
+  const int kDesiredSampleRateHz = 48000;
+  const size_t kChannels = 1;
+
+  std::vector<int16_t> dummy_data(320 * 1, 1000);
+  audio_frame.UpdateFrame(0, dummy_data.data(), 320, kCurrentSampleRateHz,
+                          AudioFrame::kNormalSpeech, AudioFrame::kVadActive,
+                          kChannels);
+
+  const bool resample_success =
+      resampler.MaybeResample(kDesiredSampleRateHz, &audio_frame);
+
+  EXPECT_TRUE(resample_success);
+  EXPECT_FALSE(audio_frame.muted());
+  EXPECT_EQ(audio_frame.sample_rate_hz_, kDesiredSampleRateHz);
+  EXPECT_EQ(audio_frame.num_channels_, kChannels);
+}
+
+}  // namespace acm2
+}  // namespace webrtc