diff options
| -rw-r--r-- | src/long_mode/display.rs | 60 | ||||
| -rw-r--r-- | test/long_mode/mod.rs | 45 | 
2 files changed, 87 insertions, 18 deletions
| diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index da138bb..198a930 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -758,11 +758,15 @@ impl DisplaySink for alloc::string::String {      fn write_u8(&mut self, mut v: u8) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((8 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((8 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        } +          self.reserve(printed_size);          let buf = unsafe { self.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -791,11 +795,15 @@ impl DisplaySink for alloc::string::String {      fn write_u16(&mut self, mut v: u16) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((16 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((16 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        } +          self.reserve(printed_size);          let buf = unsafe { self.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -826,11 +834,15 @@ impl DisplaySink for alloc::string::String {      fn write_u32(&mut self, mut v: u32) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((32 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((32 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        } +          self.reserve(printed_size);          let buf = unsafe { self.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -860,11 +872,15 @@ impl DisplaySink for alloc::string::String {      fn write_u64(&mut self, mut v: u64) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((64 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((64 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        } +          self.reserve(printed_size);          let buf = unsafe { self.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -1140,10 +1156,13 @@ impl DisplaySink for BigEnoughString {      fn write_u8(&mut self, mut v: u8) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((8 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((8 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        }          let buf = unsafe { self.content.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -1172,10 +1191,13 @@ impl DisplaySink for BigEnoughString {      fn write_u16(&mut self, mut v: u16) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((16 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((16 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        }          let buf = unsafe { self.content.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -1205,10 +1227,13 @@ impl DisplaySink for BigEnoughString {      fn write_u32(&mut self, mut v: u32) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((32 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((32 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        }          let buf = unsafe { self.content.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; @@ -1238,10 +1263,13 @@ impl DisplaySink for BigEnoughString {      fn write_u64(&mut self, mut v: u64) -> Result<(), core::fmt::Error> {          // we can fairly easily predict the size of a formatted string here with lzcnt, which also          // means we can write directly into the correct offsets of the output string. -        let printed_size = (((64 - v.leading_zeros()) >> 2) + 1) as usize; +        let mut printed_size = ((64 - v.leading_zeros() + 3) >> 2) as usize; +        if printed_size == 0 { +            printed_size = 1; +        }          let buf = unsafe { self.content.as_mut_vec() }; -        let p = buf.as_mut_ptr(); +        let p = unsafe { buf.as_mut_ptr().offset(buf.len() as isize) };          let mut curr = printed_size;          loop {              let digit = v % 16; diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 8b01461..24df133 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -15,6 +15,19 @@ use std::fmt::Write;  use yaxpeax_arch::{AddressBase, Decoder, LengthedInstruction};  use yaxpeax_x86::long_mode::InstDecoder; +#[test] +#[cfg(feature="std")] +fn test_write_hex_specialization() { +    use crate::yaxpeax_x86::long_mode::DisplaySink; +    for i in 0..0xffu8 { +        let mut out = yaxpeax_x86::long_mode::BigEnoughString::new(); +        out.write_char('0').unwrap(); +        out.write_char('x').unwrap(); +        out.write_u8(i).unwrap(); +        assert_eq!(out.into_inner(), format!("0x{:x}", i)); +    } +} +  fn test_invalid(data: &[u8]) {      test_invalid_under(&InstDecoder::default(), data);  } @@ -62,23 +75,51 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str                          text,                          expected                      ); +                      let mut text2 = yaxpeax_x86::long_mode::BigEnoughString::new();                      let mut out = yaxpeax_x86::long_mode::NoColorsSink {                          out: &mut text2,                      }; -                    instr.write_to(&mut out); +                    instr.write_to(&mut out).expect("printing succeeds");                      core::mem::drop(out);                      let text2 = text2.into_inner();                      assert!(                          text2 == text, -                        "display error for {}:\n  decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n", +                        "display error through NoColorsSink for {}:\n  decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",                          hex,                          instr,                          decoder,                          text2,                          text,                      ); + +                    let mut text3 = yaxpeax_x86::long_mode::BigEnoughString::new(); +                    instr.write_to(&mut text3).expect("printing succeeds"); +                    let text3 = text3.into_inner(); + +                    assert!( +                        text3 == text, +                        "display error through BigEnoughString for {}:\n  decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n", +                        hex, +                        instr, +                        decoder, +                        text3, +                        text, +                    ); + +                    let mut text4 = String::new(); +                    instr.write_to(&mut text4).expect("printing succeeds"); + +                    assert!( +                        text4 == text, +                        "display error through String for {}:\n  decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n", +                        hex, +                        instr, +                        decoder, +                        text4, +                        text, +                    );                  } else {                      eprintln!("non-fmt build cannot compare text equality")                  } | 
