From 56d36f27325be53450cdd1e89d9f981d7a55b625 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Sat, 27 Jun 2020 19:43:50 +0200 Subject: [PATCH] Avoid truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Error where truncation can occurr and prevent truncation in the future by using `type::from()` (which checks for truncation) instead of `as type` (which doesn’t). --- src/converter/ddr2osu.rs | 2 +- src/ddr/ssq.rs | 11 ++++++----- src/lib.rs | 2 ++ src/osu/beatmap.rs | 2 +- src/xact3/adpcm.rs | 27 ++++++++++++++++++++------- src/xact3/xwb.rs | 26 +++++++++++++++++--------- 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/converter/ddr2osu.rs b/src/converter/ddr2osu.rs index c8fefbb..46f02f3 100644 --- a/src/converter/ddr2osu.rs +++ b/src/converter/ddr2osu.rs @@ -345,7 +345,7 @@ impl ConvertedChart { }, difficulty: beatmap::Difficulty { hp_drain_rate: config.hp_drain.map_from(self.difficulty.clone().into()), - circle_size: self.difficulty.players as f32 * 4.0, + circle_size: f32::from(self.difficulty.players) * 4.0, overall_difficulty: config.accuracy.map_from(self.difficulty.clone().into()), approach_rate: 8.0, slider_multiplier: 0.64, diff --git a/src/ddr/ssq.rs b/src/ddr/ssq.rs index ced664b..fc0ba59 100644 --- a/src/ddr/ssq.rs +++ b/src/ddr/ssq.rs @@ -4,6 +4,7 @@ use std::fmt; use std::io; use std::io::prelude::*; use std::io::Cursor; +use std::num; use byteorder::{ReadBytesExt, LE}; use log::{debug, info, trace, warn}; @@ -12,7 +13,7 @@ use thiserror::Error; use crate::mini_parser::{MiniParser, MiniParserError}; use crate::utils; -const MEASURE_LENGTH: i32 = 4096; +const MEASURE_LENGTH: f32 = 4096.0; #[derive(Error, Debug)] pub enum Error { @@ -21,7 +22,7 @@ pub enum Error { #[error(transparent)] IOError(#[from] io::Error), #[error(transparent)] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError(#[from] num::TryFromIntError), #[error(transparent)] MiniParserError(#[from] MiniParserError), } @@ -29,7 +30,7 @@ pub enum Error { /// Convert time offset to beats /// time offset is the measure times MEASURE_LENGTH fn measure_to_beats(metric: i32) -> f32 { - 4.0 * metric as f32 / MEASURE_LENGTH as f32 + 4.0 * metric as f32 / MEASURE_LENGTH } #[derive(Debug, Clone, PartialEq, Default)] @@ -385,7 +386,7 @@ impl SSQ { }; loop { - let length = cursor.read_i32::()? as usize; + let length: usize = cursor.read_i32::()?.try_into()?; trace!("Found chunk (length {})", length); if length == 0 { break; @@ -401,7 +402,7 @@ impl SSQ { match chunk_type { 1 => { debug!("Parsing tempo changes (ticks/s: {})", parameter); - ssq.tempo_changes = TempoChanges::parse(parameter as i32, &data)?; + ssq.tempo_changes = TempoChanges::parse(parameter.into(), &data)?; } 3 => { debug!("Parsing step chunk ({})", Difficulty::from(parameter)); diff --git a/src/lib.rs b/src/lib.rs index 882c4b5..ff042b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(clippy::cast_lossless)] + #[cfg(test)] #[macro_use(quickcheck)] extern crate quickcheck_macros; diff --git a/src/osu/beatmap.rs b/src/osu/beatmap.rs index 30845b3..4beda74 100644 --- a/src/osu/beatmap.rs +++ b/src/osu/beatmap.rs @@ -29,7 +29,7 @@ fn assemble_hit_object_type(hit_object_type: u8, new_combo: bool, skip_combo_col } pub fn column_to_x(column: u8, columns: u8) -> OsuPixel { - ((512 * column as OsuPixel + 256) / columns as OsuPixel) as OsuPixel + (512 * OsuPixel::from(column) + 256) / OsuPixel::from(columns) } #[derive(ToPrimitive, Clone)] diff --git a/src/xact3/adpcm.rs b/src/xact3/adpcm.rs index cd8ca8a..32ac580 100644 --- a/src/xact3/adpcm.rs +++ b/src/xact3/adpcm.rs @@ -1,7 +1,9 @@ +use std::convert::TryInto; use std::io::{Cursor, Write}; use byteorder::{LittleEndian, WriteBytesExt}; use log::{debug, trace}; +use thiserror::Error; #[rustfmt::skip] const COEFFS: &[CoefSet] = &[ @@ -14,6 +16,12 @@ const COEFFS: &[CoefSet] = &[ (392, -232), ]; +#[derive(Debug, Error)] +pub enum Error { + #[error("unable to create file of size {0} (larger than 2^32)")] + TooLarge(usize), +} + trait WaveChunk { fn to_chunk(&self) -> Vec; } @@ -87,17 +95,22 @@ impl WaveChunk for RIFFHeader { } } -pub fn build_wav(format: WaveFormat, data: &[u8]) -> Vec { +pub fn build_wav(format: WaveFormat, data: &[u8]) -> Result, Error> { debug!("Building file"); + let length: u32 = data + .len() + .try_into() + .map_err(|_| Error::TooLarge(data.len()))?; + let riff_header = RIFFHeader { - file_size: 82 + data.len() as u32, + file_size: 82 + length, }; let fact = WaveFact { - length_samples: ((data.len() as u32 / format.n_block_align as u32) - * ((format.n_block_align - (7 * format.n_channels)) * 8) as u32 + length_samples: ((length / u32::from(format.n_block_align)) + * u32::from((format.n_block_align - (7 * format.n_channels)) * 8) / 4) - / format.n_channels as u32, + / u32::from(format.n_channels), }; let mut buf = Cursor::new(Vec::new()); @@ -110,8 +123,8 @@ pub fn build_wav(format: WaveFormat, data: &[u8]) -> Vec { buf.write_all(&fact.to_chunk()).unwrap(); write!(buf, "data").unwrap(); - buf.write_u32::(data.len() as u32).unwrap(); + buf.write_u32::(length).unwrap(); buf.write_all(data).unwrap(); - buf.into_inner() + Ok(buf.into_inner()) } diff --git a/src/xact3/xwb.rs b/src/xact3/xwb.rs index cedcebf..4e1e443 100644 --- a/src/xact3/xwb.rs +++ b/src/xact3/xwb.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::convert::TryInto; use std::io; use std::io::Cursor; +use std::num; use byteorder::{ReadBytesExt, LE}; use log::{debug, info, trace, warn}; @@ -23,6 +24,10 @@ pub enum Error { IOError(#[from] io::Error), #[error(transparent)] MiniParserError(#[from] MiniParserError), + #[error(transparent)] + ADPCMError(#[from] adpcm::Error), + #[error(transparent)] + TryFromIntError(#[from] num::TryFromIntError), } #[derive(Clone, FromPrimitive, Debug, PartialEq)] @@ -60,11 +65,11 @@ impl TryInto for Format { return Err(Error::UnsupportedFormat(self.tag)); } - let n_block_align = (self.alignment as u16 + 22) * self.channels; + let n_block_align = (u16::from(self.alignment) + 22) * self.channels; let n_samples_per_block = (((n_block_align - (7 * self.channels)) * 8) / (4 * self.channels)) + 2; let n_avg_bytes_per_sec = - (self.sample_rate / n_samples_per_block as u32) * n_block_align as u32; + (self.sample_rate / u32::from(n_samples_per_block)) * u32::from(n_block_align); Ok(adpcm::WaveFormat { n_channels: self.channels, @@ -113,8 +118,8 @@ impl Header { let offset = cursor.read_u32::()?; let length = cursor.read_u32::()?; segment_positions.push(SegmentPosition { - offset: offset as usize, - length: length as usize, + offset: offset.try_into()?, + length: length.try_into()?, }) } Ok(Header { segment_positions }) @@ -145,9 +150,9 @@ impl Info { let _build_time = cursor.read_u32::()?; Ok(Self { - entry_count: entry_count as usize, + entry_count: entry_count.try_into()?, name, - entry_name_element_size: entry_name_element_size as usize, + entry_name_element_size: entry_name_element_size.try_into()?, }) } } @@ -181,8 +186,8 @@ impl Entry { Ok(Self { name: "".to_string(), format: format.into(), - data_offset: data_offset as usize, - data_length: data_length as usize, + data_offset: data_offset.try_into()?, + data_length: data_length.try_into()?, }) } } @@ -264,7 +269,10 @@ pub struct Sound<'a> { impl Sound<'_> { pub fn to_wav(&self) -> Result, Error> { match &self.format.tag { - FormatTag::ADPCM => Ok(adpcm::build_wav(self.format.clone().try_into()?, self.data)), + FormatTag::ADPCM => Ok(adpcm::build_wav( + self.format.clone().try_into()?, + self.data, + )?), _ => Err(Error::UnsupportedFormat(self.format.tag.clone())), } }