mkvmuxer: Keep Segment in a good state when frame writes fail

The problem in WriteFramesAll manifests as a null pointer dereference,
while the problem in WriteFramesLessThan manifests as a use-after-free.

When multiple audio frames are queued in the Segment and a call to
WriteFramesAll or WriteFramesLessThan fails partway through, there
may be null frames left in the Segment frame queue.

This is fixed by dropping the invalid frames and continuing so that the
queue is in a good state after a call, even if it fails.

Found through fuzzing mkvmuxer.

Minimal reproduction case for issue with WriteFramesAll.

 #include <stdint.h>

 #include "mkvmuxer/mkvmuxer.h"
 #include "mkvmuxer/mkvwriter.h"

int main() {
  mkvmuxer::MkvWriter writer;

  mkvmuxer::Segment segment;

  uint64_t video_track = segment.AddVideoTrack(1, 1, 0);
  uint64_t audio_track = segment.AddAudioTrack(1, 1, 0);

  uint8_t data[] = {0};
  segment.AddFrame(data, 1, audio_track, 395136991333ULL, false);
  segment.AddFrame(data, 1, audio_track, 18374686479674129407ULL, false);
  segment.AddFrame(data, 1, video_track, 18446462628926195463ULL, false);


The second audio frame has an invalid timestamp that is only caught in
WriteFrame from , causing WriteFramesAll to fail on
writing the second audio frame when the first video frame forces a new

WriteFramesLessThan has a similar pattern, where failing partway through
a write can leave the Segment in a bad state.

Bug: b/174070314
Test: clang++ *.cc repro.cpp -I.. -o repro -fsanitize=address -g && ./repro
Change-Id: I05c707477e454752776c7571aff9f24f22195d55
1 file changed