diff --git a/src/crti/src/lib.rs b/src/crti/src/lib.rs index 8071f05900..77e8f055da 100644 --- a/src/crti/src/lib.rs +++ b/src/crti/src/lib.rs @@ -27,7 +27,8 @@ global_asm!( ); // https://git.musl-libc.org/cgit/musl/tree/crt/aarch64/crti.s #[cfg(target_arch = "aarch64")] -global_asm!(r#" +global_asm!( + r#" .section .init .global _init .type _init,%function @@ -45,7 +46,8 @@ global_asm!(r#" mov x29,sp // stp: "stores two doublewords from the first and second argument to memory addressed by addr" // Body will be filled in by gcc and ended by crtn.o -"#); +"# +); #[panic_handler] #[linkage = "weak"] diff --git a/src/crtn/src/lib.rs b/src/crtn/src/lib.rs index 6704d357e9..b2d9608678 100644 --- a/src/crtn/src/lib.rs +++ b/src/crtn/src/lib.rs @@ -23,7 +23,8 @@ global_asm!( ); // https://git.musl-libc.org/cgit/musl/tree/crt/aarch64/crtn.s #[cfg(target_arch = "aarch64")] -global_asm!(r#" +global_asm!( + r#" .section .init // This happens after crti.o and gcc has inserted code // ldp: "loads two doublewords from memory addressed by the third argument to the first and second" @@ -35,7 +36,8 @@ global_asm!(r#" // ldp: "loads two doublewords from memory addressed by the third argument to the first and second" ldp x29,x30,[sp],#16 ret -"#); +"# +); #[panic_handler] #[linkage = "weak"] diff --git a/src/header/stdio/lookaheadreader.rs b/src/header/stdio/lookaheadreader.rs new file mode 100644 index 0000000000..91092f5af5 --- /dev/null +++ b/src/header/stdio/lookaheadreader.rs @@ -0,0 +1,95 @@ +use super::{fseek_locked, ftell_locked, FILE, SEEK_SET}; +use crate::core_io::Read; +struct LookAheadBuffer { + buf: *const u8, + pos: isize, + look_ahead: isize, +} +impl LookAheadBuffer { + fn look_ahead(&mut self) -> Result, i32> { + let byte = unsafe { *self.buf.offset(self.look_ahead) }; + self.look_ahead += 1; + Ok(Some(byte)) + } + + fn commit(&mut self) { + self.pos = self.look_ahead; + } +} + +impl From<*const u8> for LookAheadBuffer { + fn from(buff: *const u8) -> LookAheadBuffer { + LookAheadBuffer { + buf: buff, + pos: 0, + look_ahead: 0, + } + } +} + +struct LookAheadFile<'a> { + f: &'a mut FILE, + look_ahead: i64, +} + +impl<'a> LookAheadFile<'a> { + fn look_ahead(&mut self) -> Result, i32> { + let buf = &mut [0]; + let seek = unsafe { ftell_locked(self.f) }; + unsafe { fseek_locked(self.f, self.look_ahead, SEEK_SET) }; + let ret = match self.f.read(buf) { + Ok(0) => Ok(None), + Ok(_) => Ok(Some(buf[0])), + Err(_) => Err(-1), + }; + unsafe { fseek_locked(self.f, seek, SEEK_SET) }; + self.look_ahead += 1; + ret + } + + fn commit(&mut self) { + unsafe { fseek_locked(self.f, self.look_ahead, SEEK_SET) }; + } +} + +impl<'a> From<&'a mut FILE> for LookAheadFile<'a> { + fn from(f: &'a mut FILE) -> LookAheadFile<'a> { + let look_ahead = unsafe { ftell_locked(f) } as i64; + LookAheadFile { f, look_ahead } + } +} + +enum LookAheadReaderEnum<'a> { + FILE(LookAheadFile<'a>), + // (buffer, location) + BUFFER(LookAheadBuffer), +} + +pub struct LookAheadReader<'a>(LookAheadReaderEnum<'a>); + +impl<'a> LookAheadReader<'a> { + pub fn lookahead1(&mut self) -> Result, i32> { + match &mut self.0 { + LookAheadReaderEnum::FILE(f) => f.look_ahead(), + LookAheadReaderEnum::BUFFER(b) => b.look_ahead(), + } + } + pub fn commit(&mut self) { + match &mut self.0 { + LookAheadReaderEnum::FILE(f) => f.commit(), + LookAheadReaderEnum::BUFFER(b) => b.commit(), + } + } +} + +impl<'a> From<&'a mut FILE> for LookAheadReader<'a> { + fn from(f: &'a mut FILE) -> LookAheadReader { + LookAheadReader(LookAheadReaderEnum::FILE(f.into())) + } +} + +impl<'a> From<*const u8> for LookAheadReader<'a> { + fn from(buff: *const u8) -> LookAheadReader<'a> { + LookAheadReader(LookAheadReaderEnum::BUFFER(buff.into())) + } +} diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 375409c2e0..2b22cf4ac5 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -39,9 +39,10 @@ mod getdelim; mod ext; mod helpers; +mod lookaheadreader; mod printf; mod scanf; - +use lookaheadreader::LookAheadReader; static mut TMPNAM_BUF: [c_char; L_tmpnam as usize + 1] = [0; L_tmpnam as usize + 1]; enum Buffer<'a> { @@ -514,9 +515,12 @@ pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) /// Seek to an offset `offset` from `whence` #[no_mangle] -pub unsafe extern "C" fn fseeko(stream: *mut FILE, mut off: off_t, whence: c_int) -> c_int { +pub unsafe extern "C" fn fseeko(stream: *mut FILE, off: off_t, whence: c_int) -> c_int { let mut stream = (*stream).lock(); + fseek_locked(&mut *stream, off, whence) +} +pub unsafe fn fseek_locked(stream: &mut FILE, mut off: off_t, whence: c_int) -> c_int { if whence == SEEK_CUR { // Since it's a buffered writer, our actual cursor isn't where the user // thinks @@ -555,7 +559,10 @@ pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long { /// Get the current position of the cursor in the file #[no_mangle] pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { - let stream = (*stream).lock(); + let mut stream = (*stream).lock(); + ftell_locked(&mut *stream) +} +pub unsafe extern "C" fn ftell_locked(stream: &mut FILE) -> off_t { let pos = Sys::lseek(*stream.file, 0, SEEK_CUR); if pos < 0 { return -1; @@ -1043,9 +1050,10 @@ pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_ pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int { let ret = { let mut file = (*file).lock(); - scanf::scanf(&mut *file, format, ap) + let f: &mut FILE = &mut *file; + let reader: LookAheadReader = f.into(); + scanf::scanf(reader, format, ap) }; - fseeko(file, -1, SEEK_CUR); ret } @@ -1056,9 +1064,6 @@ pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int { #[no_mangle] pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int { - scanf::scanf( - &mut platform::UnsafeStringReader(s as *const u8), - format, - ap, - ) + let reader = (s as *const u8).into(); + scanf::scanf(reader, format, ap) } diff --git a/src/header/stdio/scanf.rs b/src/header/stdio/scanf.rs index e8af010b4d..8a88a31630 100644 --- a/src/header/stdio/scanf.rs +++ b/src/header/stdio/scanf.rs @@ -1,4 +1,5 @@ -use crate::{io::Read, platform::types::*}; +use super::lookaheadreader::LookAheadReader; +use crate::platform::types::*; use alloc::{string::String, vec::Vec}; use core::ffi::VaList as va_list; @@ -25,8 +26,8 @@ unsafe fn next_byte(string: &mut *const c_char) -> Result { } } -unsafe fn inner_scanf( - mut r: R, +unsafe fn inner_scanf( + mut r: LookAheadReader, mut format: *const c_char, mut ap: va_list, ) -> Result { @@ -37,15 +38,14 @@ unsafe fn inner_scanf( macro_rules! read { () => {{ - let buf = &mut [byte]; - match r.read(buf) { - Ok(0) => false, - Ok(_) => { - byte = buf[0]; + match r.lookahead1() { + Ok(None) => false, + Ok(Some(b)) => { + byte = b; count += 1; true } - Err(_) => return Err(-1), + Err(x) => return Err(x), } }}; } @@ -59,7 +59,10 @@ unsafe fn inner_scanf( }; (inner $($placeholder:expr)*) => { if !skip_read && !read!() { - return Ok(matched); + match matched { + 0 => return Ok(-1), + a => return Ok(a), + } } $(else { // Hacky way of having this optional @@ -86,6 +89,7 @@ unsafe fn inner_scanf( if c != byte { return Ok(matched); } + r.commit(); } else { c = next_byte(&mut format)?; @@ -215,6 +219,7 @@ unsafe fn inner_scanf( dot = true; } n.push(byte as char); + r.commit(); width = width.map(|w| w - 1); if width.map(|w| w > 0).unwrap_or(true) && !read!() { return Ok(matched); @@ -344,6 +349,7 @@ unsafe fn inner_scanf( if let Some(ptr) = ptr { *ptr = 0; matched += 1; + r.commit(); } } b'c' => { @@ -362,6 +368,7 @@ unsafe fn inner_scanf( if ptr.is_some() { matched += 1; + r.commit(); } } b'[' => { @@ -402,12 +409,15 @@ unsafe fn inner_scanf( let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) }; // While we haven't used up all the width, and it matches + let mut data_stored = false; while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte) { if let Some(ref mut ptr) = ptr { **ptr = byte as c_char; *ptr = ptr.offset(1); + data_stored = true; } + r.commit(); // Decrease the width, and read a new character unless the width is 0 width = width.map(|w| w - 1); if width.map(|w| w > 0).unwrap_or(true) && !read!() { @@ -418,8 +428,8 @@ unsafe fn inner_scanf( } } - if let Some(ptr) = ptr { - *ptr = 0; + if data_stored { + *ptr.unwrap() = 0; matched += 1; } } @@ -444,7 +454,8 @@ unsafe fn inner_scanf( } Ok(matched) } -pub unsafe fn scanf(r: R, format: *const c_char, ap: va_list) -> c_int { + +pub unsafe fn scanf(r: LookAheadReader, format: *const c_char, ap: va_list) -> c_int { match inner_scanf(r, format, ap) { Ok(n) => n, Err(n) => n, diff --git a/src/header/sys_random/mod.rs b/src/header/sys_random/mod.rs index 7543ca995d..957f8c7753 100644 --- a/src/header/sys_random/mod.rs +++ b/src/header/sys_random/mod.rs @@ -1,14 +1,14 @@ use core::slice; -use crate::platform::{Pal, Sys, types::*}; +use crate::platform::{types::*, Pal, Sys}; pub const GRND_NONBLOCK: c_uint = 1; pub const GRND_RANDOM: c_uint = 2; #[no_mangle] pub unsafe extern "C" fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t { - Sys::getrandom(slice::from_raw_parts_mut( - buf as *mut u8, - buflen as usize - ), flags) + Sys::getrandom( + slice::from_raw_parts_mut(buf as *mut u8, buflen as usize), + flags, + ) } diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 503fe1b7e3..149f26543f 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -26,10 +26,10 @@ use crate::{ }; use super::{ + access, debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug}, tcb::{Master, Tcb}, PAGE_SIZE, - access, }; #[cfg(target_os = "redox")] diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 46a7a271a9..b39a5e7e26 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -1,11 +1,7 @@ use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader}; use self::tcb::{Master, Tcb}; -use crate::{ -start::Stack, -c_str::CStr, -platform::types::* -}; +use crate::{c_str::CStr, platform::types::*, start::Stack}; pub const PAGE_SIZE: usize = 4096; pub mod debug; @@ -85,8 +81,8 @@ pub fn static_init(sp: &'static Stack) { // Wrapper over the systemcall, Do not use outside of ld_so pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int { - let path = CStr::from_ptr(path); - syscall!(ACCESS, (path).as_ptr(), mode) as c_int + let path = CStr::from_ptr(path); + syscall!(ACCESS, (path).as_ptr(), mode) as c_int } #[cfg(target_os = "linux")] diff --git a/src/platform/redox/ptrace.rs b/src/platform/redox/ptrace.rs index b5fd2d16e6..665f5dcd00 100644 --- a/src/platform/redox/ptrace.rs +++ b/src/platform/redox/ptrace.rs @@ -5,6 +5,10 @@ //! compatibility. So, this module will be a hellhole. use super::super::{errno, types::*, Pal, PalPtrace, PalSignal, Sys}; +#[cfg(target_arch = "aarch64")] +use crate::header::arch_aarch64_user::user_regs_struct; +#[cfg(target_arch = "x86_64")] +use crate::header::arch_x64_user::user_regs_struct; use crate::{ c_str::CString, fs::File, @@ -12,10 +16,6 @@ use crate::{ io::{self, prelude::*}, sync::{Mutex, Once}, }; -#[cfg(target_arch = "aarch64")] -use crate::header::arch_aarch64_user::user_regs_struct; -#[cfg(target_arch = "x86_64")] -use crate::header::arch_x64_user::user_regs_struct; use alloc::collections::{btree_map::Entry, BTreeMap}; use core::mem; diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index 5937bdfb3d..01d6e85193 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -143,7 +143,10 @@ unsafe fn inner_get_name( inner_af_unix(&buf[5..], address, address_len); } else { // Socket doesn't belong to any scheme - panic!("socket {:?} doesn't match either tcp, udp or chan schemes", str::from_utf8(buf)); + panic!( + "socket {:?} doesn't match either tcp, udp or chan schemes", + str::from_utf8(buf) + ); } Ok(0) diff --git a/src/platform/test/mod.rs b/src/platform/test/mod.rs index d5fb9e0478..721db1b930 100644 --- a/src/platform/test/mod.rs +++ b/src/platform/test/mod.rs @@ -68,12 +68,14 @@ fn clock_gettime() { #[test] fn getrandom() { - use crate::header::sys_random; - use crate::platform::types::ssize_t; + use crate::{header::sys_random, platform::types::ssize_t}; let mut arrays = [[0; 32]; 32]; for i in 1..arrays.len() { - assert_eq!(Sys::getrandom(&mut arrays[i], 0), arrays[i].len() as ssize_t); + assert_eq!( + Sys::getrandom(&mut arrays[i], 0), + arrays[i].len() as ssize_t + ); for j in 0..arrays.len() { if i != j { diff --git a/tests/Makefile b/tests/Makefile index 7ff599552b..594b17d6d4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -45,6 +45,7 @@ EXPECT_NAMES=\ stdio/ungetc_multiple \ stdio/ungetc_ftell \ stdio/fscanf_offby1 \ + stdio/fscanf \ stdio/printf_neg_pad \ stdlib/a64l \ stdlib/alloc \ diff --git a/tests/expected/stdio/fscanf.stderr b/tests/expected/stdio/fscanf.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/stdio/fscanf.stdout b/tests/expected/stdio/fscanf.stdout new file mode 100644 index 0000000000..73f11e68cf --- /dev/null +++ b/tests/expected/stdio/fscanf.stdout @@ -0,0 +1,14 @@ +1 2 3 9 +9 +16 +35 +48 +92 +109 +152 +201 +241 +276 +293 +299 +301 diff --git a/tests/expected/stdio/scanf.stdout b/tests/expected/stdio/scanf.stdout index 230c9d2a8b..97bcc1af63 100644 --- a/tests/expected/stdio/scanf.stdout +++ b/tests/expected/stdio/scanf.stdout @@ -1,14 +1,14 @@ -1, { sa: 12, ia: 0, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } -2, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } -1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } -0, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } -1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4: } -1, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4: } -2, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: } -1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: } -0, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4: } -4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: e, string2: o, string3: l, string4: d } -4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd } -4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd } -1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: testbbbb, string2: e, string3: f, string4: dddddd } +2, { sa: 12, ia: 345, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } +3, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } +2, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: (nil), char: a, string1: , string2: , string3: , string4: } +1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: , string2: , string3: , string4: } +1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: Hello, string2: , string3: , string4: } +1, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: Hello, string2: , string3: , string4: } +2, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4: } +1, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4: } +0, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4: } +4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: e, string2: o, string3: l, string4: d } +4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: a, string2: e, string3: f, string4: dddddd } +4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: a, string2: e, string3: f, string4: dddddd } +1, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: testbbbb, string2: e, string3: f, string4: dddddd } 3 "https" "//" "redox-os.org" "" diff --git a/tests/stdio/fscanf.c b/tests/stdio/fscanf.c new file mode 100644 index 0000000000..01d4c9c03b --- /dev/null +++ b/tests/stdio/fscanf.c @@ -0,0 +1,13 @@ +//@ 1 2 3 +//@ SS +#include +int main() { + FILE *f = fopen("stdio/fscanf.c", "r"); + int x, y, z; + fscanf(f, "//@ %d %d %d",&x , &y, &z); + printf("%d %d %d %ld\n", x, y, z, ftell(f)); + while(-1 != fscanf(f, "%*[^\n]")) { + printf("%ld\n", ftell(f)); + getc(f); + } +} \ No newline at end of file