From 8e239055bb965448bc24ee57cd512e151a85ec58 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Thu, 4 Jan 2024 19:00:50 +0100 Subject: [PATCH] Use `OsString` for process names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the stat file on Linux was parsed under the assumption that it contains valid UTF-8. This is not necessarily the case for two reasons: 1. Process names don't need to be valid UTF-8 at all on Linux. They can contain invalid bytes. 2. Even if the process name was valid UTF-8, the assumption breaks because the process name is limited to 15 characters, which can cut a valid code point in half. This causes the stat file to not be parseable, causing the entire process not to show up in the list. So even if you aren't using the name of the process at all, you can't find it as part of the list. One solution is to lossily convert the process name to a string. However this means that the [Unicode replacement character `�`](https://www.fileformat.info/info/unicode/char/fffd/index.htm) is now part of those process names. The character when encoded as UTF-8 is 3 bytes. This means that process names can now be longer than 15 bytes, or in other words, doing a name based comparison on the first 15 bytes, such as suggested in the documentation of the crate, is no longer easily possible. The solution is to just provide the name as an `OsString` instead, keeping the bytes around as is. --- .cirrus.yml | 8 +-- .github/workflows/CI.yml | 6 +- Cargo.lock | 25 +++++++ Cargo.toml | 4 +- README.md | 8 +-- examples/simple.rs | 11 ++- src/common.rs | 25 +++---- src/debug.rs | 36 ++-------- src/unix/apple/app_store/process.rs | 6 +- src/unix/apple/cpu.rs | 2 +- src/unix/apple/disk.rs | 1 + src/unix/apple/macos/process.rs | 34 ++++----- src/unix/freebsd/disk.rs | 4 +- src/unix/freebsd/network.rs | 2 +- src/unix/freebsd/process.rs | 7 +- src/unix/freebsd/system.rs | 6 +- src/unix/freebsd/utils.rs | 40 ++++++++--- src/unix/linux/disk.rs | 6 +- src/unix/linux/process.rs | 106 ++++++++++++++++------------ src/unix/linux/system.rs | 8 +-- src/unix/linux/utils.rs | 13 +++- src/unknown/process.rs | 5 +- src/windows/process.rs | 14 ++-- src/windows/sid.rs | 6 +- src/windows/system.rs | 17 +++-- src/windows/users.rs | 6 +- src/windows/utils.rs | 2 +- tests/process.rs | 14 ++-- 28 files changed, 236 insertions(+), 186 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 36d17ed0d2..ac50b608d4 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,10 +1,10 @@ task: - name: rust 1.69 on freebsd 13 + name: rust 1.74 on freebsd 13 freebsd_instance: image: freebsd-13-1-release-amd64 setup_script: - curl https://sh.rustup.rs -sSf --output rustup.sh - - sh rustup.sh -y --profile=minimal --default-toolchain=1.69 + - sh rustup.sh -y --profile=minimal --default-toolchain=1.74 - . $HOME/.cargo/env - rustup --version - rustup component add clippy @@ -37,14 +37,14 @@ task: - FREEBSD_CI=1 cargo test --lib -j1 -- --ignored task: - name: rust 1.69 on mac m1 + name: rust 1.74 on mac m1 macos_instance: image: ghcr.io/cirruslabs/macos-monterey-base:latest setup_script: - brew update - brew install curl - curl https://sh.rustup.rs -sSf --output rustup.sh - - sh rustup.sh -y --profile=minimal --default-toolchain=1.69 + - sh rustup.sh -y --profile=minimal --default-toolchain=1.74 - source $HOME/.cargo/env - rustup --version - rustup component add clippy diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4098a996dd..06978a2859 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -68,7 +68,7 @@ jobs: - { os: 'ubuntu-latest', target: 'x86_64-linux-android', cross: true } - { os: 'ubuntu-latest', target: 'i686-linux-android', cross: true } toolchain: - - "1.69.0" # minimum supported rust version + - "1.74.0" # minimum supported rust version - stable - nightly steps: @@ -139,7 +139,7 @@ jobs: - macos-latest - windows-latest toolchain: - - "1.69.0" # minimum supported rust version + - "1.74.0" # minimum supported rust version - stable - nightly steps: @@ -205,7 +205,7 @@ jobs: strategy: matrix: toolchain: - - "1.69.0" # minimum supported rust version + - "1.74.0" # minimum supported rust version - stable steps: - uses: actions/checkout@v2 diff --git a/Cargo.lock b/Cargo.lock index 88b0bd7440..67b8a13b0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,17 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -104,6 +115,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + [[package]] name = "memoffset" version = "0.9.0" @@ -175,6 +192,12 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" + [[package]] name = "rustix" version = "0.38.28" @@ -240,9 +263,11 @@ dependencies = [ name = "sysinfo" version = "0.30.4" dependencies = [ + "bstr", "cfg-if", "core-foundation-sys", "libc", + "memchr", "ntapi", "once_cell", "rayon", diff --git a/Cargo.toml b/Cargo.toml index 8d7466a561..55fa1d99ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ description = "Library to get system information such as processes, CPUs, disks, repository = "https://github.com/GuillaumeGomez/sysinfo" license = "MIT" readme = "README.md" -rust-version = "1.69" +rust-version = "1.74" exclude = ["/test-unknown"] categories = ["filesystem", "os", "api-bindings"] edition = "2018" @@ -41,6 +41,7 @@ rustdoc-args = ["--generate-link-to-definition"] [dependencies] cfg-if = "1.0" +memchr = "2.7.1" rayon = { version = "^1.8", optional = true } serde = { version = "^1.0.190", optional = true } @@ -96,3 +97,4 @@ tempfile = "3.9" [dev-dependencies] serde_json = "1.0" # Used in documentation tests. +bstr = "1.9.0" # Used in example diff --git a/README.md b/README.md index 26244eea6c..2ad07847f6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You can still use `sysinfo` on non-supported OSes, it'll simply do nothing and a empty values. You can check in your program directly if an OS is supported by checking the [`IS_SUPPORTED_SYSTEM`] constant. -The minimum-supported version of `rustc` is **1.69**. +The minimum-supported version of `rustc` is **1.74**. ## Usage @@ -68,7 +68,7 @@ println!("NB CPUs: {}", sys.cpus().len()); // Display processes ID, name na disk usage: for (pid, process) in sys.processes() { - println!("[{pid}] {} {:?}", process.name(), process.disk_usage()); + println!("[{pid}] {:?} {:?}", process.name(), process.disk_usage()); } // We display all disks' information: @@ -176,8 +176,8 @@ virtual systems. Apple has restrictions as to which APIs can be linked into binaries that are distributed through the app store. By default, `sysinfo` is not compatible with these restrictions. You can use the `apple-app-store` -feature flag to disable the Apple prohibited features. This also enables the `apple-sandbox` feature. -In the case of applications using the sandbox outside of the app store, the `apple-sandbox` feature +feature flag to disable the Apple prohibited features. This also enables the `apple-sandbox` feature. +In the case of applications using the sandbox outside of the app store, the `apple-sandbox` feature can be used alone to avoid causing policy violations at runtime. ### How it works diff --git a/examples/simple.rs b/examples/simple.rs index 34634150a8..15ce7be45b 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -4,6 +4,7 @@ #![allow(unused_must_use, non_upper_case_globals)] #![allow(clippy::manual_range_contains)] +use bstr::ByteSlice; use std::io::{self, BufRead, Write}; use std::str::FromStr; use sysinfo::{Components, Disks, Networks, Pid, Signal, System, Users}; @@ -242,7 +243,7 @@ fn interpret_input( &mut io::stdout(), "{}:{} status={:?}", pid, - proc_.name(), + proc_.name().as_encoded_bytes().as_bstr(), proc_.status() ); } @@ -289,8 +290,12 @@ fn interpret_input( }; } else { let proc_name = tmp[1]; - for proc_ in sys.processes_by_name(proc_name) { - writeln!(&mut io::stdout(), "==== {} ====", proc_.name()); + for proc_ in sys.processes_by_name(proc_name.as_ref()) { + writeln!( + &mut io::stdout(), + "==== {} ====", + proc_.name().as_encoded_bytes().as_bstr() + ); writeln!(&mut io::stdout(), "{proc_:?}"); } } diff --git a/src/common.rs b/src/common.rs index 798ab1a934..057685fdfd 100644 --- a/src/common.rs +++ b/src/common.rs @@ -412,7 +412,7 @@ impl System { /// /// let s = System::new_all(); /// for (pid, process) in s.processes() { - /// println!("{} {}", pid, process.name()); + /// println!("{} {:?}", pid, process.name()); /// } /// ``` pub fn processes(&self) -> &HashMap { @@ -426,7 +426,7 @@ impl System { /// /// let s = System::new_all(); /// if let Some(process) = s.process(Pid::from(1337)) { - /// println!("{}", process.name()); + /// println!("{:?}", process.name()); /// } /// ``` pub fn process(&self, pid: Pid) -> Option<&Process> { @@ -448,17 +448,18 @@ impl System { /// use sysinfo::System; /// /// let s = System::new_all(); - /// for process in s.processes_by_name("htop") { - /// println!("{} {}", process.pid(), process.name()); + /// for process in s.processes_by_name("htop".as_ref()) { + /// println!("{} {:?}", process.pid(), process.name()); /// } /// ``` pub fn processes_by_name<'a: 'b, 'b>( &'a self, - name: &'b str, + name: &'b OsStr, ) -> impl Iterator + 'b { + let finder = memchr::memmem::Finder::new(name.as_encoded_bytes()); self.processes() .values() - .filter(move |val: &&Process| val.name().contains(name)) + .filter(move |val: &&Process| finder.find(val.name().as_encoded_bytes()).is_some()) } /// Returns an iterator of processes with exactly the given `name`. @@ -476,13 +477,13 @@ impl System { /// use sysinfo::System; /// /// let s = System::new_all(); - /// for process in s.processes_by_exact_name("htop") { - /// println!("{} {}", process.pid(), process.name()); + /// for process in s.processes_by_exact_name("htop".as_ref()) { + /// println!("{} {:?}", process.pid(), process.name()); /// } /// ``` pub fn processes_by_exact_name<'a: 'b, 'b>( &'a self, - name: &'b str, + name: &'b OsStr, ) -> impl Iterator + 'b { self.processes() .values() @@ -830,7 +831,7 @@ impl System { /// /// let s = System::new_all(); /// if let Some(process) = s.process(Pid::from(1337)) { -/// println!("{}", process.name()); +/// println!("{:?}", process.name()); /// } /// ``` pub struct Process { @@ -898,10 +899,10 @@ impl Process { /// /// let s = System::new_all(); /// if let Some(process) = s.process(Pid::from(1337)) { - /// println!("{}", process.name()); + /// println!("{:?}", process.name()); /// } /// ``` - pub fn name(&self) -> &str { + pub fn name(&self) -> &OsStr { self.inner.name() } diff --git a/src/debug.rs b/src/debug.rs index 3926fe8dc1..c9f5023060 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -73,14 +73,7 @@ impl fmt::Debug for Process { impl fmt::Debug for Components { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Components {{ {} }}", - self.iter() - .map(|x| format!("{x:?}")) - .collect::>() - .join(", ") - ) + f.debug_list().entries(self.iter()).finish() } } @@ -109,14 +102,7 @@ impl fmt::Debug for Component { impl fmt::Debug for Networks { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Networks {{ {} }}", - self.iter() - .map(|x| format!("{x:?}")) - .collect::>() - .join(", ") - ) + f.debug_list().entries(self.iter()).finish() } } @@ -141,27 +127,13 @@ impl fmt::Debug for NetworkData { impl fmt::Debug for Disks { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Disks {{ {} }}", - self.iter() - .map(|x| format!("{x:?}")) - .collect::>() - .join(", ") - ) + f.debug_list().entries(self.iter()).finish() } } impl fmt::Debug for Users { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Users {{ {} }}", - self.iter() - .map(|x| format!("{x:?}")) - .collect::>() - .join(", ") - ) + f.debug_list().entries(self.iter()).finish() } } diff --git a/src/unix/apple/app_store/process.rs b/src/unix/apple/app_store/process.rs index 0d90111da4..cfc2e979c1 100644 --- a/src/unix/apple/app_store/process.rs +++ b/src/unix/apple/app_store/process.rs @@ -1,6 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use std::path::Path; +use std::{ffi::OsStr, path::Path}; use crate::{DiskUsage, Gid, Pid, ProcessStatus, Signal, Uid}; @@ -11,8 +11,8 @@ impl ProcessInner { None } - pub(crate) fn name(&self) -> &str { - "" + pub(crate) fn name(&self) -> &OsStr { + OsStr::new("") } pub(crate) fn cmd(&self) -> &[String] { diff --git a/src/unix/apple/cpu.rs b/src/unix/apple/cpu.rs index 5ccb0bf903..18c0e99250 100644 --- a/src/unix/apple/cpu.rs +++ b/src/unix/apple/cpu.rs @@ -186,7 +186,7 @@ pub(crate) unsafe fn get_cpu_frequency() -> u64 { #[cfg(any(target_os = "ios", feature = "apple-sandbox"))] { - return 0; + 0 } #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))] { diff --git a/src/unix/apple/disk.rs b/src/unix/apple/disk.rs index e5025390dd..048c852684 100644 --- a/src/unix/apple/disk.rs +++ b/src/unix/apple/disk.rs @@ -269,6 +269,7 @@ unsafe fn get_dict_value Option>( ) -> Option { #[cfg(target_os = "macos")] let _defined; + #[allow(clippy::infallible_destructuring_match)] let key = match key { DictKey::Extern(val) => val, #[cfg(target_os = "macos")] diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs index 89355586cd..59e55ed55d 100644 --- a/src/unix/apple/macos/process.rs +++ b/src/unix/apple/macos/process.rs @@ -1,6 +1,8 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use std::ffi::{OsStr, OsString}; use std::mem::{self, MaybeUninit}; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; use std::path::{Path, PathBuf}; use libc::{c_int, c_void, kill}; @@ -12,7 +14,7 @@ use crate::sys::system::Wrap; use crate::unix::utils::cstr_to_rust_with_size; pub(crate) struct ProcessInner { - pub(crate) name: String, + pub(crate) name: OsString, pub(crate) cmd: Vec, pub(crate) exe: Option, pid: Pid, @@ -47,7 +49,7 @@ pub(crate) struct ProcessInner { impl ProcessInner { pub(crate) fn new_empty(pid: Pid) -> Self { Self { - name: String::new(), + name: OsString::new(), pid, parent: None, cmd: Vec::new(), @@ -78,7 +80,7 @@ impl ProcessInner { pub(crate) fn new(pid: Pid, parent: Option, start_time: u64, run_time: u64) -> Self { Self { - name: String::new(), + name: OsString::new(), pid, parent, cmd: Vec::new(), @@ -112,7 +114,7 @@ impl ProcessInner { unsafe { Some(kill(self.pid.0, c_signal) == 0) } } - pub(crate) fn name(&self) -> &str { + pub(crate) fn name(&self) -> &OsStr { &self.name } @@ -400,14 +402,10 @@ unsafe fn get_exe_and_name_backup( ) { x if x > 0 => { buffer.set_len(x as _); - let tmp = String::from_utf8_unchecked(buffer); + let tmp = OsString::from_vec(buffer); let exe = PathBuf::from(tmp); if process.name.is_empty() { - process.name = exe - .file_name() - .and_then(|x| x.to_str()) - .unwrap_or("") - .to_owned(); + process.name = exe.file_name().unwrap_or_default().to_owned(); } if exe_needs_update { process.exe = Some(exe); @@ -540,11 +538,7 @@ unsafe fn get_process_infos(process: &mut ProcessInner, refresh_kind: ProcessRef let (exe, proc_args) = get_exe(proc_args); if process.name.is_empty() { - process.name = exe - .file_name() - .and_then(|x| x.to_str()) - .unwrap_or("") - .to_owned(); + process.name = exe.file_name().unwrap_or_default().to_owned(); } if refresh_kind.exe().needs_update(|| process.exe.is_none()) { @@ -568,12 +562,10 @@ unsafe fn get_process_infos(process: &mut ProcessInner, refresh_kind: ProcessRef fn get_exe(data: &[u8]) -> (PathBuf, &[u8]) { let pos = data.iter().position(|c| *c == 0).unwrap_or(data.len()); - unsafe { - ( - Path::new(std::str::from_utf8_unchecked(&data[..pos])).to_path_buf(), - &data[pos..], - ) - } + ( + Path::new(OsStr::from_bytes(&data[..pos])).to_path_buf(), + &data[pos..], + ) } fn get_arguments<'a>( diff --git a/src/unix/freebsd/disk.rs b/src/unix/freebsd/disk.rs index a42bd7ca1c..aac1be0b3d 100644 --- a/src/unix/freebsd/disk.rs +++ b/src/unix/freebsd/disk.rs @@ -6,7 +6,7 @@ use std::ffi::{OsStr, OsString}; use std::os::unix::ffi::OsStringExt; use std::path::{Path, PathBuf}; -use super::utils::c_buf_to_str; +use super::utils::c_buf_to_utf8_str; pub(crate) struct DiskInner { name: OsString, @@ -134,7 +134,7 @@ pub unsafe fn get_all_list(container: &mut Vec) { continue; } - let mount_point = match c_buf_to_str(&fs_info.f_mntonname) { + let mount_point = match c_buf_to_utf8_str(&fs_info.f_mntonname) { Some(m) => m, None => { sysinfo_debug!("Cannot get disk mount point, ignoring it."); diff --git a/src/unix/freebsd/network.rs b/src/unix/freebsd/network.rs index 35e9da62bb..dfa44ca37b 100644 --- a/src/unix/freebsd/network.rs +++ b/src/unix/freebsd/network.rs @@ -79,7 +79,7 @@ impl NetworksInner { if !utils::get_sys_value(&mib, &mut data) { continue; } - if let Some(name) = utils::c_buf_to_string(&data.ifmd_name) { + if let Some(name) = utils::c_buf_to_utf8_string(&data.ifmd_name) { let data = &data.ifmd_data; match self.interfaces.entry(name) { hash_map::Entry::Occupied(mut e) => { diff --git a/src/unix/freebsd/process.rs b/src/unix/freebsd/process.rs index 1c42cd6ba8..bc9fa3a573 100644 --- a/src/unix/freebsd/process.rs +++ b/src/unix/freebsd/process.rs @@ -2,6 +2,7 @@ use crate::{DiskUsage, Gid, Pid, Process, ProcessRefreshKind, ProcessStatus, Signal, Uid}; +use std::ffi::{OsStr, OsString}; use std::fmt; use std::path::{Path, PathBuf}; @@ -41,7 +42,7 @@ impl fmt::Display for ProcessStatus { } pub(crate) struct ProcessInner { - pub(crate) name: String, + pub(crate) name: OsString, pub(crate) cmd: Vec, pub(crate) exe: Option, pub(crate) pid: Pid, @@ -72,7 +73,7 @@ impl ProcessInner { unsafe { Some(libc::kill(self.pid.0, c_signal) == 0) } } - pub(crate) fn name(&self) -> &str { + pub(crate) fn name(&self) -> &OsStr { &self.name } @@ -280,7 +281,7 @@ pub(crate) unsafe fn get_process_data( cwd: None, exe: None, // kvm_getargv isn't thread-safe so we get it in the main thread. - name: String::new(), + name: OsString::new(), // kvm_getargv isn't thread-safe so we get it in the main thread. cmd: Vec::new(), // kvm_getargv isn't thread-safe so we get it in the main thread. diff --git a/src/unix/freebsd/system.rs b/src/unix/freebsd/system.rs index 8b8d66e9af..5a55fe80cb 100644 --- a/src/unix/freebsd/system.rs +++ b/src/unix/freebsd/system.rs @@ -14,7 +14,7 @@ use std::ptr::NonNull; use crate::sys::cpu::{physical_core_count, CpusWrapper}; use crate::sys::process::get_exe; use crate::sys::utils::{ - self, boot_time, c_buf_to_string, from_cstr_array, get_sys_value, get_sys_value_by_name, + self, boot_time, c_buf_to_os_string, from_cstr_array, get_sys_value, get_sys_value_by_name, get_system_info, init_mib, }; @@ -380,7 +380,7 @@ unsafe fn add_missing_proc_info( if !cmd.is_empty() { // First, we try to retrieve the name from the command line. let p = Path::new(&cmd[0]); - if let Some(name) = p.file_name().and_then(|s| s.to_str()) { + if let Some(name) = p.file_name() { proc_inner.name = name.to_owned(); } @@ -395,7 +395,7 @@ unsafe fn add_missing_proc_info( // The name can be cut short because the `ki_comm` field size is limited, // which is why we prefer to get the name from the command line as much as // possible. - proc_inner.name = c_buf_to_string(&kproc.ki_comm).unwrap_or_default(); + proc_inner.name = c_buf_to_os_string(&kproc.ki_comm); } if refresh_kind .environ() diff --git a/src/unix/freebsd/utils.rs b/src/unix/freebsd/utils.rs index 4f7ba5e5af..555f328829 100644 --- a/src/unix/freebsd/utils.rs +++ b/src/unix/freebsd/utils.rs @@ -4,8 +4,9 @@ use crate::{Pid, Process}; use libc::{c_char, c_int, timeval}; use std::cell::UnsafeCell; use std::collections::HashMap; -use std::ffi::CStr; +use std::ffi::{CStr, OsStr, OsString}; use std::mem; +use std::os::unix::ffi::OsStrExt; use std::time::SystemTime; /// This struct is used to switch between the "old" and "new" every time you use "get_mut". @@ -109,20 +110,37 @@ pub(crate) unsafe fn get_sys_value_array(mib: &[c_int], value: &mut [T ) == 0 } -pub(crate) fn c_buf_to_str(buf: &[libc::c_char]) -> Option<&str> { +pub(crate) fn c_buf_to_utf8_str(buf: &[libc::c_char]) -> Option<&str> { unsafe { let buf: &[u8] = std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()); - if let Some(pos) = buf.iter().position(|x| *x == 0) { + std::str::from_utf8(if let Some(pos) = buf.iter().position(|x| *x == 0) { // Shrink buffer to terminate the null bytes - std::str::from_utf8(&buf[..pos]).ok() + &buf[..pos] } else { - std::str::from_utf8(buf).ok() - } + buf + }) + .ok() + } +} + +pub(crate) fn c_buf_to_utf8_string(buf: &[libc::c_char]) -> Option { + c_buf_to_utf8_str(buf).map(|s| s.to_owned()) +} + +pub(crate) fn c_buf_to_os_str(buf: &[libc::c_char]) -> &OsStr { + unsafe { + let buf: &[u8] = std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()); + OsStr::from_bytes(if let Some(pos) = buf.iter().position(|x| *x == 0) { + // Shrink buffer to terminate the null bytes + &buf[..pos] + } else { + buf + }) } } -pub(crate) fn c_buf_to_string(buf: &[libc::c_char]) -> Option { - c_buf_to_str(buf).map(|s| s.to_owned()) +pub(crate) fn c_buf_to_os_string(buf: &[libc::c_char]) -> OsString { + c_buf_to_os_str(buf).to_owned() } pub(crate) unsafe fn get_sys_value_str(mib: &[c_int], buf: &mut [libc::c_char]) -> Option { @@ -138,7 +156,7 @@ pub(crate) unsafe fn get_sys_value_str(mib: &[c_int], buf: &mut [libc::c_char]) { return None; } - c_buf_to_string(&buf[..len / mem::size_of::()]) + c_buf_to_utf8_string(&buf[..len / mem::size_of::()]) } pub(crate) unsafe fn get_sys_value_by_name(name: &[u8], value: &mut T) -> bool { @@ -180,7 +198,7 @@ pub(crate) fn get_sys_value_str_by_name(name: &[u8]) -> Option { ) == 0 && size > 0 { - c_buf_to_string(&buf) + c_buf_to_utf8_string(&buf) } else { // getting the system value failed None @@ -224,7 +242,7 @@ pub(crate) fn get_system_info(mib: &[c_int], default: Option<&str>) -> Option DiskKind { .join(trimmed) .join("queue/rotational"); // Normally, this file only contains '0' or '1' but just in case, we get 8 bytes... - match get_all_data(path, 8) + match get_all_utf8_data(path, 8) .unwrap_or_default() .trim() .parse() diff --git a/src/unix/linux/process.rs b/src/unix/linux/process.rs index 9c1d55834d..ae75c2fa1c 100644 --- a/src/unix/linux/process.rs +++ b/src/unix/linux/process.rs @@ -2,23 +2,24 @@ use std::cell::UnsafeCell; use std::collections::{HashMap, HashSet}; -use std::ffi::OsStr; -use std::fmt; +use std::ffi::{OsStr, OsString}; use std::fs::{self, DirEntry, File}; use std::io::Read; +use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::{fmt, str}; use libc::{c_ulong, gid_t, kill, uid_t}; use crate::sys::system::SystemInfo; -use crate::sys::utils::{ - get_all_data, get_all_data_from_file, realpath, FileCounter, PathHandler, PathPush, -}; +use crate::sys::utils::{get_all_data_from_file, realpath, FileCounter, PathHandler, PathPush}; use crate::{ DiskUsage, Gid, Pid, Process, ProcessRefreshKind, ProcessStatus, Signal, ThreadKind, Uid, }; +use super::utils::get_all_utf8_data; + #[doc(hidden)] impl From for ProcessStatus { fn from(status: char) -> ProcessStatus { @@ -62,7 +63,6 @@ impl fmt::Display for ProcessStatus { #[repr(usize)] enum ProcIndex { Pid = 0, - ShortExe, State, ParentPid, GroupId, @@ -92,7 +92,7 @@ enum ProcIndex { const PF_KTHREAD: c_ulong = 0x00200000; pub(crate) struct ProcessInner { - pub(crate) name: String, + pub(crate) name: OsString, pub(crate) cmd: Vec, pub(crate) exe: Option, pub(crate) pid: Pid, @@ -129,7 +129,7 @@ pub(crate) struct ProcessInner { impl ProcessInner { pub(crate) fn new(pid: Pid, proc_path: PathBuf) -> Self { Self { - name: String::new(), + name: OsString::new(), pid, parent: None, cmd: Vec::new(), @@ -169,7 +169,7 @@ impl ProcessInner { unsafe { Some(kill(self.pid.0, c_signal) == 0) } } - pub(crate) fn name(&self) -> &str { + pub(crate) fn name(&self) -> &OsStr { &self.name } @@ -310,7 +310,7 @@ pub(crate) fn set_time(p: &mut ProcessInner, utime: u64, stime: u64) { } pub(crate) fn update_process_disk_activity(p: &mut ProcessInner, path: &mut PathHandler) { - let data = match get_all_data(path.join("io"), 16_384) { + let data = match get_all_utf8_data(path.join("io"), 16_384) { Ok(d) => d, Err(_) => return, }; @@ -355,13 +355,13 @@ unsafe impl<'a, T> Send for Wrap<'a, T> {} unsafe impl<'a, T> Sync for Wrap<'a, T> {} #[inline(always)] -fn compute_start_time_without_boot_time(parts: &[&str], info: &SystemInfo) -> u64 { +fn compute_start_time_without_boot_time(parts: &Parts<'_>, info: &SystemInfo) -> u64 { // To be noted that the start time is invalid here, it still needs to be converted into // "real" time. - u64::from_str(parts[ProcIndex::StartTime as usize]).unwrap_or(0) / info.clock_cycle + u64::from_str(parts.str_parts[ProcIndex::StartTime as usize]).unwrap_or(0) / info.clock_cycle } -fn _get_stat_data(path: &Path, stat_file: &mut Option) -> Result { +fn _get_stat_data(path: &Path, stat_file: &mut Option) -> Result, ()> { let mut file = File::open(path.join("stat")).map_err(|_| ())?; let data = get_all_data_from_file(&mut file, 1024).map_err(|_| ())?; *stat_file = FileCounter::new(file); @@ -401,11 +401,11 @@ fn update_proc_info( p: &mut ProcessInner, refresh_kind: ProcessRefreshKind, proc_path: &mut PathHandler, - parts: &[&str], + str_parts: &[&str], uptime: u64, info: &SystemInfo, ) { - get_status(p, parts[ProcIndex::State as usize]); + get_status(p, str_parts[ProcIndex::State as usize]); refresh_user_group_ids(p, proc_path, refresh_kind); if refresh_kind.exe().needs_update(|| p.exe.is_none()) { @@ -427,7 +427,7 @@ fn update_proc_info( p.root = realpath(proc_path.join("root")); } - update_time_and_memory(proc_path, p, parts, uptime, info, refresh_kind); + update_time_and_memory(proc_path, p, str_parts, uptime, info, refresh_kind); if refresh_kind.disk_usage() { update_process_disk_activity(p, proc_path); } @@ -436,7 +436,7 @@ fn update_proc_info( fn retrieve_all_new_process_info( pid: Pid, parent_pid: Option, - parts: &[&str], + parts: &Parts<'_>, path: &Path, info: &SystemInfo, refresh_kind: ProcessRefreshKind, @@ -444,11 +444,11 @@ fn retrieve_all_new_process_info( ) -> Process { let mut p = ProcessInner::new(pid, path.to_owned()); let mut proc_path = PathHandler::new(path); - let name = parts[ProcIndex::ShortExe as usize]; + let name = parts.short_exe; p.parent = match parent_pid { Some(parent_pid) if parent_pid.0 != 0 => Some(parent_pid), - _ => match Pid::from_str(parts[ProcIndex::ParentPid as usize]) { + _ => match Pid::from_str(parts.str_parts[ProcIndex::ParentPid as usize]) { Ok(p) if p.0 != 0 => Some(p), _ => None, }, @@ -459,8 +459,8 @@ fn retrieve_all_new_process_info( .start_time_without_boot_time .saturating_add(info.boot_time); - p.name = name.into(); - if c_ulong::from_str(parts[ProcIndex::Flags as usize]) + p.name = OsStr::from_bytes(name).to_os_string(); + if c_ulong::from_str(parts.str_parts[ProcIndex::Flags as usize]) .map(|flags| flags & PF_KTHREAD != 0) .unwrap_or(false) { @@ -469,7 +469,14 @@ fn retrieve_all_new_process_info( p.thread_kind = Some(ThreadKind::Userland); } - update_proc_info(&mut p, refresh_kind, &mut proc_path, parts, uptime, info); + update_proc_info( + &mut p, + refresh_kind, + &mut proc_path, + &parts.str_parts, + uptime, + info, + ); Process { inner: p } } @@ -511,7 +518,14 @@ pub(crate) fn _get_process_data( if start_time_without_boot_time == entry.start_time_without_boot_time { let mut proc_path = PathHandler::new(path); - update_proc_info(entry, refresh_kind, &mut proc_path, &parts, uptime, info); + update_proc_info( + entry, + refresh_kind, + &mut proc_path, + &parts.str_parts, + uptime, + info, + ); refresh_user_group_ids(entry, &mut proc_path, refresh_kind); return Ok((None, pid)); @@ -548,14 +562,14 @@ pub(crate) fn _get_process_data( Ok((None, pid)) } -fn old_get_memory(entry: &mut ProcessInner, parts: &[&str], info: &SystemInfo) { +fn old_get_memory(entry: &mut ProcessInner, str_parts: &[&str], info: &SystemInfo) { // rss - entry.memory = u64::from_str(parts[ProcIndex::ResidentSetSize as usize]) + entry.memory = u64::from_str(str_parts[ProcIndex::ResidentSetSize as usize]) .unwrap_or(0) .saturating_mul(info.page_size_b); // vsz correspond to the Virtual memory size in bytes. // see: https://man7.org/linux/man-pages/man5/proc.5.html - entry.virtual_memory = u64::from_str(parts[ProcIndex::VirtualSize as usize]).unwrap_or(0); + entry.virtual_memory = u64::from_str(str_parts[ProcIndex::VirtualSize as usize]).unwrap_or(0); } fn slice_to_nb(s: &[u8]) -> u64 { @@ -604,7 +618,7 @@ fn get_memory(path: &Path, entry: &mut ProcessInner, info: &SystemInfo) -> bool fn update_time_and_memory( path: &mut PathHandler, entry: &mut ProcessInner, - parts: &[&str], + str_parts: &[&str], uptime: u64, info: &SystemInfo, refresh_kind: ProcessRefreshKind, @@ -614,13 +628,13 @@ fn update_time_and_memory( if refresh_kind.memory() { // Keeping this nested level for readability reasons. if !get_memory(path.join("statm"), entry, info) { - old_get_memory(entry, parts, info); + old_get_memory(entry, str_parts, info); } } set_time( entry, - u64::from_str(parts[ProcIndex::UserTime as usize]).unwrap_or(0), - u64::from_str(parts[ProcIndex::SystemTime as usize]).unwrap_or(0), + u64::from_str(str_parts[ProcIndex::UserTime as usize]).unwrap_or(0), + u64::from_str(str_parts[ProcIndex::SystemTime as usize]).unwrap_or(0), ); entry.run_time = uptime.saturating_sub(entry.start_time_without_boot_time); } @@ -797,7 +811,7 @@ fn copy_from_file(entry: &Path) -> Vec { // Fetch tuples of real and effective UID and GID. fn get_uid_and_gid(file_path: &Path) -> Option<((uid_t, uid_t), (gid_t, gid_t))> { - let status_data = get_all_data(file_path, 16_385).ok()?; + let status_data = get_all_utf8_data(file_path, 16_385).ok()?; // We're only interested in the lines starting with Uid: and Gid: // here. From these lines, we're looking at the first and second entries to get @@ -842,7 +856,12 @@ fn get_uid_and_gid(file_path: &Path) -> Option<((uid_t, uid_t), (gid_t, gid_t))> } } -fn parse_stat_file(data: &str) -> Option> { +struct Parts<'a> { + str_parts: Vec<&'a str>, + short_exe: &'a [u8], +} + +fn parse_stat_file(data: &[u8]) -> Option> { // The stat file is "interesting" to parse, because spaces cannot // be used as delimiters. The second field stores the command name // surrounded by parentheses. Unfortunately, whitespace and @@ -852,16 +871,15 @@ fn parse_stat_file(data: &str) -> Option> { // in the entire string. All other fields are delimited by // whitespace. - let mut parts = Vec::with_capacity(52); - let mut data_it = data.splitn(2, ' '); - parts.push(data_it.next()?); - let mut data_it = data_it.next()?.rsplitn(2, ')'); - let data = data_it.next()?; - parts.push(data_it.next()?); - parts.extend(data.split_whitespace()); - // Remove command name '(' - if let Some(name) = parts[ProcIndex::ShortExe as usize].strip_prefix('(') { - parts[ProcIndex::ShortExe as usize] = name; - } - Some(parts) + let mut str_parts = Vec::with_capacity(51); + let mut data_it = data.splitn(2, |&b| b == b' '); + str_parts.push(str::from_utf8(data_it.next()?).ok()?); + let mut data_it = data_it.next()?.rsplitn(2, |&b| b == b')'); + let data = str::from_utf8(data_it.next()?).ok()?; + let short_exe = data_it.next()?; + str_parts.extend(data.split_whitespace()); + Some(Parts { + str_parts, + short_exe: short_exe.strip_prefix(&[b'(']).unwrap_or(short_exe), + }) } diff --git a/src/unix/linux/system.rs b/src/unix/linux/system.rs index 734e645470..55df6a6d21 100644 --- a/src/unix/linux/system.rs +++ b/src/unix/linux/system.rs @@ -2,7 +2,7 @@ use crate::sys::cpu::{get_physical_core_count, CpusWrapper}; use crate::sys::process::{_get_process_data, compute_cpu_usage, refresh_procs, unset_updated}; -use crate::sys::utils::{get_all_data, to_u64}; +use crate::sys::utils::{get_all_utf8_data, to_u64}; use crate::{Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process, ProcessRefreshKind}; use libc::{self, c_char, sysconf, _SC_CLK_TCK, _SC_HOST_NAME_MAX, _SC_PAGESIZE}; @@ -352,7 +352,7 @@ impl SystemInner { } pub(crate) fn uptime() -> u64 { - let content = get_all_data("/proc/uptime", 50).unwrap_or_default(); + let content = get_all_utf8_data("/proc/uptime", 50).unwrap_or_default(); content .split('.') .next() @@ -508,7 +508,7 @@ impl SystemInner { } fn read_u64(filename: &str) -> Option { - get_all_data(filename, 16_635) + get_all_utf8_data(filename, 16_635) .ok() .and_then(|d| u64::from_str(d.trim()).ok()) } @@ -517,7 +517,7 @@ fn read_table(filename: &str, colsep: char, mut f: F) where F: FnMut(&str, u64), { - if let Ok(content) = get_all_data(filename, 16_635) { + if let Ok(content) = get_all_utf8_data(filename, 16_635) { content .split('\n') .flat_map(|line| { diff --git a/src/unix/linux/utils.rs b/src/unix/linux/utils.rs index 7d4292817d..987f4e18dc 100644 --- a/src/unix/linux/utils.rs +++ b/src/unix/linux/utils.rs @@ -7,16 +7,23 @@ use std::sync::atomic::Ordering; use crate::sys::system::REMAINING_FILES; -pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result { +pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result> { + let mut buf = Vec::with_capacity(size); + file.rewind()?; + file.read_to_end(&mut buf)?; + Ok(buf) +} + +pub(crate) fn get_all_utf8_data_from_file(file: &mut File, size: usize) -> io::Result { let mut buf = String::with_capacity(size); file.rewind()?; file.read_to_string(&mut buf)?; Ok(buf) } -pub(crate) fn get_all_data>(file_path: P, size: usize) -> io::Result { +pub(crate) fn get_all_utf8_data>(file_path: P, size: usize) -> io::Result { let mut file = File::open(file_path.as_ref())?; - get_all_data_from_file(&mut file, size) + get_all_utf8_data_from_file(&mut file, size) } #[allow(clippy::useless_conversion)] diff --git a/src/unknown/process.rs b/src/unknown/process.rs index 0bb48554b7..bca71e07fa 100644 --- a/src/unknown/process.rs +++ b/src/unknown/process.rs @@ -2,6 +2,7 @@ use crate::{DiskUsage, Gid, Pid, ProcessStatus, Signal, Uid}; +use std::ffi::OsStr; use std::fmt; use std::path::Path; @@ -21,8 +22,8 @@ impl ProcessInner { None } - pub(crate) fn name(&self) -> &str { - "" + pub(crate) fn name(&self) -> &OsStr { + OsStr::new("") } pub(crate) fn cmd(&self) -> &[String] { diff --git a/src/windows/process.rs b/src/windows/process.rs index 063189596b..17e00afcdd 100644 --- a/src/windows/process.rs +++ b/src/windows/process.rs @@ -4,7 +4,7 @@ use crate::sys::system::is_proc_running; use crate::windows::Sid; use crate::{DiskUsage, Gid, Pid, ProcessRefreshKind, ProcessStatus, Signal, Uid}; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fmt; #[cfg(feature = "debug")] use std::io; @@ -199,7 +199,7 @@ unsafe impl Send for HandleWrapper {} unsafe impl Sync for HandleWrapper {} pub(crate) struct ProcessInner { - name: String, + name: OsString, cmd: Vec, exe: Option, pid: Pid, @@ -266,7 +266,7 @@ unsafe fn display_ntstatus_error(ntstatus: windows::core::HRESULT) { // Take a look at https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/query.htm // for explanations. -unsafe fn get_process_name(pid: Pid) -> Option { +unsafe fn get_process_name(pid: Pid) -> Option { let mut info = SYSTEM_PROCESS_ID_INFORMATION { ProcessId: pid.0 as _, ImageName: MaybeUninit::zeroed().assume_init(), @@ -333,9 +333,7 @@ unsafe fn get_process_name(pid: Pid) -> Option { info.ImageName.Length as usize / std::mem::size_of::(), ); let os_str = OsString::from_wide(s); - let name = Path::new(&os_str) - .file_name() - .map(|s| s.to_string_lossy().to_string()); + let name = Path::new(&os_str).file_name().map(|s| s.to_os_string()); let _err = LocalFree(HLOCAL(info.ImageName.Buffer.cast())); name } @@ -420,7 +418,7 @@ impl ProcessInner { parent: Option, memory: u64, virtual_memory: u64, - name: String, + name: OsString, now: u64, refresh_kind: ProcessRefreshKind, ) -> Self { @@ -544,7 +542,7 @@ impl ProcessInner { } } - pub(crate) fn name(&self) -> &str { + pub(crate) fn name(&self) -> &OsStr { &self.name } diff --git a/src/windows/sid.rs b/src/windows/sid.rs index 5ed5029124..85c5b4b452 100644 --- a/src/windows/sid.rs +++ b/src/windows/sid.rs @@ -9,7 +9,7 @@ use windows::Win32::Security::{ CopySid, GetLengthSid, IsValidSid, LookupAccountSidW, SidTypeUnknown, }; -use crate::sys::utils::to_str; +use crate::sys::utils::to_utf8_str; #[doc = include_str!("../../md_doc/sid.md")] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -102,7 +102,7 @@ impl Sid { return None; } - Some(to_str(PWSTR::from_raw(name.as_mut_ptr()))) + Some(to_utf8_str(PWSTR::from_raw(name.as_mut_ptr()))) } } } @@ -115,7 +115,7 @@ impl Display for Sid { sysinfo_debug!("ConvertSidToStringSidW failed: {:?}", _err); return None; } - let result = to_str(string_sid); + let result = to_utf8_str(string_sid); let _err = LocalFree(HLOCAL(string_sid.0 as _)); Some(result) } diff --git a/src/windows/system.rs b/src/windows/system.rs index b621e71679..46248368fe 100644 --- a/src/windows/system.rs +++ b/src/windows/system.rs @@ -12,7 +12,9 @@ use crate::utils::into_iter; use std::cell::UnsafeCell; use std::collections::HashMap; +use std::ffi::OsString; use std::mem::{size_of, zeroed}; +use std::os::windows::ffi::OsStringExt; use std::ptr; use std::time::SystemTime; @@ -434,14 +436,14 @@ impl SystemInner { if Self::is_windows_eleven() { return get_reg_string_value( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", ) .map(|product_name| product_name.replace("Windows 10 ", "Windows 11 ")); } get_reg_string_value( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", ) } @@ -453,7 +455,7 @@ impl SystemInner { pub(crate) fn kernel_version() -> Option { get_reg_string_value( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuildNumber", ) } @@ -461,7 +463,7 @@ impl SystemInner { pub(crate) fn os_version() -> Option { let build_number = get_reg_string_value( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentBuildNumber", ) .unwrap_or_default(); @@ -471,7 +473,7 @@ impl SystemInner { u32::from_le_bytes( get_reg_value_u32( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentMajorVersionNumber", ) .unwrap_or_default(), @@ -542,7 +544,7 @@ fn refresh_existing_process( #[allow(clippy::size_of_in_element_count)] //^ needed for "name.Length as usize / std::mem::size_of::()" -pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: Pid) -> String { +pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: Pid) -> OsString { let name = &process.ImageName; if name.Buffer.is_null() { match process_id.0 { @@ -550,6 +552,7 @@ pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: 4 => "System".to_owned(), _ => format!(" Process {process_id}"), } + .into() } else { unsafe { let slice = std::slice::from_raw_parts( @@ -558,7 +561,7 @@ pub(crate) fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: name.Length as usize / std::mem::size_of::(), ); - String::from_utf16_lossy(slice) + OsString::from_wide(slice) } } } diff --git a/src/windows/users.rs b/src/windows/users.rs index 6a3317fa48..f9e694564e 100644 --- a/src/windows/users.rs +++ b/src/windows/users.rs @@ -1,6 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::sys::utils::to_str; +use crate::sys::utils::to_utf8_str; use crate::{ common::{Gid, Uid}, windows::sid::Sid, @@ -139,7 +139,7 @@ unsafe fn get_groups_for_user(username: PCWSTR) -> Vec { if !buf.0.is_null() { let entries = std::slice::from_raw_parts(buf.0, nb_entries as _); groups.extend(entries.iter().map(|entry| Group { - name: to_str(entry.lgrui0_name), + name: to_utf8_str(entry.lgrui0_name), id: Gid(0), })); } @@ -191,7 +191,7 @@ pub(crate) fn get_users(users: &mut Vec) { // if this fails. let name = sid .account_name() - .unwrap_or_else(|| to_str(entry.usri0_name)); + .unwrap_or_else(|| to_utf8_str(entry.usri0_name)); users.push(User { inner: UserInner::new( Uid(sid), diff --git a/src/windows/utils.rs b/src/windows/utils.rs index 56deb796d9..1510f08a10 100644 --- a/src/windows/utils.rs +++ b/src/windows/utils.rs @@ -23,7 +23,7 @@ pub(crate) fn get_now() -> u64 { .unwrap_or(0) } -pub(crate) unsafe fn to_str(p: PWSTR) -> String { +pub(crate) unsafe fn to_utf8_str(p: PWSTR) -> String { if p.is_null() { return String::new(); } diff --git a/tests/process.rs b/tests/process.rs index 02324726f4..8cd1f7aa65 100644 --- a/tests/process.rs +++ b/tests/process.rs @@ -404,7 +404,10 @@ fn test_refresh_tasks() { .map(|task| task.name() == task_name) .unwrap_or(false))) .unwrap_or(false)); - assert!(s.processes_by_exact_name(task_name).next().is_some()); + assert!(s + .processes_by_exact_name(task_name.as_ref()) + .next() + .is_some()); // Let's give some time to the system to clean up... std::thread::sleep(std::time::Duration::from_secs(2)); @@ -420,7 +423,10 @@ fn test_refresh_tasks() { .map(|task| task.name() == task_name) .unwrap_or(false))) .unwrap_or(false)); - assert!(s.processes_by_exact_name(task_name).next().is_none()); + assert!(s + .processes_by_exact_name(task_name.as_ref()) + .next() + .is_none()); } // Checks that `refresh_process` is NOT removing dead processes. @@ -564,14 +570,14 @@ fn test_process_iterator_lifetimes() { { let name = String::from(""); // errors before PR #904: name does not live long enough - process = s.processes_by_name(&name).next(); + process = s.processes_by_name(name.as_ref()).next(); } process.unwrap(); let process: Option<&sysinfo::Process>; { // worked fine before and after: &'static str lives longer than System, error couldn't appear - process = s.processes_by_name("").next(); + process = s.processes_by_name("".as_ref()).next(); } process.unwrap(); }