diff --git a/fuzz/fuzz.rs b/fuzz/fuzz.rs index 801068e..4b52a0b 100644 --- a/fuzz/fuzz.rs +++ b/fuzz/fuzz.rs @@ -1,18 +1,21 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use std::collections::VecDeque; use std::collections::HashMap; extern crate add_ed; use add_ed::io::fake_io::FakeIO; -fuzz_target!(|data: VecDeque| { +// You can do anything in 4 input lines, so that should be enough +// (and it should help with the out-of-memory problems while fuzzing) +fuzz_target!(|data: [String; 4]| { let mut ui = add_ed::ui::ScriptedUI { - input: data, + input: data.into(), print_ui: None, }; let mut io = FakeIO{fake_fs: HashMap::new(), fake_shell: HashMap::new()}; - let mut buffer = add_ed::buffer::Buffer::new(); - let mut ed = add_ed::Ed::new(&mut buffer, &mut io, "".to_string()); - let _ = ed.run_macro(&mut ui); + let macro_store = HashMap::new(); + let mut ed = add_ed::Ed::new(&mut io, ¯o_store); + loop { + if let Ok(true) = ed.get_and_run_command(&mut ui) { break; } + } }); diff --git a/src/cmd/parsing/selection.rs b/src/cmd/parsing/selection.rs index 5d196ab..32c9dd4 100644 --- a/src/cmd/parsing/selection.rs +++ b/src/cmd/parsing/selection.rs @@ -54,14 +54,11 @@ pub fn parse_index( // then an offset. Not caught earlier so we can give a more // detailed error. Same error logic as post loop State::Default if let Some(_) = current_ind {return Err( + // Note that this reports getting digits after another index. + // We catch it here to get all the digits before erroring. EdError::IndicesUnrelated{ - prior_index: input[start..i].to_owned(), - // Find the end of the current index - unrelated_index: input[i..] - .find(|c: char| !c.is_ascii_digit()) - .map(|end| &input[i..end] ) - .unwrap_or(&input[i..]) - .to_owned(), + prior_index: input[..start].to_owned(), + unrelated_index: input[start..i].to_owned(), } )} // If there is numeric input before, handle that @@ -121,8 +118,17 @@ pub fn parse_index( State::Tag => { if let Some(_) = current_ind { return Err( EdError::IndicesUnrelated{ + // Safe, as the -1 is to exclude the ' (which is 1 byte long) prior_index: input[..i-1].to_owned(), - unrelated_index: input[i-1..i+1].to_owned(), + // As the start -1 includes the ' the start is safe, but we can't + // assume the given tag is 1 byte long. + unrelated_index: { + let mut index = String::new(); + for ch in input[i-1..].chars().take(2) { + index.push(ch); + } + index + }, } )} current_ind = Some(Ind::Tag(ch)); @@ -304,7 +310,7 @@ pub fn interpret_index( // These are relative to the prior, so have no indexing per-se Ind::Add(inner, offset) => { let inner = interpret_index(state, *inner, old_selection)?; - Ok(inner+offset) + Ok(inner.saturating_add(offset)) }, Ind::Sub(inner, offset) => { let inner = interpret_index(state, *inner, old_selection)?; diff --git a/src/error/display.rs b/src/error/display.rs index c89c047..6bc64b6 100644 --- a/src/error/display.rs +++ b/src/error/display.rs @@ -110,7 +110,7 @@ impl std::fmt::Display for EdError { text, ), IndicesUnrelated{prior_index, unrelated_index} => write!(f, - "Received index `{}` immediately after index `{}`.", + "Received non-chainable index `{}` immediately after index `{}`.", unrelated_index, prior_index, ), diff --git a/tests/old_fuss_fails.rs b/tests/old_fuss_fails.rs new file mode 100644 index 0000000..85ef96b --- /dev/null +++ b/tests/old_fuss_fails.rs @@ -0,0 +1,29 @@ +mod shared; +use shared::fixtures::{ + ErrorTest, +}; +use add_ed::EdError; + +#[test] +fn unrelated_indice_with_unicode_tag() { + ErrorTest{ + init_buffer: vec![], + command_input: vec!["'''🏷 G"], + expected_error: EdError::IndicesUnrelated{ + prior_index: "''".to_owned(), + unrelated_index: "'🏷".to_owned(), + }, + }.run() +} + +#[test] +fn index_overflow() { + ErrorTest{ + init_buffer: vec![], + command_input: vec!["9999999999999999999+9999999999999999999"], + expected_error: EdError::IndexTooBig{ + index: 18_446_744_073_709_551_615, + buffer_len: 0, + }, + }.run() +} diff --git a/tests/shared/inner_fixture.rs b/tests/shared/inner_fixture.rs index 38610ae..5d8ecb3 100644 --- a/tests/shared/inner_fixture.rs +++ b/tests/shared/inner_fixture.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use super::{ - dummy_io::DummyIO, + fake_io::FakeIO, mock_ui::{Print, MockUI}, }; use add_ed::{ @@ -33,7 +33,10 @@ pub fn inner_fixture( expected_prints: Vec, ) { // Instantiate dummy IO - let mut io = DummyIO::new(); + let mut io = FakeIO{ + fake_fs: HashMap::new(), + fake_shell: HashMap::new(), + }; // Apply given or default to no macros let macros = init_macros.unwrap_or(HashMap::new()); // Create ed state and init ed.buffer