From af633ce157082bf2b0fd0577765e9b49c34c3e90 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Thu, 2 Oct 2014 20:55:26 +0200 Subject: [PATCH] native: fix passing errno to parent after fork The bitshifts were wrong in that they invoked undefined behavior and only passed the lower byte of the presumed-to-be-32bit errno value. Apparently all actually possible values for errno happen to be easily under 256, so this didn't cause any actual problems. This commit fixes the bitshifts, but doesn't generalize to errno types that aren't 32bit. --- src/libnative/io/process.rs | 17 ++-- src/test/run-pass/unix-process-spawn-errno.rs | 94 +++++++++++++++++++ 2 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/unix-process-spawn-errno.rs diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs index 3a6ae42f946..7a0c1c35d65 100644 --- a/src/libnative/io/process.rs +++ b/src/libnative/io/process.rs @@ -583,10 +583,11 @@ fn spawn_process_os(cfg: ProcessConfig, let mut bytes = [0, ..4]; return match input.inner_read(bytes) { Ok(4) => { - let errno = (bytes[0] << 24) as i32 | - (bytes[1] << 16) as i32 | - (bytes[2] << 8) as i32 | - (bytes[3] << 0) as i32; + let errno = (bytes[0] as i32 << 24) | + (bytes[1] as i32 << 16) | + (bytes[2] as i32 << 8) | + (bytes[3] as i32 << 0); + Err(IoError { code: errno as uint, detail: None, @@ -637,10 +638,10 @@ fn spawn_process_os(cfg: ProcessConfig, fn fail(output: &mut file::FileDesc) -> ! { let errno = os::errno(); let bytes = [ - (errno << 24) as u8, - (errno << 16) as u8, - (errno << 8) as u8, - (errno << 0) as u8, + (errno >> 24) as u8, + (errno >> 16) as u8, + (errno >> 8) as u8, + (errno >> 0) as u8, ]; assert!(output.inner_write(bytes).is_ok()); unsafe { libc::_exit(1) } diff --git a/src/test/run-pass/unix-process-spawn-errno.rs b/src/test/run-pass/unix-process-spawn-errno.rs new file mode 100644 index 00000000000..555bf2cd4c0 --- /dev/null +++ b/src/test/run-pass/unix-process-spawn-errno.rs @@ -0,0 +1,94 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-windows + +#![feature(macro_rules)] + +extern crate native; +extern crate rustrt; +extern crate libc; +use libc::{c_char, c_int}; +use native::io::process; +use rustrt::rtio; +use rustrt::c_str; + +macro_rules! c_string { + ($s:expr) => { { + let ptr = concat!($s, "\0").as_ptr() as *const i8; + unsafe { &c_str::CString::new(ptr, false) } + } } +} + +static EXPECTED_ERRNO: c_int = 0x778899aa; + +#[no_mangle] +pub unsafe extern "C" fn chdir(_: *const c_char) -> c_int { + // copied from std::os::errno() + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd"))] + fn errno_location() -> *mut c_int { + extern { + fn __error() -> *mut c_int; + } + unsafe { + __error() + } + } + + #[cfg(target_os = "dragonfly")] + fn errno_location() -> *mut c_int { + extern { + fn __dfly_error() -> *mut c_int; + } + unsafe { + __dfly_error() + } + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + fn errno_location() -> *mut c_int { + extern { + fn __errno_location() -> *mut c_int; + } + unsafe { + __errno_location() + } + } + + *errno_location() = EXPECTED_ERRNO; + return -1; +} + +fn main() { + let program = c_string!("true"); + let cwd = c_string!("whatever"); + let cfg = rtio::ProcessConfig { + program: program, + args: &[], + env: None, + cwd: Some(cwd), + stdin: rtio::Ignored, + stdout: rtio::Ignored, + stderr: rtio::Ignored, + extra_io: &[], + uid: None, + gid: None, + detach: false + }; + + match process::Process::spawn(cfg) { + Ok(_) => { fail!("spawn() should have failled"); } + Err(rtio::IoError { code: err, ..}) => { + assert_eq!(err as c_int, EXPECTED_ERRNO); + } + }; +}