Index: webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc |
diff --git a/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc b/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc |
index bb2418c81a46a29dc1e40f2dcab0c0364999a6ef..5c3cfcba289b44103b7326cfc8b09c11f2fa7ead 100644 |
--- a/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc |
+++ b/webrtc/test/fuzzers/transport_feedback_packet_loss_tracker_fuzzer.cc |
@@ -44,90 +44,174 @@ size_t FuzzInRange(const uint8_t** data, |
class TransportFeedbackGenerator { |
public: |
- explicit TransportFeedbackGenerator(rtc::ArrayView<const uint8_t> data) |
- : data_(data), ended_(false), data_idx_(0) {} |
+ explicit TransportFeedbackGenerator(const uint8_t** data, size_t* size) |
+ : data_(data), size_(size) {} |
- void GetNextTransportFeedback(rtcp::TransportFeedback* feedback) { |
+ bool GetNextTransportFeedback(rtcp::TransportFeedback* feedback) { |
uint16_t base_seq_num = 0; |
if (!ReadData<uint16_t>(&base_seq_num)) { |
- return; |
+ return false; |
} |
- |
- const int64_t kBaseTimeUs = 1234; // Irrelevant to this test. |
+ constexpr int64_t kBaseTimeUs = 1234; // Irrelevant to this test. |
feedback->SetBase(base_seq_num, kBaseTimeUs); |
- uint16_t num_statuses = 0; |
- if (!ReadData<uint16_t>(&num_statuses)) |
- return; |
- num_statuses = std::max<uint16_t>(num_statuses, 1); |
+ uint16_t remaining_packets = 0; |
+ if (!ReadData<uint16_t>(&remaining_packets)) |
+ return false; |
+ // Range is [0x00001 : 0x10000], but we keep it 0x0000 to 0xffff for now, |
+ // and add the last status as RECEIVED. That is because of a limitation |
+ // that says that the last status cannot be LOST. |
uint16_t seq_num = base_seq_num; |
- while (true) { |
+ while (remaining_packets > 0) { |
uint8_t status_byte = 0; |
- if (!ReadData<uint8_t>(&status_byte)) |
- return; |
+ if (!ReadData<uint8_t>(&status_byte)) { |
+ return false; |
+ } |
// Each status byte contains 8 statuses. |
- for (size_t j = 0; j < 8; ++j) { |
- if (status_byte & 0x01) { |
+ for (size_t i = 0; i < 8 && remaining_packets > 0; ++i) { |
+ const bool received = (status_byte & (0x01 << i)); |
+ if (received) { |
feedback->AddReceivedPacket(seq_num, kBaseTimeUs); |
} |
- seq_num++; |
- if (seq_num >= base_seq_num + num_statuses) { |
- feedback->AddReceivedPacket(seq_num, kBaseTimeUs); |
- return; |
- } |
- status_byte >>= 1; |
+ ++seq_num; |
+ --remaining_packets; |
} |
} |
- } |
- bool ended() const { return ended_; } |
+ // As mentioned above, all feedbacks must report with a received packet. |
+ feedback->AddReceivedPacket(seq_num, kBaseTimeUs); |
+ |
+ return true; |
+ } |
private: |
template <typename T> |
bool ReadData(T* value) { |
- RTC_CHECK(!ended_); |
- if (data_idx_ + sizeof(T) > data_.size()) { |
- ended_ = true; |
+ if (*size_ < sizeof(T)) { |
return false; |
+ } else { |
+ *value = FuzzInput<T>(data_, size_); |
+ return true; |
} |
- *value = ByteReader<T>::ReadBigEndian(&data_[data_idx_]); |
- data_idx_ += sizeof(T); |
- return true; |
} |
- const rtc::ArrayView<const uint8_t> data_; |
- bool ended_; |
- size_t data_idx_; |
+ const uint8_t** data_; |
+ size_t* size_; |
}; |
-} // namespace |
- |
-void FuzzOneInput(const uint8_t* data, size_t size) { |
- if (size < 3 * sizeof(uint16_t)) { |
- return; |
+bool Setup(const uint8_t** data, |
+ size_t* size, |
+ std::unique_ptr<TransportFeedbackPacketLossTracker>* tracker) { |
+ if (*size < 3 * sizeof(uint16_t)) { |
+ return false; |
} |
+ |
constexpr size_t kSeqNumHalf = 0x8000u; |
// 0x8000 >= max_window_size >= plr_min_num_packets > rplr_min_num_pairs >= 1 |
// (The distribution isn't uniform, but it's enough; more would be overkill.) |
- const size_t max_window_size = FuzzInRange(&data, &size, 2, kSeqNumHalf); |
+ const size_t max_window_size = FuzzInRange(data, size, 2, kSeqNumHalf); |
const size_t plr_min_num_packets = |
- FuzzInRange(&data, &size, 2, max_window_size); |
+ FuzzInRange(data, size, 2, max_window_size); |
const size_t rplr_min_num_pairs = |
- FuzzInRange(&data, &size, 1, plr_min_num_packets - 1); |
+ FuzzInRange(data, size, 1, plr_min_num_packets - 1); |
- TransportFeedbackPacketLossTracker tracker( |
- max_window_size, plr_min_num_packets, rplr_min_num_pairs); |
+ tracker->reset(new TransportFeedbackPacketLossTracker( |
+ max_window_size, plr_min_num_packets, rplr_min_num_pairs)); |
- TransportFeedbackGenerator feedback_generator( |
- rtc::ArrayView<const uint8_t>(data, size)); |
+ return true; |
+} |
+ |
+bool FuzzSequenceNumberDelta(const uint8_t** data, |
+ size_t* size, |
+ uint16_t* delta) { |
+ // Fuzz with a higher likelihood for immediately consecutive pairs |
+ // than you would by just fuzzing 1-256. |
+ // Note: Values higher than 256 still possible, but that would be in a new |
+ // packet-sending block. |
+ // * Fuzzed value in [0 : 127] (50% chance) -> delta is 1. |
+ // * Fuzzed value in [128 : 255] (50% chance) -> delta in range [2 : 129]. |
+ if (*size < sizeof(uint8_t)) { |
+ return false; |
+ } |
+ uint8_t fuzzed = FuzzInput<uint8_t>(data, size); |
+ *delta = (fuzzed < 128) ? 1 : (fuzzed - 128 + 2); |
+ return true; |
+} |
+ |
+bool FuzzPacketSendBlock( |
+ std::unique_ptr<TransportFeedbackPacketLossTracker>& tracker, |
+ const uint8_t** data, |
+ size_t* size) { |
+ // We want to test with block lengths between 1 and 2^16, inclusive. |
+ if (*size < sizeof(uint8_t)) { |
+ return false; |
+ } |
+ size_t packet_block_len = 1 + FuzzInput<uint8_t>(data, size); |
- while (!feedback_generator.ended()) { |
+ // First sent sequence number uniformly selected. |
+ if (*size < sizeof(uint16_t)) { |
+ return false; |
+ } |
+ uint16_t seq_num = FuzzInput<uint16_t>(data, size); |
+ tracker->OnPacketAdded(seq_num); |
+ tracker->Validate(); |
+ |
+ for (size_t i = 1; i < packet_block_len; i++) { |
+ uint16_t delta; |
+ bool may_continue = FuzzSequenceNumberDelta(data, size, &delta); |
+ if (!may_continue) |
+ return false; |
+ seq_num += delta; |
+ tracker->OnPacketAdded(seq_num); |
+ tracker->Validate(); |
+ } |
+ |
+ return true; |
+} |
+ |
+bool FuzzTransportFeedbackBlock( |
+ std::unique_ptr<TransportFeedbackPacketLossTracker>& tracker, |
+ const uint8_t** data, |
+ size_t* size) { |
+ // Fuzz the number of back-to-back feedbacks. At least one, or this would |
+ // be meaningless - we'd go straight back to fuzzing another packet |
+ // transmission block. |
+ if (*size < sizeof(uint8_t)) { |
+ return false; |
+ } |
+ |
+ size_t feedbacks_num = 1 + (FuzzInput<uint8_t>(data, size) & 0x3f); |
+ TransportFeedbackGenerator feedback_generator(data, size); |
+ |
+ for (size_t i = 0; i < feedbacks_num; i++) { |
rtcp::TransportFeedback feedback; |
- feedback_generator.GetNextTransportFeedback(&feedback); |
- tracker.OnReceivedTransportFeedback(feedback); |
- tracker.Validate(); |
+ bool may_continue = feedback_generator.GetNextTransportFeedback(&feedback); |
+ if (!may_continue) { |
+ return false; |
+ } |
+ tracker->OnReceivedTransportFeedback(feedback); |
+ tracker->Validate(); |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+void FuzzOneInput(const uint8_t* data, size_t size) { |
+ std::unique_ptr<TransportFeedbackPacketLossTracker> tracker; |
+ bool may_continue; |
+ |
+ may_continue = Setup(&data, &size, &tracker); |
+ |
+ while (may_continue) { |
+ may_continue = FuzzPacketSendBlock(tracker, &data, &size); |
+ if (!may_continue) { |
+ return; |
+ } |
+ may_continue = FuzzTransportFeedbackBlock(tracker, &data, &size); |
} |
} |