From 4c94dfac00e7360f002dde3198abb5b350d2cae7 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Fri, 22 May 2020 21:54:42 +0200 Subject: [PATCH 1/9] Add type definition for caddr_t Normally one shouldn't be using this datatype ever, but then someone have to tell that to gcc folks :( --- include/sys/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sys/types.h b/include/sys/types.h index 270a43e46a..19cf76bb78 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -30,5 +30,6 @@ typedef unsigned int u_int, uint; typedef unsigned long u_long, ulong; typedef long long quad_t; typedef unsigned long long u_quad_t; +typedef char *caddr_t; #endif /* _SYS_TYPES_H */ From 7a6f96373e1f93b0ad556974822ebd83979741b2 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Fri, 22 May 2020 23:05:49 +0200 Subject: [PATCH 2/9] Add support for multiple unget at the same time According to the standards, only one ungetc may be guaranteed however glibc allows more than one of those, and to be glibc compatiable, one needs to be able to do the same, allowing only 1 ungetc may trigger bug while compiling gcc as ungetc is used there alot --- src/header/stdio/default.rs | 3 ++- src/header/stdio/helpers.rs | 6 +++--- src/header/stdio/mod.rs | 29 ++++++++++++++--------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/header/stdio/default.rs b/src/header/stdio/default.rs index 592a77845b..b86115e2d6 100644 --- a/src/header/stdio/default.rs +++ b/src/header/stdio/default.rs @@ -2,6 +2,7 @@ use super::{constants, Buffer, BUFSIZ, FILE}; use core::{cell::UnsafeCell, ptr}; use crate::{fs::File, io::LineWriter, platform::types::*, sync::Mutex}; +use alloc::vec::Vec; pub struct GlobalFile(UnsafeCell); impl GlobalFile { @@ -16,7 +17,7 @@ impl GlobalFile { read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]), read_pos: 0, read_size: 0, - unget: None, + unget: Vec::new(), writer, pid: None, diff --git a/src/header/stdio/helpers.rs b/src/header/stdio/helpers.rs index 399a8a8991..6d5d9da841 100644 --- a/src/header/stdio/helpers.rs +++ b/src/header/stdio/helpers.rs @@ -1,5 +1,6 @@ use alloc::boxed::Box; +use super::{constants::*, Buffer, FILE}; use crate::{ fs::File, header::{errno, fcntl::*, string::strchr}, @@ -7,8 +8,7 @@ use crate::{ platform::{self, types::*}, sync::Mutex, }; - -use super::{constants::*, Buffer, FILE}; +use alloc::vec::Vec; /// Parse mode flags as a string and output a mode flags integer pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 { @@ -72,7 +72,7 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> { read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]), read_pos: 0, read_size: 0, - unget: None, + unget: Vec::new(), writer, pid: None, diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 0163ea1c86..636c6a1ae5 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -6,6 +6,7 @@ use alloc::{ vec::Vec, }; use core::{ + cmp, ffi::VaList as va_list, fmt::{self, Write as WriteFmt}, mem, @@ -76,7 +77,7 @@ pub struct FILE { read_buf: Buffer<'static>, read_pos: usize, read_size: usize, - unget: Option, + unget: Vec, // pub for stdio_ext pub(crate) writer: LineWriter, @@ -86,11 +87,12 @@ pub struct FILE { impl Read for FILE { fn read(&mut self, out: &mut [u8]) -> io::Result { - if !out.is_empty() { - if let Some(c) = self.unget.take() { - out[0] = c; - return Ok(1); - } + let unget_read_size = cmp::min(out.len(), self.unget.len()); + for i in 0..unget_read_size { + out[i] = self.unget.pop().unwrap(); + } + if unget_read_size != 0 { + return Ok(unget_read_size); } let len = { @@ -311,11 +313,12 @@ pub unsafe extern "C" fn fgets( let mut wrote = false; if left >= 1 { - if let Some(c) = stream.unget.take() { - *out = c as c_char; + let unget_read_size = cmp::min(left, stream.unget.len()); + for _ in 0..unget_read_size { + *out = stream.unget.pop().unwrap() as i8; out = out.offset(1); - left -= 1; } + left -= unget_read_size; } loop { @@ -533,7 +536,7 @@ pub unsafe extern "C" fn fseeko(stream: *mut FILE, mut off: off_t, whence: c_int stream.flags &= !(F_EOF | F_ERR); stream.read_pos = 0; stream.read_size = 0; - stream.unget = None; + stream.unget = Vec::new(); 0 } @@ -990,11 +993,7 @@ unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_cha #[no_mangle] pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { let mut stream = (*stream).lock(); - if stream.unget.is_some() { - platform::errno = errno::EIO; - return EOF; - } - stream.unget = Some(c as u8); + stream.unget.push(c as u8); c } From 49dec86a5da0b71ac1b12edfafeb91e3d7eed7a9 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Fri, 22 May 2020 23:28:28 +0200 Subject: [PATCH 3/9] Unit test arbitrarily long ungetc() --- tests/Makefile | 1 + tests/expected/stdio/ungetc_multiple.stderr | 0 tests/expected/stdio/ungetc_multiple.stdout | 1 + tests/stdio/ungetc_multiple.c | 27 +++++++++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 tests/expected/stdio/ungetc_multiple.stderr create mode 100644 tests/expected/stdio/ungetc_multiple.stdout create mode 100644 tests/stdio/ungetc_multiple.c diff --git a/tests/Makefile b/tests/Makefile index a6f967a872..00facce3bf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -42,6 +42,7 @@ EXPECT_NAMES=\ stdio/setvbuf \ stdio/sprintf \ stdio/printf_space_pad \ + stdio/ungetc_multiple \ stdlib/a64l \ stdlib/alloc \ stdlib/atof \ diff --git a/tests/expected/stdio/ungetc_multiple.stderr b/tests/expected/stdio/ungetc_multiple.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/ungetc_multiple.stdout b/tests/expected/stdio/ungetc_multiple.stdout new file mode 100644 index 0000000000..3b18e512db --- /dev/null +++ b/tests/expected/stdio/ungetc_multiple.stdout @@ -0,0 +1 @@ +hello world diff --git a/tests/stdio/ungetc_multiple.c b/tests/stdio/ungetc_multiple.c new file mode 100644 index 0000000000..611430489a --- /dev/null +++ b/tests/stdio/ungetc_multiple.c @@ -0,0 +1,27 @@ +#include +int main() { + ungetc('\n', stdin); + ungetc('d', stdin); + ungetc('l', stdin); + ungetc('r', stdin); + ungetc('o', stdin); + ungetc('w', stdin); + ungetc(' ', stdin); + ungetc('o', stdin); + ungetc('l', stdin); + ungetc('l', stdin); + ungetc('e', stdin); + ungetc('h', stdin); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); + putchar(getchar()); +} From 1733b3da6e33c274173294b02e432b532c6dcdc9 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 12:53:39 +0200 Subject: [PATCH 4/9] Fix bug related to ungetc and ftell() At least in relibc, each call to ungetc should decrement ftell() by one also allowing negative ftell() this is not possible on relibc thus gcc failing to compile (gcc compiles tools that is later used to compile gcc itself and these tools are the ones that fail) --- src/header/stdio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 636c6a1ae5..260f6e5cde 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -561,7 +561,7 @@ pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { return -1; } - pos - (stream.read_size - stream.read_pos) as off_t + pos - (stream.read_size - stream.read_pos) as off_t - stream.unget.len() as off_t } /// Try to lock the file. Returns 0 for success, 1 for failure From 6fba592fdb49a230d2d7a2320f917949ad9a9d5b Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 12:55:10 +0200 Subject: [PATCH 5/9] Implement regression test for ftell-ungetc bug --- tests/Makefile | 1 + tests/expected/stdio/ungetc_ftell.stderr | 0 tests/expected/stdio/ungetc_ftell.stdout | 28 ++++++++++++++++++ tests/stdio/ungetc_ftell.c | 37 ++++++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 tests/expected/stdio/ungetc_ftell.stderr create mode 100644 tests/expected/stdio/ungetc_ftell.stdout create mode 100644 tests/stdio/ungetc_ftell.c diff --git a/tests/Makefile b/tests/Makefile index 00facce3bf..bc6123d676 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -43,6 +43,7 @@ EXPECT_NAMES=\ stdio/sprintf \ stdio/printf_space_pad \ stdio/ungetc_multiple \ + stdio/ungetc_ftell \ stdlib/a64l \ stdlib/alloc \ stdlib/atof \ diff --git a/tests/expected/stdio/ungetc_ftell.stderr b/tests/expected/stdio/ungetc_ftell.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/ungetc_ftell.stdout b/tests/expected/stdio/ungetc_ftell.stdout new file mode 100644 index 0000000000..e36f413519 --- /dev/null +++ b/tests/expected/stdio/ungetc_ftell.stdout @@ -0,0 +1,28 @@ +#, 0 +i, 1 +n, 2 +h, -9 +e, -8 +l, -7 +l, -6 +o, -5 + , -4 +w, -3 +o, -2 +r, -1 +l, 0 +d, 1 + +, 2 +c, 3 +l, 4 +u, 5 +d, 6 +e, 7 + , 8 +<, 9 +s, 10 +t, 11 +d, 12 +i, 13 +o, 14 diff --git a/tests/stdio/ungetc_ftell.c b/tests/stdio/ungetc_ftell.c new file mode 100644 index 0000000000..10be6a3057 --- /dev/null +++ b/tests/stdio/ungetc_ftell.c @@ -0,0 +1,37 @@ +#include +int main() { + FILE *f = fopen("stdio/ungetc_ftell.c", "r"); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + ungetc('\n', f);ungetc('d', f); + ungetc('l', f); ungetc('r', f); + ungetc('o', f); ungetc('w', f); + ungetc(' ', f); ungetc('o', f); + ungetc('l', f); ungetc('l', f); + ungetc('e', f); ungetc('h', f); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); + printf("%c, %ld\n", getc(f), ftell(f)); +} From d7d3e008672d450d2ddda6a79f85cdb29147a1e4 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 13:20:52 +0200 Subject: [PATCH 6/9] Fix off-by-1 error in vfscanf Scanf function requires look ahead to function properly, In case of scanning from a buffer that will not be an issue, but in our case we are reading from file, so lookaheads needs to be undone (via lseek) in our case. The only problem here is that if we opened a file that doesn't support lseek such as many of the file /dev/* --- src/header/stdio/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 260f6e5cde..375409c2e0 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -1041,8 +1041,12 @@ pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_ #[no_mangle] pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int { - let mut file = (*file).lock(); - scanf::scanf(&mut *file, format, ap) + let ret = { + let mut file = (*file).lock(); + scanf::scanf(&mut *file, format, ap) + }; + fseeko(file, -1, SEEK_CUR); + ret } #[no_mangle] From 1b131b8c600bc9de8b38b0227637b67f2dfc56bc Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 13:23:31 +0200 Subject: [PATCH 7/9] Test off by one bug in vfscanf --- tests/Makefile | 1 + tests/expected/stdio/fscanf_offby1.stderr | 0 tests/expected/stdio/fscanf_offby1.stdout | 1 + tests/stdio/fscanf_offby1.c | 8 ++++++++ 4 files changed, 10 insertions(+) create mode 100644 tests/expected/stdio/fscanf_offby1.stderr create mode 100644 tests/expected/stdio/fscanf_offby1.stdout create mode 100644 tests/stdio/fscanf_offby1.c diff --git a/tests/Makefile b/tests/Makefile index bc6123d676..c6958733d2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -44,6 +44,7 @@ EXPECT_NAMES=\ stdio/printf_space_pad \ stdio/ungetc_multiple \ stdio/ungetc_ftell \ + stdio/fscanf_offby1 \ stdlib/a64l \ stdlib/alloc \ stdlib/atof \ diff --git a/tests/expected/stdio/fscanf_offby1.stderr b/tests/expected/stdio/fscanf_offby1.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/fscanf_offby1.stdout b/tests/expected/stdio/fscanf_offby1.stdout new file mode 100644 index 0000000000..daf724a9e5 --- /dev/null +++ b/tests/expected/stdio/fscanf_offby1.stdout @@ -0,0 +1 @@ +1234, 7, 32 diff --git a/tests/stdio/fscanf_offby1.c b/tests/stdio/fscanf_offby1.c new file mode 100644 index 0000000000..c833935793 --- /dev/null +++ b/tests/stdio/fscanf_offby1.c @@ -0,0 +1,8 @@ +//1234 a +#include +int main() { + FILE *f = fopen("stdio/fscanf_offby1.c", "r"); + int x; + fscanf(f, "//%d", &x); + printf("%d, %ld, %d\n", x, ftell(f), fgetc(f)); +} From ee5e2bad5ac24bbb87439b6b3b66a0dd812197b6 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 14:59:12 +0200 Subject: [PATCH 8/9] Support negative padding size in printf and friends as it seams you can do something like printf ("A%*s%s/\n", -5, "B", "CC"); and it will print the padding to the left --- src/header/stdio/printf.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/header/stdio/printf.rs b/src/header/stdio/printf.rs index 727de95264..4c5550bebe 100644 --- a/src/header/stdio/printf.rs +++ b/src/header/stdio/printf.rs @@ -660,16 +660,22 @@ unsafe fn inner_printf(w: W, format: *const c_char, mut ap: VaList) -> }; let alternate = arg.alternate; let zero = arg.zero; - let left = arg.left; + let mut left = arg.left; let sign_reserve = arg.sign_reserve; let sign_always = arg.sign_always; let min_width = arg.min_width.resolve(&mut varargs, &mut ap); let precision = arg.precision.map(|n| n.resolve(&mut varargs, &mut ap)); let pad_zero = arg.pad_zero.resolve(&mut varargs, &mut ap); - let pad_space = match pad_zero { - 0 => min_width, + let signed_space = match pad_zero { + 0 => min_width as isize, _ => 0, }; + let pad_space = if signed_space < 0 { + left = true; + -signed_space as usize + } else { + signed_space as usize + }; let intkind = arg.intkind; let fmt = arg.fmt; let fmtkind = arg.fmtkind; From 7eba6d88dfc7ba2fb26737e2dc3207d79292b849 Mon Sep 17 00:00:00 2001 From: oddcoder Date: Sat, 23 May 2020 15:29:16 +0200 Subject: [PATCH 9/9] Add test for negative pad stupport in printf --- tests/Makefile | 1 + tests/expected/stdio/printf_neg_pad.stderr | 0 tests/expected/stdio/printf_neg_pad.stdout | 2 ++ tests/stdio/printf_neg_pad.c | 5 +++++ 4 files changed, 8 insertions(+) create mode 100644 tests/expected/stdio/printf_neg_pad.stderr create mode 100644 tests/expected/stdio/printf_neg_pad.stdout create mode 100644 tests/stdio/printf_neg_pad.c diff --git a/tests/Makefile b/tests/Makefile index c6958733d2..7ff599552b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -45,6 +45,7 @@ EXPECT_NAMES=\ stdio/ungetc_multiple \ stdio/ungetc_ftell \ stdio/fscanf_offby1 \ + stdio/printf_neg_pad \ stdlib/a64l \ stdlib/alloc \ stdlib/atof \ diff --git a/tests/expected/stdio/printf_neg_pad.stderr b/tests/expected/stdio/printf_neg_pad.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/printf_neg_pad.stdout b/tests/expected/stdio/printf_neg_pad.stdout new file mode 100644 index 0000000000..f573a2b6d2 --- /dev/null +++ b/tests/expected/stdio/printf_neg_pad.stdout @@ -0,0 +1,2 @@ +A BCC/ +AB CC/ diff --git a/tests/stdio/printf_neg_pad.c b/tests/stdio/printf_neg_pad.c new file mode 100644 index 0000000000..7f443034b9 --- /dev/null +++ b/tests/stdio/printf_neg_pad.c @@ -0,0 +1,5 @@ +#include +int main() { + printf ("A%*s%s/\n", 5, "B", "CC"); + printf ("A%*s%s/\n", -5, "B", "CC"); +}