stdio, string, platform: fix a bug in printf() involving chars

Because we were previously converting the bytes in the format
string into Rust's char type and then printing that using the
format machinery, byte values that were not valid single-byte
UTF-8 characters failed to print correctly.  I found this while
trying to implement qsort() because the output of my test program
was mysteriously incorrect despite it working when I used glibc.
This commit is contained in:
Alex Lyon
2018-05-11 22:53:36 -07:00
parent 1bcc40c08f
commit 0cabecd5b5
5 changed files with 92 additions and 59 deletions
+13 -10
View File
@@ -11,11 +11,12 @@ extern crate va_list as vl;
use core::str;
use core::ptr;
use core::fmt::{Error, Result, Write};
use core::fmt::{self, Error, Result};
use core::fmt::Write as WriteFmt;
use core::sync::atomic::{AtomicBool, Ordering};
use platform::types::*;
use platform::{c_str, errno};
use platform::{c_str, errno, Write};
use errno::STR_ERROR;
use vl::VaList as va_list;
@@ -164,7 +165,7 @@ impl FILE {
unsafe { platform::lseek(self.fd, off, whence) }
}
}
impl Write for FILE {
impl fmt::Write for FILE {
fn write_str(&mut self, s: &str) -> Result {
let s = s.as_bytes();
if self.write(s) != s.len() {
@@ -174,6 +175,15 @@ impl Write for FILE {
}
}
}
impl Write for FILE {
fn write_u8(&mut self, byte: u8) -> Result {
if self.write(&[byte]) != 1 {
Err(Error)
} else {
Ok(())
}
}
}
/// Clears EOF and ERR indicators on a stream
#[no_mangle]
@@ -872,10 +882,3 @@ pub unsafe extern "C" fn vsnprintf(
pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
}
/*
#[no_mangle]
pub extern "C" fn func(args) -> c_int {
unimplemented!();
}
*/
+12 -16
View File
@@ -1,19 +1,18 @@
use core::{fmt, slice, str};
use platform::{self, Write};
use platform::types::*;
use vl::VaList;
pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
extern "C" {
fn strlen(s: *const c_char) -> size_t;
}
pub unsafe fn printf<W: Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
let format = unsafe { slice::from_raw_parts(format as *const u8, usize::max_value()) };
let format = slice::from_raw_parts(format as *const u8, strlen(format));
let mut i = 0;
let mut found_percent = false;
while i < format.len() {
let b = format[i];
for &b in format.iter() {
// check for NUL
if b == 0 {
break;
}
if found_percent {
match b as char {
@@ -24,7 +23,7 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
'c' => {
let a = ap.get::<u32>();
w.write_char(a as u8 as char);
w.write_u8(a as u8);
found_percent = false;
}
@@ -57,9 +56,8 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
's' => {
let a = ap.get::<usize>();
w.write_str(str::from_utf8_unchecked(slice::from_raw_parts(
a as *const u8,
strlen(a as *const c_char),
w.write_str(str::from_utf8_unchecked(platform::c_str(
a as *const c_char,
)));
found_percent = false;
@@ -102,10 +100,8 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
} else if b == b'%' {
found_percent = true;
} else {
w.write_char(b as char);
w.write_u8(b);
}
i += 1;
}
0