Closed
Description
Hi.
The CI of rustc_codegen_gcc suddendly started failing.
After investigation, it seems to be caused by recent changes to libc, regarding posix spawn stuff (so possibly related to this change).
My target triple is: x86_64-unknown-linux-gnu
.
Here's the code (inspired by std::process::Command
) that works with libc 0.2.153, but segfaults with 0.2.154 (it doesn't reproduce in the playground since it still uses version 0.2.153):
use std::{ffi::OsStr, io};
use std::ffi::{c_int, c_ulong, c_short};
use libc::{gid_t, pid_t, uid_t};
//use std::os::unix::raw::{uid_t, gid_t, pid_t};
mod imp {
use std::{ffi::{CString, OsStr}, io, os::unix::ffi::OsStrExt, process::Stdio};
use libc::{gid_t, pid_t, uid_t};
//use std::os::unix::raw::{uid_t, gid_t, pid_t};
pub struct Command {
pub program: CString,
args: Vec<CString>,
cwd: Option<CString>,
pub uid: Option<uid_t>,
pub gid: Option<gid_t>,
saw_nul: bool,
pub closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
pub groups: Option<Box<[gid_t]>>,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
#[cfg(target_os = "linux")]
pub create_pidfd: bool,
pub pgroup: Option<pid_t>,
}
fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
CString::new(s.as_bytes()).unwrap_or_else(|_e| {
*saw_nul = true;
CString::new("<string-with-nul>").unwrap()
})
}
impl Command {
pub fn new(program: &OsStr) -> Command {
let mut saw_nul = false;
let program = os2c(program, &mut saw_nul);
Command {
args: vec![program.clone()],
program,
cwd: None,
uid: None,
gid: None,
saw_nul,
closures: Vec::new(),
groups: None,
stdin: None,
stdout: None,
stderr: None,
create_pidfd: false,
pgroup: None,
}
}
}
}
pub fn cvt_nz(error: c_int) -> io::Result<()> {
if error == 0 {
return Ok(())
}
panic!();
}
pub struct Command {
inner: imp::Command,
}
impl Command {
pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
Command { inner: imp::Command::new(program.as_ref()) }
}
pub fn get_pgroup(&self) -> Option<pid_t> {
self.inner.pgroup
}
pub fn get_create_pidfd(&self) -> bool {
self.inner.create_pidfd
}
pub fn get_uid(&self) -> Option<uid_t> {
self.inner.uid
}
pub fn get_gid(&self) -> Option<gid_t> {
self.inner.gid
}
pub fn env_saw_path(&self) -> bool {
false
}
pub fn program_is_path(&self) -> bool {
self.inner.program.to_bytes().contains(&b'/')
}
pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
&mut self.inner.closures
}
pub fn get_groups(&self) -> Option<&[gid_t]> {
self.inner.groups.as_deref()
}
fn posix_spawn(
&mut self,
) -> io::Result<Option<i32>> {
use std::mem::MaybeUninit;
if self.get_gid().is_some()
|| self.get_uid().is_some()
|| (self.env_saw_path() && !self.program_is_path())
|| !self.get_closures().is_empty()
|| self.get_groups().is_some()
|| self.get_create_pidfd()
{
return Ok(None);
}
#[repr(C)]
struct sched_param {
sched_priority: c_int,
}
#[repr(C)]
struct sigset_t {
__val: [c_ulong; 16],
}
#[repr(C)]
pub struct posix_spawnattr_t {
__flags: c_short,
__pgrp: pid_t,
__sd: sigset_t,
__ss: sigset_t,
#[cfg(any(target_env = "musl", target_env = "ohos"))]
__prio: c_int,
#[cfg(not(any(target_env = "musl", target_env = "ohos")))]
__sp: sched_param,
__policy: c_int,
__pad: [c_int; 16],
}
extern "C" {
fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int;
}
unsafe {
let mut attrs = MaybeUninit::uninit();
//cvt_nz(posix_spawnattr_init(attrs.as_mut_ptr()))?; // This works.
cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?; // This segfaults.
Ok(None)
}
}
}
fn main() {
let mut command = Command::new("ls");
command.posix_spawn().unwrap();
}
It seems there's stack corruption.
It could be interesting to run the std tests in the CI to check if changes to libc breaks anything.
Thanks.
Edit: Pinning to the version 0.2.153 fixes the CI in rustc_codegen_gcc: rust-lang/rustc_codegen_gcc#512
Activity