--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -757,16 +757,17 @@ MP4MetadataRust::Init()
{
mp4parse_io io = { read_source, &mRustSource };
mRustParser.reset(mp4parse_new(&io));
MOZ_ASSERT(mRustParser);
if (MOZ_LOG_TEST(sLog, LogLevel::Debug)) {
mp4parse_log(true);
}
+ mp4parse_fallible_allocation(true);
mp4parse_status rv = mp4parse_read(mRustParser.get());
MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv));
Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS,
rv == mp4parse_status_OK);
if (rv != mp4parse_status_OK && rv != mp4parse_status_TABLE_TOO_LARGE) {
MOZ_LOG(sLog, LogLevel::Info, ("Rust mp4 parser fails to parse this stream."));
MOZ_ASSERT(rv > 0);
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/fallible/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "fallible"
+version = "0.0.1"
+authors = ["The Servo Project Developers"]
+license = "MPL-2.0"
+publish = false
+
+[lib]
+name = "fallible"
+path = "lib.rs"
+
+[dependencies]
+smallvec = "0.4"
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/fallible/lib.rs
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::mem;
+use std::vec::Vec;
+
+extern "C" {
+ fn realloc(ptr: *mut u8, bytes: usize) -> *mut u8;
+ fn malloc(bytes: usize) -> *mut u8;
+}
+
+pub trait FallibleVec<T> {
+ /// Append |val| to the end of |vec|. Returns Ok(()) on success,
+ /// Err(()) if it fails, which can only be due to lack of memory.
+ fn try_push(&mut self, value: T) -> Result<(), ()>;
+
+ /// Expand the vector size. Return Ok(()) on success, Err(()) if it
+ /// fails.
+ fn try_reserve(&mut self, new_cap: usize) -> Result<(), ()>;
+}
+
+/////////////////////////////////////////////////////////////////
+// Vec
+
+impl<T> FallibleVec<T> for Vec<T> {
+ #[inline]
+ fn try_push(&mut self, val: T) -> Result<(), ()> {
+ if self.capacity() == self.len() {
+ let old_cap: usize = self.capacity();
+ let new_cap: usize
+ = if old_cap == 0 { 4 } else { old_cap.checked_mul(2).ok_or(()) ? };
+
+ try_extend_vec(self, new_cap)?;
+ debug_assert!(self.capacity() > self.len());
+ }
+ self.push(val);
+ Ok(())
+ }
+
+ #[inline]
+ fn try_reserve(&mut self, cap: usize) -> Result<(), ()> {
+ let new_cap = cap + self.capacity();
+ try_extend_vec(self, new_cap)?;
+ debug_assert!(self.capacity() == new_cap);
+ Ok(())
+ }
+}
+
+#[inline(never)]
+#[cold]
+fn try_extend_vec<T>(vec: &mut Vec<T>, new_cap: usize) -> Result<(), ()> {
+ let old_ptr = vec.as_mut_ptr();
+ let old_len = vec.len();
+
+ let old_cap: usize = vec.capacity();
+
+ if old_cap > new_cap {
+ return Ok(());
+ }
+
+ let new_size_bytes
+ = new_cap.checked_mul(mem::size_of::<T>()).ok_or(()) ? ;
+
+ let new_ptr = unsafe {
+ if old_cap == 0 {
+ malloc(new_size_bytes)
+ } else {
+ realloc(old_ptr as *mut u8, new_size_bytes)
+ }
+ };
+
+ if new_ptr.is_null() {
+ return Err(());
+ }
+
+ let new_vec = unsafe {
+ Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap)
+ };
+
+ mem::forget(mem::replace(vec, new_vec));
+ Ok(())
+}
+
+#[test]
+fn oom_test() {
+ let mut vec: Vec<char> = Vec::new();
+ match vec.try_reserve(std::usize::MAX) {
+ Ok(_) => panic!("it should be OOM"),
+ _ => (),
+ }
+}
--- a/media/libstagefright/binding/include/mp4parse.h
+++ b/media/libstagefright/binding/include/mp4parse.h
@@ -19,16 +19,17 @@ extern "C" {
typedef enum mp4parse_status {
mp4parse_status_OK = 0,
mp4parse_status_BAD_ARG = 1,
mp4parse_status_INVALID = 2,
mp4parse_status_UNSUPPORTED = 3,
mp4parse_status_EOF = 4,
mp4parse_status_IO = 5,
mp4parse_status_TABLE_TOO_LARGE = 6,
+ mp4parse_status_OOM = 7,
} mp4parse_status;
typedef enum mp4parse_track_type {
mp4parse_track_type_VIDEO = 0,
mp4parse_track_type_AUDIO = 1,
} mp4parse_track_type;
typedef enum mp4parse_codec {
@@ -113,16 +114,18 @@ typedef struct mp4parse_io {
mp4parse_parser* mp4parse_new(mp4parse_io const* io);
/// Free an `mp4parse_parser*` allocated by `mp4parse_new()`.
void mp4parse_free(mp4parse_parser* parser);
/// Enable `mp4_parser` log.
void mp4parse_log(bool enable);
+void mp4parse_fallible_allocation(bool enable);
+
/// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
mp4parse_status mp4parse_read(mp4parse_parser* parser);
/// Return the number of tracks parsed by previous `mp4parse_read()` call.
mp4parse_status mp4parse_get_track_count(mp4parse_parser const* parser, uint32_t* count);
/// Fill the supplied `mp4parse_track_info` with metadata for `track`.
mp4parse_status mp4parse_get_track_info(mp4parse_parser* parser, uint32_t track_index, mp4parse_track_info* info);
--- a/media/libstagefright/binding/mp4parse-cargo.patch
+++ b/media/libstagefright/binding/mp4parse-cargo.patch
@@ -1,28 +1,30 @@
diff --git a/media/libstagefright/binding/mp4parse/Cargo.toml b/media/libstagefright/binding/mp4parse/Cargo.toml
index ff9422c..814c4c6 100644
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
-@@ -20,19 +20,11 @@ exclude = [
+@@ -20,20 +20,12 @@ exclude = [
]
-[badges]
-travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
[dependencies]
-byteorder = "1.0.0"
-afl = { version = "0.1.1", optional = true }
-afl-plugin = { version = "0.1.1", optional = true }
-abort_on_panic = { version = "1.0.0", optional = true }
-bitreader = { version = "0.3.0" }
-num-traits = "0.1.37"
+-fallible = { path = "../fallible" }
+byteorder = "1.0.0"
+bitreader = { version = "0.3.0" }
+num-traits = "0.1.37"
++fallible = { path = "../fallible" }
[dev-dependencies]
test-assembler = "0.1.2"
-[features]
-fuzz = ["afl", "afl-plugin", "abort_on_panic"]
-
# Somewhat heavy-handed, but we want at least -Z force-overflow-checks=on.
--- a/media/libstagefright/binding/mp4parse/Cargo.toml
+++ b/media/libstagefright/binding/mp4parse/Cargo.toml
@@ -19,12 +19,13 @@ exclude = [
"*.mp4",
]
[dependencies]
byteorder = "1.0.0"
bitreader = { version = "0.3.0" }
num-traits = "0.1.37"
+fallible = { path = "../fallible" }
[dev-dependencies]
test-assembler = "0.1.2"
--- a/media/libstagefright/binding/mp4parse/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse/src/lib.rs
@@ -6,43 +6,50 @@
#![cfg_attr(feature = "fuzz", feature(plugin))]
#![cfg_attr(feature = "fuzz", plugin(afl_plugin))]
#[cfg(feature = "fuzz")]
extern crate afl;
extern crate byteorder;
extern crate bitreader;
extern crate num_traits;
+extern crate fallible;
use byteorder::{ReadBytesExt, WriteBytesExt};
use bitreader::{BitReader, ReadInto};
use std::io::{Read, Take};
use std::io::Cursor;
use std::cmp;
use num_traits::Num;
+use fallible::FallibleVec;
mod boxes;
use boxes::{BoxType, FourCC};
// Unit tests.
#[cfg(test)]
mod tests;
// Arbitrary buffer size limit used for raw read_bufs on a box.
const BUF_SIZE_LIMIT: usize = 1024 * 1024;
// Max table length. Calculating in worth case for one week long video, one
// frame per table entry in 30 fps.
-#[cfg(target_pointer_width = "64")]
const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24 * 7;
-// Reduce max table length if it is in 32 arch for memory problem.
-#[cfg(target_pointer_width = "32")]
-const TABLE_SIZE_LIMIT: u32 = 30 * 60 * 60 * 24;
+static DEBUG_MODE: std::sync::atomic::AtomicBool = std::sync::atomic::ATOMIC_BOOL_INIT;
+
+static FALLIBLE_ALLOCATION: std::sync::atomic::AtomicBool = std::sync::atomic::ATOMIC_BOOL_INIT;
-static DEBUG_MODE: std::sync::atomic::AtomicBool = std::sync::atomic::ATOMIC_BOOL_INIT;
+pub fn set_fallible_allocation_mode(fallible: bool) {
+ FALLIBLE_ALLOCATION.store(fallible, std::sync::atomic::Ordering::SeqCst);
+}
+
+fn get_fallible_allocation_mode() -> bool {
+ FALLIBLE_ALLOCATION.load(std::sync::atomic::Ordering::Relaxed)
+}
pub fn set_debug_mode(mode: bool) {
DEBUG_MODE.store(mode, std::sync::atomic::Ordering::SeqCst);
}
#[inline(always)]
fn get_debug_mode() -> bool {
DEBUG_MODE.load(std::sync::atomic::Ordering::Relaxed)
@@ -51,16 +58,47 @@ fn get_debug_mode() -> bool {
macro_rules! log {
($($args:tt)*) => (
if get_debug_mode() {
println!( $( $args )* );
}
)
}
+// TODO: vec_push() and vec_reserve() needs to be replaced when Rust supports
+// fallible memory allocation in raw_vec.
+pub fn vec_push<T>(vec: &mut Vec<T>, val: T) -> std::result::Result<(), ()> {
+ if get_fallible_allocation_mode() {
+ return vec.try_push(val);
+ }
+
+ vec.push(val);
+ Ok(())
+}
+
+pub fn vec_reserve<T>(vec: &mut Vec<T>, size: usize) -> std::result::Result<(), ()> {
+ if get_fallible_allocation_mode() {
+ return vec.try_reserve(size);
+ }
+
+ vec.reserve(size);
+ Ok(())
+}
+
+fn reserve_read_buf(size: usize) -> std::result::Result<Vec<u8>, ()> {
+ if get_fallible_allocation_mode() {
+ let mut buf: Vec<u8> = Vec::new();
+ buf.try_reserve(size)?;
+ unsafe { buf.set_len(size); }
+ return Ok(buf);
+ }
+
+ Ok(vec![0; size])
+}
+
/// Describes parser failures.
///
/// This enum wraps the standard `io::Error` type, unified with
/// our own parser error states and those of crates we use.
#[derive(Debug)]
pub enum Error {
/// Parse error caused by corrupt or malformed data.
InvalidData(&'static str),
@@ -69,16 +107,18 @@ pub enum Error {
/// Reflect `std::io::ErrorKind::UnexpectedEof` for short data.
UnexpectedEOF,
/// Propagate underlying errors from `std::io`.
Io(std::io::Error),
/// read_mp4 terminated without detecting a moov box.
NoMoov,
/// Parse error caused by table size is over limitation.
TableTooLarge,
+ /// Out of memory
+ OutOfMemory,
}
impl From<bitreader::BitReaderError> for Error {
fn from(_: bitreader::BitReaderError) -> Error {
Error::InvalidData("invalid data")
}
}
@@ -92,16 +132,22 @@ impl From<std::io::Error> for Error {
}
impl From<std::string::FromUtf8Error> for Error {
fn from(_: std::string::FromUtf8Error) -> Error {
Error::InvalidData("invalid utf8")
}
}
+impl From<()> for Error {
+ fn from(_: ()) -> Error {
+ Error::OutOfMemory
+ }
+}
+
/// Result shorthand using our Error enum.
pub type Result<T> = std::result::Result<T, Error>;
/// Basic ISO box structure.
///
/// mp4 files are a sequence of possibly-nested 'box' structures. Each box
/// begins with a header describing the length of the box's data and a
/// four-byte box type which identifies the type of the box. Together these
@@ -684,27 +730,27 @@ fn read_moov<T: Read>(f: &mut BMFFBox<T>
BoxType::MovieHeaderBox => {
let (mvhd, timescale) = parse_mvhd(&mut b)?;
context.timescale = timescale;
log!("{:?}", mvhd);
}
BoxType::TrackBox => {
let mut track = Track::new(context.tracks.len());
read_trak(&mut b, &mut track)?;
- context.tracks.push(track);
+ vec_push(&mut context.tracks, track)?;
}
BoxType::MovieExtendsBox => {
let mvex = read_mvex(&mut b)?;
log!("{:?}", mvex);
context.mvex = Some(mvex);
}
BoxType::ProtectionSystemSpecificHeaderBox => {
let pssh = read_pssh(&mut b)?;
log!("{:?}", pssh);
- context.psshs.push(pssh);
+ vec_push(&mut context.psshs, pssh)?;
}
_ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(())
}
@@ -718,29 +764,29 @@ fn read_pssh<T: Read>(src: &mut BMFFBox<
let system_id = read_buf(pssh, 16)?;
let mut kid: Vec<ByteData> = Vec::new();
if version > 0 {
let count = be_u32_with_limit(pssh)?;
for _ in 0..count {
let item = read_buf(pssh, 16)?;
- kid.push(item);
+ vec_push(&mut kid, item)?;
}
}
let data_size = be_u32_with_limit(pssh)? as usize;
let data = read_buf(pssh, data_size)?;
(system_id, kid, data)
};
let mut pssh_box = Vec::new();
write_be_u32(&mut pssh_box, src.head.size as u32)?;
- pssh_box.append(&mut b"pssh".to_vec());
+ pssh_box.extend_from_slice(b"pssh");
pssh_box.append(&mut box_content);
Ok(ProtectionSystemSpecificHeaderBox {
system_id: system_id,
kid: kid,
data: data,
box_content: pssh_box,
})
@@ -935,17 +981,17 @@ fn read_ftyp<T: Read>(src: &mut BMFFBox<
let bytes_left = src.bytes_left();
if bytes_left % 4 != 0 {
return Err(Error::InvalidData("invalid ftyp size"));
}
// Is a brand_count of zero valid?
let brand_count = bytes_left / 4;
let mut brands = Vec::new();
for _ in 0..brand_count {
- brands.push(From::from(be_u32(src)?));
+ vec_push(&mut brands, From::from(be_u32(src)?))?;
}
Ok(FileTypeBox {
major_brand: From::from(major),
minor_version: minor,
compatible_brands: brands,
})
}
@@ -1044,22 +1090,22 @@ fn read_elst<T: Read>(src: &mut BMFFBox<
0 => {
// 32 bit segment duration and media times.
(be_u32(src)? as u64, be_i32(src)? as i64)
}
_ => return Err(Error::InvalidData("unhandled elst version")),
};
let media_rate_integer = be_i16(src)?;
let media_rate_fraction = be_i16(src)?;
- edits.push(Edit {
+ vec_push(&mut edits, Edit {
segment_duration: segment_duration,
media_time: media_time,
media_rate_integer: media_rate_integer,
media_rate_fraction: media_rate_fraction,
- })
+ })?;
}
Ok(EditListBox {
edits: edits,
})
}
/// Parse a mdhd box.
@@ -1105,51 +1151,51 @@ fn read_mdhd<T: Read>(src: &mut BMFFBox<
}
/// Parse a stco box.
fn read_stco<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
let (_, _) = read_fullbox_extra(src)?;
let offset_count = be_u32_with_limit(src)?;
let mut offsets = Vec::new();
for _ in 0..offset_count {
- offsets.push(be_u32(src)? as u64);
+ vec_push(&mut offsets, be_u32(src)? as u64)?;
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(ChunkOffsetBox {
offsets: offsets,
})
}
/// Parse a co64 box.
fn read_co64<T: Read>(src: &mut BMFFBox<T>) -> Result<ChunkOffsetBox> {
let (_, _) = read_fullbox_extra(src)?;
let offset_count = be_u32_with_limit(src)?;
let mut offsets = Vec::new();
for _ in 0..offset_count {
- offsets.push(be_u64(src)?);
+ vec_push(&mut offsets, be_u64(src)?)?;
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(ChunkOffsetBox {
offsets: offsets,
})
}
/// Parse a stss box.
fn read_stss<T: Read>(src: &mut BMFFBox<T>) -> Result<SyncSampleBox> {
let (_, _) = read_fullbox_extra(src)?;
let sample_count = be_u32_with_limit(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
- samples.push(be_u32(src)?);
+ vec_push(&mut samples, be_u32(src)?)?;
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(SyncSampleBox {
samples: samples,
})
@@ -1159,21 +1205,21 @@ fn read_stss<T: Read>(src: &mut BMFFBox<
fn read_stsc<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleToChunkBox> {
let (_, _) = read_fullbox_extra(src)?;
let sample_count = be_u32_with_limit(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
let first_chunk = be_u32(src)?;
let samples_per_chunk = be_u32_with_limit(src)?;
let sample_description_index = be_u32(src)?;
- samples.push(SampleToChunk {
+ vec_push(&mut samples, SampleToChunk {
first_chunk: first_chunk,
samples_per_chunk: samples_per_chunk,
sample_description_index: sample_description_index,
- });
+ })?;
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(SampleToChunkBox {
samples: samples,
})
@@ -1198,20 +1244,20 @@ fn read_ctts<T: Read>(src: &mut BMFFBox<
let count = be_u32_with_limit(src)?;
let offset = TimeOffsetVersion::Version1(be_i32(src)?);
(count, offset)
},
_ => {
return Err(Error::InvalidData("unsupported version in 'ctts' box"));
}
};
- offsets.push(TimeOffset {
+ vec_push(&mut offsets, TimeOffset {
sample_count: sample_count,
time_offset: time_offset,
- });
+ })?;
}
skip_box_remain(src)?;
Ok(CompositionOffsetBox {
samples: offsets,
})
}
@@ -1219,17 +1265,17 @@ fn read_ctts<T: Read>(src: &mut BMFFBox<
/// Parse a stsz box.
fn read_stsz<T: Read>(src: &mut BMFFBox<T>) -> Result<SampleSizeBox> {
let (_, _) = read_fullbox_extra(src)?;
let sample_size = be_u32(src)?;
let sample_count = be_u32_with_limit(src)?;
let mut sample_sizes = Vec::new();
if sample_size == 0 {
for _ in 0..sample_count {
- sample_sizes.push(be_u32(src)?);
+ vec_push(&mut sample_sizes, be_u32(src)?)?;
}
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(SampleSizeBox {
sample_size: sample_size,
@@ -1240,20 +1286,20 @@ fn read_stsz<T: Read>(src: &mut BMFFBox<
/// Parse a stts box.
fn read_stts<T: Read>(src: &mut BMFFBox<T>) -> Result<TimeToSampleBox> {
let (_, _) = read_fullbox_extra(src)?;
let sample_count = be_u32_with_limit(src)?;
let mut samples = Vec::new();
for _ in 0..sample_count {
let sample_count = be_u32_with_limit(src)?;
let sample_delta = be_u32(src)?;
- samples.push(Sample {
+ vec_push(&mut samples, Sample {
sample_count: sample_count,
sample_delta: sample_delta,
- });
+ })?;
}
// Padding could be added in some contents.
skip_box_remain(src)?;
Ok(TimeToSampleBox {
samples: samples,
})
@@ -1450,17 +1496,17 @@ fn read_ds_descriptor(data: &[u8], esds:
channel_counts += read_surround_channel_count(bit_reader, num_back_channel)?;
channel_counts += read_surround_channel_count(bit_reader, num_lfe_channel)?;
}
esds.audio_object_type = Some(audio_object_type);
esds.audio_sample_rate = sample_frequency;
esds.audio_channel_count = Some(channel_counts);
assert!(esds.decoder_specific_data.is_empty());
- esds.decoder_specific_data.extend(data.iter());
+ esds.decoder_specific_data.extend_from_slice(data);
Ok(())
}
fn read_surround_channel_count(bit_reader: &mut BitReader, channels: u8) -> Result<u16> {
let mut count = 0;
for _ in 0..channels {
let is_cpe: bool = ReadInto::read(bit_reader, 1)?;
@@ -1538,17 +1584,17 @@ fn read_dfla<T: Read>(src: &mut BMFFBox<
return Err(Error::Unsupported("unknown dfLa (FLAC) version"));
}
if flags != 0 {
return Err(Error::InvalidData("no-zero dfLa (FLAC) flags"));
}
let mut blocks = Vec::new();
while src.bytes_left() > 0 {
let block = read_flac_metadata(src)?;
- blocks.push(block);
+ vec_push(&mut blocks, block)?;
}
// The box must have at least one meta block, and the first block
// must be the METADATA_BLOCK_STREAMINFO
if blocks.is_empty() {
return Err(Error::InvalidData("FLACSpecificBox missing metadata"));
} else if blocks[0].block_type != 0 {
return Err(Error::InvalidData(
"FLACSpecificBox must have STREAMINFO metadata first"));
@@ -1732,17 +1778,17 @@ fn read_video_sample_entry<T: Read>(src:
codec_specific = Some(VideoCodecSpecific::ESDSConfig(esds));
}
BoxType::ProtectionSchemeInformationBox => {
if name != BoxType::ProtectedVisualSampleEntry {
return Err(Error::InvalidData("malformed video sample entry"));
}
let sinf = read_sinf(&mut b)?;
log!("{:?} (sinf)", sinf);
- protection_info.push(sinf);
+ vec_push(&mut protection_info, sinf)?;
}
_ => {
log!("Unsupported video codec, box {:?} found", b.head.name);
skip_box_content(&mut b)?;
}
}
check_parser_state!(b.content);
}
@@ -1857,17 +1903,17 @@ fn read_audio_sample_entry<T: Read>(src:
}
BoxType::ProtectionSchemeInformationBox => {
if name != BoxType::ProtectedAudioSampleEntry {
return Err(Error::InvalidData("malformed audio sample entry"));
}
let sinf = read_sinf(&mut b)?;
log!("{:?} (sinf)", sinf);
codec_type = CodecType::EncryptedAudio;
- protection_info.push(sinf);
+ vec_push(&mut protection_info, sinf)?;
}
_ => {
log!("Unsupported audio codec, box {:?} found", b.head.name);
skip_box_content(&mut b)?;
}
}
check_parser_state!(b.content);
}
@@ -1915,17 +1961,17 @@ fn read_stsd<T: Read>(src: &mut BMFFBox<
}
Err(e) => return Err(e),
};
if track.data.is_none() {
track.data = Some(description.clone());
} else {
log!("** don't know how to handle multiple descriptions **");
}
- descriptions.push(description);
+ vec_push(&mut descriptions, description)?;
check_parser_state!(b.content);
if descriptions.len() == description_count as usize {
break;
}
}
}
// Padding could be added in some contents.
@@ -2010,22 +2056,25 @@ fn skip<T: Read>(src: &mut T, mut bytes:
Ok(())
}
/// Read size bytes into a Vector or return error.
fn read_buf<T: ReadBytesExt>(src: &mut T, size: usize) -> Result<Vec<u8>> {
if size > BUF_SIZE_LIMIT {
return Err(Error::InvalidData("read_buf size exceeds BUF_SIZE_LIMIT"));
}
- let mut buf = vec![0; size];
- let r = src.read(&mut buf)?;
- if r != size {
- return Err(Error::InvalidData("failed buffer read"));
+ if let Ok(mut buf) = reserve_read_buf(size) {
+ let r = src.read(&mut buf)?;
+ if r != size {
+ return Err(Error::InvalidData("failed buffer read"));
+ }
+ return Ok(buf);
}
- Ok(buf)
+
+ Err(Error::OutOfMemory)
}
fn be_i16<T: ReadBytesExt>(src: &mut T) -> Result<i16> {
src.read_i16::<byteorder::BigEndian>().map_err(From::from)
}
fn be_i32<T: ReadBytesExt>(src: &mut T) -> Result<i32> {
src.read_i32::<byteorder::BigEndian>().map_err(From::from)
--- a/media/libstagefright/binding/mp4parse_capi/src/lib.rs
+++ b/media/libstagefright/binding/mp4parse_capi/src/lib.rs
@@ -53,28 +53,30 @@ use mp4parse::AudioCodecSpecific;
use mp4parse::VideoCodecSpecific;
use mp4parse::MediaTimeScale;
use mp4parse::MediaScaledTime;
use mp4parse::TrackTimeScale;
use mp4parse::TrackScaledTime;
use mp4parse::serialize_opus_header;
use mp4parse::CodecType;
use mp4parse::Track;
+use mp4parse::vec_push;
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum mp4parse_status {
OK = 0,
BAD_ARG = 1,
INVALID = 2,
UNSUPPORTED = 3,
EOF = 4,
IO = 5,
TABLE_TOO_LARGE = 6,
+ OOM = 7,
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum mp4parse_track_type {
VIDEO = 0,
AUDIO = 1,
@@ -303,26 +305,31 @@ pub unsafe extern fn mp4parse_free(parse
}
/// Enable `mp4_parser` log.
#[no_mangle]
pub unsafe extern fn mp4parse_log(enable: bool) {
mp4parse::set_debug_mode(enable);
}
+#[no_mangle]
+pub unsafe extern fn mp4parse_fallible_allocation(enable: bool) {
+ mp4parse::set_fallible_allocation_mode(enable);
+}
+
/// Run the `mp4parse_parser*` allocated by `mp4parse_new()` until EOF or error.
#[no_mangle]
pub unsafe extern fn mp4parse_read(parser: *mut mp4parse_parser) -> mp4parse_status {
// Validate arguments from C.
if parser.is_null() || (*parser).poisoned() {
return mp4parse_status::BAD_ARG;
}
- let mut context = (*parser).context_mut();
- let mut io = (*parser).io_mut();
+ let context = (*parser).context_mut();
+ let io = (*parser).io_mut();
let r = read_mp4(io, context);
match r {
Ok(_) => mp4parse_status::OK,
Err(Error::NoMoov) | Err(Error::InvalidData(_)) => {
// Block further calls. We've probable lost sync.
(*parser).set_poisoned(true);
mp4parse_status::INVALID
@@ -333,16 +340,17 @@ pub unsafe extern fn mp4parse_read(parse
// Block further calls after a read failure.
// Getting std::io::ErrorKind::UnexpectedEof is normal
// but our From trait implementation should have converted
// those to our Error::UnexpectedEOF variant.
(*parser).set_poisoned(true);
mp4parse_status::IO
},
Err(Error::TableTooLarge) => mp4parse_status::TABLE_TOO_LARGE,
+ Err(Error::OutOfMemory) => mp4parse_status::OOM,
}
}
/// Return the number of tracks parsed by previous `mp4parse_read()` call.
#[no_mangle]
pub unsafe extern fn mp4parse_get_track_count(parser: *const mp4parse_parser, count: *mut u32) -> mp4parse_status {
// Validate arguments from C.
if parser.is_null() || count.is_null() || (*parser).poisoned() {
@@ -895,26 +903,27 @@ fn create_sample_table(track: &Track, tr
(t, _) if t > 0 => start_offset + t as u64,
_ => 0,
};
if end_offset == 0 {
return None;
}
cur_position = end_offset;
- sample_table.push(
- mp4parse_indice {
- start_offset: start_offset,
- end_offset: end_offset,
- start_composition: 0,
- end_composition: 0,
- start_decode: 0,
- sync: !has_sync_table,
- }
- );
+ let res = vec_push(&mut sample_table, mp4parse_indice {
+ start_offset: start_offset,
+ end_offset: end_offset,
+ start_composition: 0,
+ end_composition: 0,
+ start_decode: 0,
+ sync: !has_sync_table,
+ });
+ if res.is_err() {
+ return None;
+ }
}
}
// Mark the sync sample in sample_table according to 'stss'.
if let Some(ref v) = track.stss {
for iter in &v.samples {
if let Some(elem) = sample_table.get_mut((iter - 1) as usize) {
elem.sync = true;
@@ -972,22 +981,23 @@ fn create_sample_table(track: &Track, tr
_ => return None,
}
}
// Correct composition end time due to 'ctts' causes composition time re-ordering.
//
// Composition end time is not in specification. However, gecko needs it, so we need to
// calculate to correct the composition end time.
- if track.ctts.is_some() {
+ if sample_table.len() > 0 {
// Create an index table refers to sample_table and sorted by start_composisiton time.
let mut sort_table = Vec::new();
- sort_table.reserve(sample_table.len());
for i in 0 .. sample_table.len() {
- sort_table.push(i);
+ if vec_push(&mut sort_table, i).is_err() {
+ return None;
+ }
}
sort_table.sort_by_key(|i| {
match sample_table.get(*i) {
Some(v) => {
v.start_composition
},
_ => 0,
@@ -1111,17 +1121,17 @@ extern fn panic_read(_: *mut u8, _: usiz
#[cfg(test)]
extern fn error_read(_: *mut u8, _: usize, _: *mut std::os::raw::c_void) -> isize {
-1
}
#[cfg(test)]
extern fn valid_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
- let mut input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
+ let input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
let mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
@@ -1275,16 +1285,18 @@ fn get_track_count_poisoned_parser() {
assert!(!parser.is_null());
// Our mp4parse_io read should simply fail with an error.
assert_eq!(mp4parse_status::IO, mp4parse_read(parser));
let mut count: u32 = 0;
let rv = mp4parse_get_track_count(parser, &mut count);
assert_eq!(rv, mp4parse_status::BAD_ARG);
+
+ mp4parse_free(parser);
}
}
#[test]
fn arg_validation_with_data() {
unsafe {
let mut file = std::fs::File::open("../mp4parse/tests/minimal.mp4").unwrap();
let io = mp4parse_io { read: Some(valid_read),
--- a/media/libstagefright/binding/update-rust.sh
+++ b/media/libstagefright/binding/update-rust.sh
@@ -1,13 +1,13 @@
#!/bin/sh -e
# Script to update mp4parse-rust sources to latest upstream
# Default version.
-VER=81260ded506dce968716720e10544c510f37d222
+VER=500dd97c307c346eca8f3bc61dd374d67fc9b802
# Accept version or commit from the command line.
if test -n "$1"; then
VER=$1
fi
echo "Fetching sources..."
rm -rf _upstream
@@ -33,16 +33,19 @@ mkdir -p mp4parse/tests
cp _upstream/mp4parse/mp4parse/tests/*.rs mp4parse/tests/
cp _upstream/mp4parse/mp4parse/tests/*.mp4 mp4parse/tests/
rm -rf mp4parse_capi
mkdir -p mp4parse_capi/src
cp _upstream/mp4parse/mp4parse_capi/Cargo.toml mp4parse_capi/
cp _upstream/mp4parse/mp4parse_capi/build.rs mp4parse_capi/
cp _upstream/mp4parse/mp4parse_capi/include/mp4parse.h include/
cp _upstream/mp4parse/mp4parse_capi/src/*.rs mp4parse_capi/src/
+rm -rf fallible
+mkdir -p fallible
+cp _upstream/mp4parse/fallible/* fallible/
echo "Applying patches..."
patch -p4 < mp4parse-cargo.patch
echo "Cleaning up..."
rm -rf _upstream
echo "Updating gecko Cargo.lock..."
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -481,16 +481,23 @@ source = "registry+https://github.com/ru
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "fallible"
+version = "0.0.1"
+dependencies = [
+ "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fnv"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -769,16 +776,17 @@ dependencies = [
]
[[package]]
name = "mp4parse"
version = "0.8.0"
dependencies = [
"bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fallible 0.0.1",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mp4parse-gtest"
version = "0.1.0"
[[package]]
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -479,16 +479,23 @@ source = "registry+https://github.com/ru
dependencies = [
"heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "fallible"
+version = "0.0.1"
+dependencies = [
+ "smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fnv"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "freetype"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -767,16 +774,17 @@ dependencies = [
]
[[package]]
name = "mp4parse"
version = "0.8.0"
dependencies = [
"bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fallible 0.0.1",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mp4parse_capi"
version = "0.8.0"
dependencies = [
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",