Change:
FIXME says "turn mode into something useful?"
We appear to only ignore the mode argument on Windows, so this will need someone who knows how Windows prefers to handle modes.
I think we ought to abstract concepts like file-modes at the level into more portable sets of flags. As doing so will change API, I think this is properly classified.
cc me
The API's have been cleaned up a lot but this comment still exists in native::file. We can probably look at what libuv does with these flags for some hints as to what to do on windows. We are still directly exposing the unix permission flags in the API and we might want to reconsider whether this is right. In particular we are still just or-ing together bits instead of using something type safe, not to mention that the unix model doesn't make so much sense on windows.
Updated title to better reflect the problem: our file API's expose unix-style file permissions that are simply ignored on windows.
File systems without support for permission bits are often used on Linux and other nix operating systems. The issue is handled by pretending setting permissions worked, even though it's not doing anything. Since we're already forced into this behaviour on nix for a file system like FAT32, we do already have a consistent API on Windows. Unless someone can explain what we're doing wrong, I don't see a bug here.

Discussion:
branches: - 'master' schedule: <del> - cron: '5 15 * * *' # At 15:05 UTC every day. </del> <ins> - cron: '6 6 * * *' # At 6:06 UTC every day. </ins> env: CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'

strategy: fail-fast: false matrix: <del> build: [linux64, macos, win32] </del> include: <del> - build: linux64 os: ubuntu-latest </del> <ins> - os: ubuntu-latest </ins> host_target: x86_64-unknown-linux-gnu <del> - build: macos os: macos-latest </del> <ins> - os: macos-latest </ins> host_target: x86_64-apple-darwin <del> - build: win32 os: windows-latest </del> <ins> - os: windows-latest </ins> host_target: i686-pc-windows-msvc steps: - uses: actions/checkout@v3

;; i686-pc-windows-msvc) MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests <ins> MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests </ins> ;; *) echo "FATAL: unknown OS"

mir, ty::{self, FloatTy, Ty}, }; <del> use rustc_target::abi::Integer; </del> <ins> use rustc_target::abi::{Integer, Size}; </ins> use crate::*; use atomic::EvalContextExt as _;

this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?; } <ins> "ptr_mask" => { let [ptr, mask] = check_arg_count(args)?; let ptr = this.read_pointer(ptr)?; let mask = this.read_scalar(mask)?.to_machine_usize(this)?; let masked_addr = Size::from_bytes(ptr.addr().bytes() & mask); this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?; } </ins> // Floating-point operations "fabsf32" => { let [f] = check_arg_count(args)?;

let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let thread = this.pthread_self()?; let max_len = this.eval_libc("MAXTHREADNAMESIZE")?.to_machine_usize(this)?; <del> this.pthread_setname_np( </del> <ins> let res = this.pthread_setname_np( </ins> thread, this.read_scalar(name)?, max_len.try_into().unwrap(), )?; <ins> // Contrary to the manpage, `pthread_setname_np` on macOS still // returns an integer indicating success. this.write_scalar(res, dest)?; </ins> } "pthread_getname_np" => { let [thread, name, len] =

//@ignore-target-windows: No libc on Windows #![feature(cstr_from_bytes_until_nul)] <del> use std::ffi::CStr; </del> <ins> use std::ffi::{CStr, CString}; </ins> use std::thread; fn main() {

.chain(std::iter::repeat(" yada").take(100)) .collect::<String>(); <ins> fn set_thread_name(name: &CStr) -> i32 { #[cfg(target_os = "linux")] return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }; #[cfg(target_os = "macos")] return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }; } </ins> let result = thread::Builder::new().name(long_name.clone()).spawn(move || { // Rust remembers the full thread name itself. assert_eq!(thread::current().name(), Some(long_name.as_str()));

// But the system is limited -- make sure we successfully set a truncation. let mut buf = vec![0u8; long_name.len() + 1]; unsafe { <del> libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); } </del> <ins> libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()) }; </ins> let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); assert!(cstr.to_bytes().len() >= 15); // POSIX seems to promise at least 15 chars assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); <ins> // Also test directly calling pthread_setname to check its return value. assert_eq!(set_thread_name(&cstr), 0); // But with a too long name it should fail. assert_ne!(set_thread_name(&CString::new(long_name).unwrap()), 0); </ins> }); result.unwrap().join().unwrap(); }

<ins> #![feature(ptr_mask)] #![feature(strict_provenance)] fn main() { let v: u32 = 0xABCDABCD; let ptr: *const u32 = &v; // u32 is 4 aligned, // so the lower `log2(4) = 2` bits of the address are always 0 assert_eq!(ptr.addr() & 0b11, 0); let tagged_ptr = ptr.map_addr(|a| a | 0b11); let tag = tagged_ptr.addr() & 0b11; let masked_ptr = tagged_ptr.mask(!0b11); assert_eq!(tag, 0b11); assert_eq!(unsafe { *masked_ptr }, 0xABCDABCD); } </ins>