From 1bca13a1e02580ec54bd9a5f381a879824a8acc4 Mon Sep 17 00:00:00 2001 From: Vincent Thiberville Date: Thu, 18 Apr 2024 14:22:27 +0200 Subject: [PATCH] fix: remove use of `from_utf8_unchecked` in macos process handling Those unsafe functions have been observed to not respect their safety constraints, as some values retrieved from the macos API are not guaranteed to be UTF-8. This is fixed by replacing those calls with `from_utf8_lossy`, which will replace those values with a replacement character to ensure the generated String is valid. This solution is not ideal, but the master branch contains the better fix: an OsString is returned to let the caller decide how to handle the value. Changing those calls remove the need of unsafe blocks, so those were removed at the same time. --- src/unix/apple/macos/process.rs | 60 +++++++++++++++------------------ 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs index 3d2580f0f..c01950d69 100644 --- a/src/unix/apple/macos/process.rs +++ b/src/unix/apple/macos/process.rs @@ -2,7 +2,9 @@ #![allow(clippy::assigning_clones)] +use std::ffi::OsStr; use std::mem::{self, MaybeUninit}; +use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; use libc::{c_int, c_void, kill}; @@ -407,7 +409,7 @@ 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 = String::from_utf8_lossy(&buffer).to_string(); let exe = PathBuf::from(tmp); if process.name.is_empty() { process.name = exe @@ -575,12 +577,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>( @@ -600,21 +600,19 @@ fn get_arguments<'a>( data = &data[1..]; } - unsafe { - while n_args > 0 && !data.is_empty() { - let pos = data.iter().position(|c| *c == 0).unwrap_or(data.len()); - let arg = std::str::from_utf8_unchecked(&data[..pos]); - if !arg.is_empty() && refresh_cmd { - cmd.push(arg.to_string()); - } - data = &data[pos..]; - while data.first() == Some(&0) { - data = &data[1..]; - } - n_args -= 1; + while n_args > 0 && !data.is_empty() { + let pos = data.iter().position(|c| *c == 0).unwrap_or(data.len()); + let arg = String::from_utf8_lossy(&data[..pos]); + if !arg.is_empty() && refresh_cmd { + cmd.push(arg.to_string()); } - data + data = &data[pos..]; + while data.first() == Some(&0) { + data = &data[1..]; + } + n_args -= 1; } + data } fn get_environ(environ: &mut Vec, mut data: &[u8]) { @@ -624,18 +622,16 @@ fn get_environ(environ: &mut Vec, mut data: &[u8]) { data = &data[1..]; } - unsafe { - while !data.is_empty() { - let pos = data.iter().position(|c| *c == 0).unwrap_or(data.len()); - let arg = std::str::from_utf8_unchecked(&data[..pos]); - if arg.is_empty() { - return; - } - environ.push(arg.to_string()); - data = &data[pos..]; - while data.first() == Some(&0) { - data = &data[1..]; - } + while !data.is_empty() { + let pos = data.iter().position(|c| *c == 0).unwrap_or(data.len()); + let arg = String::from_utf8_lossy(&data[..pos]); + if arg.is_empty() { + return; + } + environ.push(arg.to_string()); + data = &data[pos..]; + while data.first() == Some(&0) { + data = &data[1..]; } } }