From 1b894c65de8e5bf03225afa29664045f5622e6d7 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Sun, 15 Mar 2015 21:35:48 +0100 Subject: [PATCH] Improve error handling in libflate This removes the error case of the compression functions, the only errors that can occur are incorrect parameters or an out-of-memory condition, both of which are handled with panics in Rust. Also introduces an extensible `Error` type instead of returning an `Option`. --- src/libflate/lib.rs | 68 +++++++++++++++++++++----------- src/librustc/metadata/loader.rs | 4 +- src/librustc_trans/back/link.rs | 7 +--- src/librustc_trans/back/lto.rs | 8 ++-- src/librustc_trans/trans/base.rs | 5 +-- 5 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 100a9e36e86..695c71c73ed 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -25,7 +25,6 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(int_uint)] #![feature(libc)] #![feature(staged_api)] #![feature(unique)] @@ -35,13 +34,33 @@ extern crate libc; use libc::{c_void, size_t, c_int}; +use std::fmt; use std::ops::Deref; use std::ptr::Unique; use std::slice; +#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Error { + _unused: (), +} + +impl Error { + fn new() -> Error { + Error { + _unused: (), + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "decompression error".fmt(f) + } +} + pub struct Bytes { ptr: Unique, - len: uint, + len: usize, } impl Deref for Bytes { @@ -78,55 +97,56 @@ fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, const TINFL_FLAG_PARSE_ZLIB_HEADER: c_int = 0x1; // parse zlib header and adler32 checksum const TDEFL_WRITE_ZLIB_HEADER: c_int = 0x01000; // write zlib header and adler32 checksum -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { +fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Bytes { unsafe { - let mut outsz : size_t = 0; + let mut outsz: size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, bytes.len() as size_t, &mut outsz, flags); - if !res.is_null() { - let res = Unique::new(res as *mut u8); - Some(Bytes { ptr: res, len: outsz as uint }) - } else { - None + assert!(!res.is_null()); + Bytes { + ptr: Unique::new(res as *mut u8), + len: outsz as usize, } } } /// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Option { +pub fn deflate_bytes(bytes: &[u8]) -> Bytes { deflate_bytes_internal(bytes, LZ_NORM) } /// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option { +pub fn deflate_bytes_zlib(bytes: &[u8]) -> Bytes { deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) } -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option { +fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result { unsafe { - let mut outsz : size_t = 0; + let mut outsz: size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, bytes.len() as size_t, &mut outsz, flags); if !res.is_null() { - let res = Unique::new(res as *mut u8); - Some(Bytes { ptr: res, len: outsz as uint }) + Ok(Bytes { + ptr: Unique::new(res as *mut u8), + len: outsz as usize, + }) } else { - None + Err(Error::new()) } } } /// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Option { +pub fn inflate_bytes(bytes: &[u8]) -> Result { inflate_bytes_internal(bytes, 0) } /// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option { +pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result { inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) } @@ -140,7 +160,7 @@ mod tests { #[test] fn test_flate_round_trip() { let mut r = rand::thread_rng(); - let mut words = vec!(); + let mut words = vec![]; for _ in 0..20 { let range = r.gen_range(1, 10); let v = r.gen_iter::().take(range).collect::>(); @@ -153,8 +173,8 @@ fn test_flate_round_trip() { } debug!("de/inflate of {} bytes of random word-sequences", input.len()); - let cmp = deflate_bytes(&input).expect("deflation failed"); - let out = inflate_bytes(&cmp).expect("inflation failed"); + let cmp = deflate_bytes(&input); + let out = inflate_bytes(&cmp).unwrap(); debug!("{} bytes deflated to {} ({:.1}% size)", input.len(), cmp.len(), 100.0 * ((cmp.len() as f64) / (input.len() as f64))); @@ -164,9 +184,9 @@ fn test_flate_round_trip() { #[test] fn test_zlib_flate() { - let bytes = vec!(1, 2, 3, 4, 5); - let deflated = deflate_bytes(&bytes).expect("deflation failed"); - let inflated = inflate_bytes(&deflated).expect("inflation failed"); + let bytes = vec![1, 2, 3, 4, 5]; + let deflated = deflate_bytes(&bytes); + let inflated = inflate_bytes(&deflated).unwrap(); assert_eq!(&*inflated, &*bytes); } } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 8486bf782b0..e466dc8a3a0 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -784,8 +784,8 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result return Ok(MetadataVec(inflated)), - None => {} + Ok(inflated) => return Ok(MetadataVec(inflated)), + Err(_) => {} } } llvm::LLVMMoveToNextSection(si.llsi); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3087a8ea45d..34a23f3efac 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -626,12 +626,7 @@ fn link_rlib<'a>(sess: &'a Session, e)) } - let bc_data_deflated = match flate::deflate_bytes(&bc_data[..]) { - Some(compressed) => compressed, - None => sess.fatal(&format!("failed to compress bytecode \ - from {}", - bc_filename.display())) - }; + let bc_data_deflated = flate::deflate_bytes(&bc_data[..]); let mut bc_file_deflated = match fs::File::create(&bc_deflated_filename) { Ok(file) => file, diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index db9966e0548..3893b974987 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -96,8 +96,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, (link::RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET + data_size as uint)]; match flate::inflate_bytes(compressed_data) { - Some(inflated) => inflated, - None => { + Ok(inflated) => inflated, + Err(_) => { sess.fatal(&format!("failed to decompress bc of `{}`", name)) } @@ -112,8 +112,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // the object must be in the old, pre-versioning format, so simply // inflate everything and let LLVM decide if it can make sense of it match flate::inflate_bytes(bc_encoded) { - Some(bc) => bc, - None => { + Ok(bc) => bc, + Err(_) => { sess.fatal(&format!("failed to decompress bc of `{}`", name)) } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index ccf24f7e859..e9f58ec53df 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2974,10 +2974,7 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec { let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item); let metadata = encoder::encode_metadata(encode_parms, krate); let mut compressed = encoder::metadata_encoding_version.to_vec(); - compressed.push_all(&match flate::deflate_bytes(&metadata) { - Some(compressed) => compressed, - None => cx.sess().fatal("failed to compress metadata"), - }); + compressed.push_all(&flate::deflate_bytes(&metadata)); let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); let name = format!("rust_metadata_{}_{}", -- 2.44.0