From c7f3af1af8506a736878dab2a8f8d1a1a03c9a48 Mon Sep 17 00:00:00 2001 From: Thomas Hurst Date: Wed, 4 May 2022 23:27:48 +0100 Subject: [PATCH] FreeBSD: Rewrite to remove heap allocation (#8) Instead of using libutil's kinfo_getproc(), call sysctl() ourselves using a stack-allocated buffer. In addition to avoiding a heap allocation, this also avoids a second call to sysctl() - kinfo_getproc() appears to have copied a bit too much from kinfo_getallproc() and uses the dynamic-sized-sysctl pattern with a size it already knows. --- src/freebsd.rs | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/freebsd.rs b/src/freebsd.rs index e86674c..1c3cbc8 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -1,18 +1,36 @@ extern crate libc; use std::num::NonZeroUsize; - -extern "C" { - fn kinfo_getproc(pid: libc::pid_t) -> *mut libc::kinfo_proc; -} +use std::{mem, ptr}; pub(crate) fn num_threads() -> Option { - // Safety: `kinfo_getproc` and `getpid` are both thread-safe. All invariants of `as_ref` are - // upheld. + // Safety: `sysctl` and `getpid` are both thread-safe. + // `kip` is only accessed if sysctl() succeeds and agrees with the expected size, + // and the data only trusted if both its embedded size and pid match expectations unsafe { - let kip = kinfo_getproc(libc::getpid()); - let num_threads = NonZeroUsize::new(kip.as_ref()?.ki_numthreads as usize); - libc::free(kip as *mut libc::c_void); - num_threads + let pid = libc::getpid(); + let mib: [libc::c_int; 4] = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_PID, pid]; + let mut kip: libc::kinfo_proc = mem::zeroed(); + let expected_kip_len = mem::size_of_val(&kip); + let mut kip_len = expected_kip_len; + + let ret = libc::sysctl( + mib.as_ptr(), + mib.len() as u32, + &mut kip as *mut _ as *mut libc::c_void, + &mut kip_len, + ptr::null(), + 0, + ); + + if ret == 0 + && kip_len == expected_kip_len + && kip.ki_structsize == expected_kip_len as i32 + && kip.ki_pid == pid + { + NonZeroUsize::new(kip.ki_numthreads as usize) + } else { + None + } } }