CVE-2026-118328
Overview
Background
- Forward Error Correction (FEC)
- WebRTC’s ULPFEC/FlexFEC machinery (
modules/rtp_rtcp/source/forward_error_correction.cc) that generates redundant repair packets and reconstructs lost media packets from received FEC packets at the receiver. - Packet mask tables
kPacketMaskBurstyTbl/kPacketMaskRandomTbl: flattened byte arrays encoding the bitmasks that say which media packets each FEC packet protects. The patch pins their exact length (kPacketMaskBurstyTblSize = 741, computed1 + 12 + 78 + 650).- `packet_masks_` / `tmp_packet_masks_`
- fixed-capacity scratch buffers (
kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize) thatGeneratePacketMasks()fills and thatInsertZerosInPacketMasks()rewrites. - `ParseSequenceNumber` / `ParseSsrc`
- static helpers that read the 16-bit sequence number (bytes 2–3) and 32-bit SSRC (bytes 8–11) out of an RTP header.
- Spanification
- the Chromium/WebRTC program of replacing raw
uint8_t*+ length arithmetic withstd::span/std::array, so the length travels with the pointer and bounds are enforced.
Root Cause Analysis
The patch, titled “Spanify and thus harden forward error correction code,” replaces every raw-pointer/memset/memcpy access in the FEC path with bounded std::span/std::array equivalents, which is the tell that the pre-patch code had under-checked memory accesses over attacker-influenced RTP/FEC data. The receiver-side recovery functions are the sharp edge: ParseSequenceNumber(const uint8_t*) and ParseSsrc(const uint8_t*) indexed packet[2..3] and packet[8..11] with no length guarantee, and InitRecovery/FinishPacketRecovery copied fec_packet.protection_length and the recovered-length field read from data[2] into a freshly SetSized buffer using raw memcpy/memset and ByteReader/ByteWriter on bare pointers. A received FEC packet whose header-declared lengths or offsets (fec_header_size, protection_length) exceeded the actual buffer could drive those copies and the ByteReader<uint16_t>::ReadBigEndian(&data[2]) read out of bounds.
The fix threads std::span<const uint8_t> through ParseSequenceNumber/ParseSsrc (via GetBE16/GetBE32 on packet.subspan(2)/subspan(8)), rewrites the recovery copies as data.Set(span.first(kRtpHeaderSize)) and data.Append(span.subspan(fec_header_size, protection_length)), converts the generation scratch buffers packet_masks_/tmp_packet_masks_ from C arrays to std::array, and replaces the memset/memcpy in mask generation with std::ranges::fill/std::ranges::copy over std::span(...).first(num_fec_packets * mask_size). It also converts the static mask tables to constexpr std::array<uint8_t, …> with a static_assert(tbl.back() != 0) so a wrong size is caught at compile time. Because this is a broad spanification, the single exploitable out-of-bounds site is not isolated to one line by the diff (inferred); the advisory labels it “Improper input validation,” which is consistent with an under-validated length but understates that the sink is an out-of-bounds memory access.
std::span/std::array.Attack Path
- Peer / network attacker
establishes or injects into a WebRTC session that negotiates ULPFEC/FlexFEC so the victim’s receiver runs
ForwardErrorCorrectiondecode (inferred: requires FEC negotiated). - Craft FEC packet
sends a received FEC packet whose header fields (
protection_length,fec_header_size, or the embedded recovered-length at byte offset 2) describe more bytes than the packet actually contains. - Trigger recovery
loss/recovery logic enters
InitRecovery/FinishPacketRecovery, whichSetSizes a buffer and copies based on those attacker lengths. - Out-of-bounds access
the raw
memcpy/ByteReaderover the undersized buffer reads adjacent heap memory into the recovered packet or writes past it. - Primitive out-of-bounds read (potential info leak into recovered media) or out-of-bounds write in the renderer/network process; escalation to further corruption is (inferred).
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifmodules/rtp_rtcp/source/forward_error_correction.cc |
modified | |
formodules/rtp_rtcp/source/forward_error_correction.cc |
modified |
Files Changed
modules/rtp_rtcp/source/forward_error_correction.ccmodules/rtp_rtcp/source/fec_private_tables_bursty.hmodules/rtp_rtcp/source/fec_private_tables_bursty.ccmodules/rtp_rtcp/source/forward_error_correction_internal.ccunsafe_buffers_paths.txtmodules/rtp_rtcp/source/fec_private_tables_random.hmodules/rtp_rtcp/source/forward_error_correction.hmodules/rtp_rtcp/source/forward_error_correction_internal.hmodules/rtp_rtcp/test/testFec/test_fec.ccmodules/rtp_rtcp/source/fec_private_tables_bursty_unittest.ccmodules/rtp_rtcp/BUILD.gnmodules/rtp_rtcp/source/fec_private_tables_random.cc
Audit Directions
- Other RTP/RTCP parsersaudit remaining
const uint8_t*header parsers inmodules/rtp_rtcp(e.g. RTCP, red/ulpfec header readers) for fixed-offset reads without length checks, the same pattern spanified here. - FlexFEC/ULPFEC header readers
flexfec_03_header_reader_writerandulpfec_header_reader_writercomputefec_header_size/protection_length; verify those cannot exceed the packet before recovery copies use them. - Scratch-buffer fillssearch for
memset(buf, 0, count * size)/memcpyover fixed C arrays elsewhere in media wherecount*sizederives from packet-count math and could exceed the array. - Compile-time table sizinglook for other flattened constant tables declared
const uint8_t x[]whose consuming code assumes a hard-coded length, now guardable with thestatic_assert(back() != 0)idiom.
Patch
From 3efe1a3a90c14ce339e22c451d48f4f7e831c75b Mon Sep 17 00:00:00 2001 From: Danil Chapovalov <[email protected]> Date: Tue, 13 Oct 2026 11:00:54 +0200 Subject: [PATCH] Spanify and thus harden forward error correction code Bug: chromium:570927027 Change-Id: I36cc3771838fc6e0524a4c8a1e37528eb30d769e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/508300 Reviewed-by: Tomas Gunnarsson <[email protected]> Commit-Queue: Danil Chapovalov <[email protected]> Reviewed-by: Erik Språng <[email protected]> Cr-Commit-Position: refs/heads/main@{#48878} --- diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty.cc b/modules/rtp_rtcp/source/fec_private_tables_bursty.cc index 84a4857..52ddbef 100644 --- a/modules/rtp_rtcp/source/fec_private_tables_bursty.cc +++ b/modules/rtp_rtcp/source/fec_private_tables_bursty.cc @@ -10,6 +10,7 @@ #include "modules/rtp_rtcp/source/fec_private_tables_bursty.h" +#include <array> #include <cstdint> namespace webrtc { @@ -643,7 +644,7 @@ namespace fec_private_tables { -const uint8_t kPacketMaskBurstyTbl[] = { +constexpr std::array<uint8_t, kPacketMaskBurstyTblSize> kPacketMaskBurstyTbl = { 12, kPacketMaskBursty1, kPacketMaskBursty2, @@ -659,5 +660,11 @@ kPacketMaskBursty12, }; +// Check size is set correctly. If size is too small, compiler would warn there +// are excess elements in struct initializer. If size is too large, compiler +// would initialize unspecfied values with default value 0. Check size is not +// too large by checking last element wasn't default initialized to 0. +static_assert(kPacketMaskBurstyTbl.back() != 0); + } // namespace fec_private_tables } // namespace webrtc diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty.h b/modules/rtp_rtcp/source/fec_private_tables_bursty.h index 217d950..99729ea 100644 --- a/modules/rtp_rtcp/source/fec_private_tables_bursty.h +++ b/modules/rtp_rtcp/source/fec_private_tables_bursty.h @@ -25,12 +25,23 @@ // (i.e., more packets/symbols in the code, so larger (k,m), i.e., k > 4, // m > 3). -#include <stdint.h> +#include <array> +#include <cstddef> +#include <cstdint> namespace webrtc { namespace fec_private_tables { -extern const uint8_t kPacketMaskBurstyTbl[]; +// Size of the flattened table for up to N=12 media packets. +// The flattened table keeps 12 square tables sizes from 1 to 12. +// Sum of all squared numbers N^2 from 1 to 12: 650. +// Each line in each table is prepended by size. +// Sum of all numbers N from 1 to 12: 78 +// Each 2d table is prepended by its size, adding 12 more entries. +// Table itself is prepended by the number of subtables, adding 1 more entry. +// Total number of entries = 1 + 12 + 78 + 650 = 741. +inline constexpr size_t kPacketMaskBurstyTblSize = 741; +extern const std::array<uint8_t, kPacketMaskBurstyTblSize> kPacketMaskBurstyTbl; } // namespace fec_private_tables } // namespace webrtc diff --git a/modules/rtp_rtcp/source/fec_private_tables_random.cc b/modules/rtp_rtcp/source/fec_private_tables_random.cc index b5cd8bc..88bcb93 100644 --- a/modules/rtp_rtcp/source/fec_private_tables_random.cc +++ b/modules/rtp_rtcp/source/fec_private_tables_random.cc @@ -10,6 +10,7 @@ #include "modules/rtp_rtcp/source/fec_private_tables_random.h" +#include <array> #include <cstdint> namespace webrtc { @@ -643,7 +644,7 @@ namespace fec_private_tables { -const uint8_t kPacketMaskRandomTbl[] = { +constexpr std::array<uint8_t, kPacketMaskRandomTblSize> kPacketMaskRandomTbl = { 12, kPacketMaskRandom1, // 2 byte entries. kPacketMaskRandom2, @@ -659,5 +660,11 @@ kPacketMaskRandom12, }; +// Check size is set correctly. If size is too small, compiler would warn there +// are excess elements in struct initializer. If size is too large, compiler +// would initialize unspecfied values with default value 0. Check size is not +// too large by checking last element wasn't default initialized to 0. +static_assert(kPacketMaskRandomTbl.back() != 0); + } // namespace fec_private_tables } // namespace webrtc diff --git a/modules/rtp_rtcp/source/fec_private_tables_random.h b/modules/rtp_rtcp/source/fec_private_tables_random.h index cc7b929..674ff06 100644 --- a/modules/rtp_rtcp/source/fec_private_tables_random.h +++ b/modules/rtp_rtcp/source/fec_private_tables_random.h @@ -15,12 +15,23 @@ // this table are specifically designed to favor recovery to random loss. // These packet masks are defined to protect up to maximum of 48 media packets. -#include <stdint.h> +#include <array> +#include <cstddef> +#include <cstdint> namespace webrtc { namespace fec_private_tables { -extern const uint8_t kPacketMaskRandomTbl[]; +// Size of the flattened table for up to N=12 media packets. +// The flattened table keeps 12 square tables sizes from 1 to 12. +// Sum of all squared numbers N^2 from 1 to 12: 650. +// Each line in each table is prepended by its size. +// Sum of all numbers N from 1 to 12: 78 +// Each 2d table is prepended by its size, adding 12 more entries. +// Table itself is prepended by the number of subtables, adding 1 more entry. +// Total number of entries = 1 + 12 + 78 + 650 = 741. +inline constexpr size_t kPacketMaskRandomTblSize = 741; +extern const std::array<uint8_t, kPacketMaskRandomTblSize> kPacketMaskRandomTbl; } // namespace fec_private_tables } // namespace webrtc diff --git a/modules/rtp_rtcp/source/forward_error_correction.cc b/modules/rtp_rtcp/source/forward_error_correction.cc index 0bb81a8..0e31bf1 100644 --- a/modules/rtp_rtcp/source/forward_error_correction.cc +++ b/modules/rtp_rtcp/source/forward_error_correction.cc @@ -15,6 +15,7 @@ #include <cstring> #include <list> #include <memory> +#include <span> #include <utility> #include <vector> @@ -26,6 +27,7 @@ #include "modules/rtp_rtcp/source/flexfec_03_header_reader_writer.h" #include "modules/rtp_rtcp/source/forward_error_correction_internal.h" #include "modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" +#include "rtc_base/byte_order.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/mod_ops.h" @@ -167,7 +169,9 @@ internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); packet_mask_size_ = internal::PacketMaskSize(num_media_packets); - memset(packet_masks_, 0, num_fec_packets * packet_mask_size_); + std::ranges::fill( + std::span(packet_masks_).first(num_fec_packets * packet_mask_size_), 0); + internal::GeneratePacketMasks(num_media_packets, num_fec_packets, num_important_packets, use_unequal_protection, &mask_table, packet_masks_); @@ -186,9 +190,9 @@ GenerateFecPayloads(media_packets, num_fec_packets); // TODO(brandtr): Generalize this when multistream protection support is // added. - const uint32_t media_ssrc = ParseSsrc(media_packets.front()->data.data()); + const uint32_t media_ssrc = ParseSsrc(media_packets.front()->data); const uint16_t seq_num_base = - ParseSequenceNumber(media_packets.front()->data.data()); + ParseSequenceNumber(media_packets.front()->data); FinalizeFecHeaders(num_fec_packets, media_ssrc, seq_num_base); return 0; @@ -220,8 +224,7 @@ size_t media_pkt_idx = 0; auto media_packets_it = media_packets.cbegin(); - uint16_t prev_seq_num = - ParseSequenceNumber((*media_packets_it)->data.data()); + uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data); while (media_packets_it != media_packets.end()) { Packet* const media_packet = media_packets_it->get(); // Should `media_packet` be protected by `fec_packet`? @@ -233,8 +236,8 @@ if (fec_packet_length > fec_packet->data.size()) { size_t old_size = fec_packet->data.size(); fec_packet->data.SetSize(fec_packet_length); - memset(fec_packet->data.MutableData() + old_size, 0, - fec_packet_length - old_size); + std::ranges::fill(fec_packet->data.AsMutableSpan().subspan(old_size), + 0); } XorHeaders(*media_packet, fec_packet); XorPayloads(*media_packet, media_payload_length, fec_header_size, @@ -242,8 +245,7 @@ } media_packets_it++; if (media_packets_it != media_packets.end()) { - uint16_t seq_num = - ParseSequenceNumber((*media_packets_it)->data.data()); + uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); prev_seq_num = seq_num; } @@ -262,10 +264,8 @@ if (num_media_packets <= 1) { return num_media_packets; } - uint16_t last_seq_num = - ParseSequenceNumber(media_packets.back()->data.data()); - uint16_t first_seq_num = - ParseSequenceNumber(media_packets.front()->data.data()); + uint16_t last_seq_num = ParseSequenceNumber(media_packets.back()->data); + uint16_t first_seq_num = ParseSequenceNumber(media_packets.front()->data); size_t total_missing_seq_nums = static_cast<uint16_t>(last_seq_num - first_seq_num) - num_media_packets + 1; @@ -281,7 +281,9 @@ // Allocate the new mask. size_t tmp_packet_mask_size = internal::PacketMaskSize(total_missing_seq_nums + num_media_packets); - memset(tmp_packet_masks_, 0, num_fec_packets * tmp_packet_mask_size); + std::ranges::fill(std::span(tmp_packet_masks_) + .first(num_fec_packets * tmp_packet_mask_size), + 0); auto media_packets_it = media_packets.cbegin(); uint16_t prev_seq_num = first_seq_num; @@ -298,7 +300,7 @@ // We can only cover up to 48 packets. break; } - uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data.data()); + uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); const int num_zeros_to_insert = static_cast<uint16_t>(seq_num - prev_seq_num - 1); if (num_zeros_to_insert > 0) { @@ -323,8 +325,9 @@ } } // Replace the old mask with the new. - memcpy(packet_masks_, tmp_packet_masks_, - num_fec_packets * tmp_packet_mask_size); + std::ranges::copy(std::span(tmp_packet_masks_) + .first(num_fec_packets * tmp_packet_mask_size), + packet_masks_.begin()); return new_bit_index; } @@ -565,20 +568,19 @@ } // Initialize recovered packet data. recovered_packet->pkt->data.EnsureCapacity(IP_PACKET_SIZE); - recovered_packet->pkt->data.SetSize(fec_packet.protection_length + - kRtpHeaderSize); + recovered_packet->returned = false; recovered_packet->was_recovered = true; // Copy bytes corresponding to minimum RTP header size. // Note that the sequence number and SSRC fields will be overwritten // at the end of packet recovery. - memcpy(recovered_packet->pkt->data.MutableData(), - fec_packet.pkt->data.cdata(), kRtpHeaderSize); + recovered_packet->pkt->data.Set( + std::span(fec_packet.pkt->data).first(kRtpHeaderSize)); // Copy remaining FEC payload. if (fec_packet.protection_length > 0) { - memcpy(recovered_packet->pkt->data.MutableData() + kRtpHeaderSize, - fec_packet.pkt->data.cdata() + fec_packet.fec_header_size, - fec_packet.protection_length); + recovered_packet->pkt->data.Append( + std::span(fec_packet.pkt->data) + .subspan(fec_packet.fec_header_size, fec_packet.protection_length)); } return true; } @@ -586,13 +588,12 @@ bool ForwardErrorCorrection::FinishPacketRecovery( const ReceivedFecPacket& /* fec_packet */, RecoveredPacket* recovered_packet) { - uint8_t* data = recovered_packet->pkt->data.MutableData(); + std::span<uint8_t> data = recovered_packet->pkt->data.AsMutableSpan(); // Set the RTP version to 2. data[0] |= 0x80; // Set the 1st bit. data[0] &= 0xbf; // Clear the 2nd bit. // Recover the packet length, from temporary location. - const size_t new_size = - ByteReader<uint16_t>::ReadBigEndian(&data[2]) + kRtpHeaderSize; + const size_t new_size = GetBE16(data.subspan(2)) + kRtpHeaderSize; if (new_size > size_t{IP_PACKET_SIZE - kRtpHeaderSize}) { RTC_LOG(LS_WARNING) << "The recovered packet had a length larger than a " "typical IP packet, and is thus dropped."; @@ -600,21 +601,21 @@ } size_t old_size = recovered_packet->pkt->data.size(); recovered_packet->pkt->data.SetSize(new_size); - data = recovered_packet->pkt->data.MutableData(); + data = recovered_packet->pkt->data.AsMutableSpan(); if (new_size > old_size) { - memset(data + old_size, 0, new_size - old_size); + std::ranges::fill(data.subspan(old_size), 0); } // Set the SN field. - ByteWriter<uint16_t>::WriteBigEndian(&data[2], recovered_packet->seq_num); + SetBE16(data.subspan(2), recovered_packet->seq_num); // Set the SSRC field. - ByteWriter<uint32_t>::WriteBigEndian(&data[8], recovered_packet->ssrc); + SetBE32(data.subspan(8), recovered_packet->ssrc); return true; } void ForwardErrorCorrection::XorHeaders(const Packet& src, Packet* dst) { - uint8_t* dst_data = dst->data.MutableData(); - const uint8_t* src_data = src.data.cdata(); + std::span<uint8_t> dst_data = dst->data.AsMutableSpan(); + std::span<const uint8_t> src_data = src.data; // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields. dst_data[0] ^= src_data[0]; dst_data[1] ^= src_data[1]; @@ -644,12 +645,11 @@ RTC_DCHECK_LE(dst_offset + payload_length, dst->data.capacity()); if (dst_offset + payload_length > dst->data.size()) { size_t old_size = dst->data.size(); - size_t new_size = dst_offset + payload_length; - dst->data.SetSize(new_size); - memset(dst->data.MutableData() + old_size, 0, new_size - old_size); + dst->data.SetSize(dst_offset + payload_length); + std::ranges::fill(dst->data.AsMutableSpan().subspan(old_size), 0); } - uint8_t* dst_data = dst->data.MutableData(); - const uint8_t* src_data = src.data.cdata(); + std::span<uint8_t> dst_data = dst->data.AsMutableSpan(); + std::span<const uint8_t> src_data = src.data; for (size_t i = 0; i < payload_length; ++i) { dst_data[dst_offset + i] ^= src_data[kRtpHeaderSize + i]; } @@ -774,12 +774,13 @@ kOldSequenceThreshold); } -uint16_t ForwardErrorCorrection::ParseSequenceNumber(const uint8_t* packet) { - return (packet[2] << 8) + packet[3]; +uint16_t ForwardErrorCorrection::ParseSequenceNumber( + std::span<const uint8_t> packet) { + return GetBE16(packet.subspan(2)); } -uint32_t ForwardErrorCorrection::ParseSsrc(const uint8_t* packet) { - return (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11]; +uint32_t ForwardErrorCorrection::ParseSsrc(std::span<const uint8_t> packet) { + return GetBE32(packet.subspan(8)); } ForwardErrorCorrection::DecodeFecResult ForwardErrorCorrection::DecodeFec( diff --git a/modules/rtp_rtcp/source/forward_error_correction.h b/modules/rtp_rtcp/source/forward_error_correction.h index fcfa641..a50064bc 100644 --- a/modules/rtp_rtcp/source/forward_error_correction.h +++ b/modules/rtp_rtcp/source/forward_error_correction.h @@ -14,6 +14,7 @@ #include <stddef.h> #include <stdint.h> +#include <array> #include <list> #include <memory> #include <span> @@ -250,8 +251,8 @@ // TODO(brandtr): Remove these functions when the Packet classes // have been refactored. - static uint16_t ParseSequenceNumber(const uint8_t* packet); - static uint32_t ParseSsrc(const uint8_t* packet); + static uint16_t ParseSequenceNumber(std::span<const uint8_t> packet); + static uint32_t ParseSsrc(std::span<const uint8_t> packet); protected: ForwardErrorCorrection(std::unique_ptr<FecHeaderReader> fec_header_reader, @@ -363,8 +364,10 @@ // Arrays used to avoid dynamically allocating memory when generating // the packet masks. // (There are never more than `kUlpfecMaxMediaPackets` FEC packets generated.) - uint8_t packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize]; - uint8_t tmp_packet_masks_[kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize]; + std::array<uint8_t, kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize> + packet_masks_; + std::array<uint8_t, kUlpfecMaxMediaPackets * kUlpfecMaxPacketMaskSize> + tmp_packet_masks_; size_t packet_mask_size_; };
Regression Test / PoC
diff --git a/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc b/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc
index b14e2fb..bda185c 100644
--- a/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc
+++ b/modules/rtp_rtcp/source/fec_private_tables_bursty_unittest.cc
@@ -10,6 +10,7 @@
#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
+#include <array>
#include <cstddef>
#include <cstdint>
#include <span>
@@ -21,8 +22,8 @@
namespace webrtc {
namespace {
-constexpr uint8_t kMaskRandom15_6[] = {0x82, 0x08, 0x41, 0x04, 0x20, 0x82,
- 0x10, 0x40, 0x08, 0x20, 0x04, 0x10};
+constexpr std::array<uint8_t, 12> kMaskRandom15_6 = {
+ 0x82, 0x08, 0x41, 0x04, 0x20, 0x82, 0x10, 0x40, 0x08, 0x20, 0x04, 0x10};
} // namespace
namespace fec_private_tables {
@@ -31,24 +32,24 @@
TEST(FecTable, TestBurstyLookup) {
std::span<const uint8_t> result;
- result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 0, 0);
+ result = LookUpInFecTable(kPacketMaskBurstyTbl, 0, 0);
// Should match kMaskBursty1_1.
EXPECT_EQ(2u, result.size());
EXPECT_EQ(0x80u, result[0]);
- result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 3, 0);
+ result = LookUpInFecTable(kPacketMaskBurstyTbl, 3, 0);
// Should match kMaskBursty4_1.
EXPECT_EQ(2u, result.size());
EXPECT_EQ(0xf0u, result[0]);
EXPECT_EQ(0x00u, result[1]);
- result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 1, 1);
+ result = LookUpInFecTable(kPacketMaskBurstyTbl, 1, 1);
// Should match kMaskBursty2_2.
EXPECT_EQ(4u, result.size());
EXPECT_EQ(0x80u, result[0]);
EXPECT_EQ(0xc0u, result[2]);
- result = LookUpInFecTable(&kPacketMaskBurstyTbl[0], 11, 11);
+ result = LookUpInFecTable(kPacketMaskBurstyTbl, 11, 11);
// Should match kMaskBursty12_12.
EXPECT_EQ(24u, result.size());
EXPECT_EQ(0x80u, result[0]);
@@ -57,12 +58,12 @@
TEST(FecTable, TestRandomLookup) {
std::span<const uint8_t> result;
- result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 0, 0);
+ result = LookUpInFecTable(kPacketMaskRandomTbl, 0, 0);
EXPECT_EQ(2u, result.size());
EXPECT_EQ(0x80u, result[0]);
EXPECT_EQ(0x00u, result[1]);
- result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 4, 1);
+ result = LookUpInFecTable(kPacketMaskRandomTbl, 4, 1);
// kMaskRandom5_2.
EXPECT_EQ(4u, result.size());
EXPECT_EQ(0xa8u, result[0]);
diff --git a/modules/rtp_rtcp/test/testFec/test_fec.cc b/modules/rtp_rtcp/test/testFec/test_fec.cc
index 067fa0c..2f66abf 100644
--- a/modules/rtp_rtcp/test/testFec/test_fec.cc
+++ b/modules/rtp_rtcp/test/testFec/test_fec.cc
@@ -13,12 +13,14 @@
* functions in ForwardErrorCorrection directly.
*/
+#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <list>
#include <memory>
+#include <span>
#include <string>
#include <utility>
#include <vector>
@@ -168,8 +170,7 @@
mask_type_idx);
const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx];
- std::unique_ptr<uint8_t[]> packet_mask(
- new uint8_t[packet_mask_max * kNumMaskBytesL1]);
+ std::vector<uint8_t> packet_mask(packet_mask_max * kNumMaskBytesL1);
FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
@@ -194,13 +195,15 @@
const uint32_t mask_bytes_per_fec_packet =
(num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
- memset(packet_mask.get(), 0,
- num_media_packets * mask_bytes_per_fec_packet);
+ std::ranges::fill(
+ std::span(packet_mask)
+ .first(num_media_packets * mask_bytes_per_fec_packet),
+ 0);
// Transfer packet masks from bit-mask to byte-mask.
internal::GeneratePacketMasks(
num_media_packets, num_fec_packets, num_imp_packets,
- kUseUnequalProtection, &mask_table, packet_mask.get());
+ kUseUnequalProtection, &mask_table, packet_mask);
#ifdef VERBOSE_OUTPUT
printf(