NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: pkg/57708: rust problem when building firefox
The attached Rust program prints the parameters for both the main
thread and non-main threads. It should be relatively easy to adapt to
the code in Rust std/sys/thread.rs, I expect.
Plop it in src/main.rs next to a Cargo.toml file with the following
content, and run with `cargo run':
[package]
name = "stackguard"
version = "0.1.0"
edition = "2021"
[dependencies]
libc = "^0.2.150"
//
// __MACHINE_STACK_GROWS_UP (hppa):
//
// +---------------+
// | |
// | guard pages | guardsize
// | |
// +---------------+ guardaddr = stackbase + stacksize
// | |
// | stack pages | stacksize
// | |
// +---------------+ stackaddr = stackbase
//
// !__MACHINE_STACK_GROWS_UP (i.e., stack grows down -- most
// architectures):
//
// +---------------+ stackbase
// | |
// | stack pages | stacksize
// | |
// +---------------+ stackaddr = stackbase - stacksize
// | |
// | guard pages | guardsize
// | |
// +---------------+ guardaddr = stackbase - stacksize - guardsize
//
use libc;
use std::io;
use std::mem;
use std::os::raw::c_int;
use std::os::raw::c_uint;
use std::os::raw::c_ulong;
use std::os::raw::c_void;
use std::ptr;
const __MACHINE_STACK_GROWS_UP: bool = false; // XXX
#[repr(C)]
struct AuxInfo {
a_type: u32, // Elf32_Word, Elf64_Word
a_v: c_ulong, // Elf32_Word, Elf64_Xword
}
const AT_NULL: u32 = 0;
const AT_STACKBASE: u32 = 13;
extern { fn _dlauxinfo() -> *const AuxInfo; }
const VM_GUARD_SIZE: c_int = 17;
fn pth(error: c_int) -> io::Result<()> {
if error == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(error))
}
}
fn getmainstack() -> io::Result<(*mut c_void, usize, *mut c_void, usize)> {
// Get the stack guard size by reading the unsigned int
// vm.guard_size sysctl.
//
// XXX In principle, this is racy because there is a window between
// when the kernel reads the sysctl to determine the guard page
// allocation and when we read the sysctl to find what that was,
// during which time a privileged process could change the sysctl
// without affecting the guard page allocation, but
//
// (a) it's unlikely that this will happen, and
//
// (b) NetBSD doesn't currently provide a non-racy way to do this,
// like maybe an AT_NETBSD_GUARDSIZE auxinfo entry.
//
let mut mib = [libc::CTL_VM, VM_GUARD_SIZE];
let mut guardsize: c_uint = 0;
let mut len: usize = mem::size_of::<c_uint>();
if unsafe { libc::sysctl(
mib.as_mut_ptr(), // name
mib.len() as c_uint, // namelen
&mut guardsize as *mut _ as *mut _, // oldp
&mut len, // oldlenp
ptr::null_mut(), // newp
0, // newlenp
) } == -1 {
return Err(io::Error::last_os_error());
}
// Get the stack base by reading the AT_STACKBASE _dlauxinfo item.
// Note: This is the initial stack pointer -- not the numerically
// lowest address; it grows up or down depending on
// __MACHINE_STACK_GROWS_UP.
//
let mut auxinfo = unsafe { _dlauxinfo() };
let mut stackbase: *mut c_void = ptr::null_mut();
while unsafe { (*auxinfo).a_type } != AT_NULL {
let (a_type, a_v) = unsafe { ((*auxinfo).a_type, (*auxinfo).a_v) };
println!("a_type={} a_v=0x{:x}", a_type, a_v);
if a_type == AT_STACKBASE {
stackbase = unsafe { mem::transmute((*auxinfo).a_v) };
break
}
auxinfo = unsafe { auxinfo.offset(1) };
}
// Get the stack size by reading the hard stack rlimit, which the
// kernel used to determine the maximum stack allocation (not
// including the guard pages).
//
// XXX In principle, this is racy because there is a window between
// when the kernel reads the rlimit to determine the maximum stack
// allocation and when we read the rlimit to find what that was,
// during which time a privileged process could change the rlimit
// without affecting the stack allocation, but
//
// (a) it's unlikely that this will happen, and
//
// (b) NetBSD doesn't currently provide a non-racy way to do this,
// like maybe an AT_NETBSD_STACKSIZE auxinfo entry.
//
let mut rlim = unsafe { mem::zeroed() };
if unsafe { libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) } == -1 {
return Err(io::Error::last_os_error());
}
let stacksize = rlim.rlim_max as usize;
let istacksize = stacksize as isize;
let iguardsize = guardsize as isize;
// Determine the numerically least addresses of the stack and
// guard. See diagram at top about stacks that grow up vs stacks
// that grow down.
//
let stackaddr = if __MACHINE_STACK_GROWS_UP {
stackbase
} else {
unsafe { stackbase.offset(-istacksize) }
};
let guardaddr = if __MACHINE_STACK_GROWS_UP {
unsafe { stackbase.offset(istacksize) }
} else {
unsafe { stackbase.offset(-istacksize - iguardsize) }
};
Ok((stackaddr, stacksize, guardaddr, guardsize as usize))
}
fn getthreadattrstack(attr: *mut libc::pthread_attr_t)
-> io::Result<(*mut c_void, usize, *mut c_void, usize)> {
let mut stackaddr = ptr::null_mut();
let mut stacksize: usize = 0;
let mut guardsize: usize = 0;
pth(unsafe {
libc::pthread_attr_getstack(attr, &mut stackaddr, &mut stacksize)
})?;
pth(unsafe { libc::pthread_attr_getguardsize(attr, &mut guardsize) })?;
let guardaddr = if __MACHINE_STACK_GROWS_UP {
unsafe { stackaddr.offset(stacksize as isize) }
} else {
unsafe { stackaddr.offset(-(guardsize as isize)) }
};
Ok((stackaddr, stacksize, guardaddr, guardsize))
}
fn getthreadstack() -> io::Result<(*mut c_void, usize, *mut c_void, usize)> {
let t = unsafe { libc::pthread_self() };
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
pth(unsafe { libc::pthread_getattr_np(t, &mut attr) })?;
let r = getthreadattrstack(&mut attr);
pth(unsafe { libc::pthread_attr_destroy(&mut attr) })
.expect("pthread_attr_destroy should never fail");
r
}
fn showstack(name: &str, stack: (*mut c_void, usize, *mut c_void, usize)) {
let (stackaddr, stacksize, guardaddr, guardsize) = stack;
println!("{} stack @ [{:p}, {:p})",
name,
stackaddr, unsafe { stackaddr.offset(stacksize as isize) });
println!("{} guard @ [{:p}, {:p})",
name,
guardaddr, unsafe { guardaddr.offset(guardsize as isize) });
}
fn main() {
match getmainstack() {
Ok(stack) => showstack("main", stack),
Err(e) => println!("getmainstack: {}", e),
}
match getthreadstack() {
Ok(stack) => showstack("thread", stack),
Err(e) => println!("getthreadstack: {}", e),
}
}
Home |
Main Index |
Thread Index |
Old Index