<commit_before>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::mem;
    use crate::ptr;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        use crate::sys_common::util::report_overflow;

        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            report_overflow();
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
    static mut NEED_ALTSTACK: bool = false;

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK = true;
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        let stackp =
            mmap(ptr::null_mut(), SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }
        stackp
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            munmap(handler._data, SIGSTKSZ);
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<commit_msg>Rollup merge of #69969 - iximeow:sigstack-guard-page, r=cuviper<commit_after>#![cfg_attr(test, allow(dead_code))]

use self::imp::{drop_handler, make_handler};

pub use self::imp::cleanup;
pub use self::imp::init;

pub struct Handler {
    _data: *mut libc::c_void,
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }

    fn null() -> Handler {
        Handler { _data: crate::ptr::null_mut() }
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
))]
mod imp {
    use super::Handler;
    use crate::mem;
    use crate::ptr;

    use libc::MAP_FAILED;
    use libc::{mmap, munmap};
    use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
    use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};

    use crate::sys::unix::os::page_size;
    use crate::sys_common::thread_info;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        #[repr(C)]
        struct siginfo_t {
            a: [libc::c_int; 3], // si_signo, si_errno, si_code
            si_addr: *mut libc::c_void,
        }

        (*(info as *const siginfo_t)).si_addr as usize
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
        (*info).si_addr as usize
    }

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. We then abort to exit and
    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
    // users to believe that unsafe code has accessed an invalid pointer; the
    // SIGSEGV encountered when overflowing the stack is expected and
    // well-defined.
    //
    // If this is not a stack overflow, the handler un-registers itself and
    // then returns (to allow the original signal to be delivered again).
    // Returning from this kind of signal handler is technically not defined
    // to work when reading the POSIX spec strictly, but in practice it turns
    // out many large systems and all implementations allow returning from a
    // signal handler to work. For a more detailed explanation see the
    // comments on #26458.
    unsafe extern "C" fn signal_handler(
        signum: libc::c_int,
        info: *mut libc::siginfo_t,
        _data: *mut libc::c_void,
    ) {
        use crate::sys_common::util::report_overflow;

        let guard = thread_info::stack_guard().unwrap_or(0..0);
        let addr = siginfo_si_addr(info);

        // If the faulting address is within the guard page, then we print a
        // message saying so and abort.
        if guard.start <= addr && addr < guard.end {
            report_overflow();
            rtabort!("stack overflow");
        } else {
            // Unregister ourselves by reverting back to the default behavior.
            let mut action: sigaction = mem::zeroed();
            action.sa_sigaction = SIG_DFL;
            sigaction(signum, &action, ptr::null_mut());

            // See comment above for why this function returns.
        }
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
    static mut NEED_ALTSTACK: bool = false;

    pub unsafe fn init() {
        let mut action: sigaction = mem::zeroed();
        for &signal in &[SIGSEGV, SIGBUS] {
            sigaction(signal, ptr::null_mut(), &mut action);
            // Configure our signal handler if one is not already set.
            if action.sa_sigaction == SIG_DFL {
                action.sa_flags = SA_SIGINFO | SA_ONSTACK;
                action.sa_sigaction = signal_handler as sighandler_t;
                sigaction(signal, &action, ptr::null_mut());
                NEED_ALTSTACK = true;
            }
        }

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    unsafe fn get_stackp() -> *mut libc::c_void {
        let stackp = mmap(
            ptr::null_mut(),
            SIGSTKSZ + page_size(),
            PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANON,
            -1,
            0,
        );
        if stackp == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }
        let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE);
        if guard_result != 0 {
            panic!("failed to set up alternative stack guard page");
        }
        stackp.add(page_size())
    }

    #[cfg(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
        target_os = "solaris"
    ))]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
    }

    #[cfg(target_os = "dragonfly")]
    unsafe fn get_stack() -> libc::stack_t {
        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
    }

    pub unsafe fn make_handler() -> Handler {
        if !NEED_ALTSTACK {
            return Handler::null();
        }
        let mut stack = mem::zeroed();
        sigaltstack(ptr::null(), &mut stack);
        // Configure alternate signal stack, if one is not already set.
        if stack.ss_flags & SS_DISABLE != 0 {
            stack = get_stack();
            sigaltstack(&stack, ptr::null_mut());
            Handler { _data: stack.ss_sp as *mut libc::c_void }
        } else {
            Handler::null()
        }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        if !handler._data.is_null() {
            let stack = libc::stack_t {
                ss_sp: ptr::null_mut(),
                ss_flags: SS_DISABLE,
                // Workaround for bug in macOS implementation of sigaltstack
                // UNIX2003 which returns ENOMEM when disabling a stack while
                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
                // both ss_sp and ss_size should be ignored in this case.
                ss_size: SIGSTKSZ,
            };
            sigaltstack(&stack, ptr::null_mut());
            // We know from `get_stackp` that the alternate stack we installed is part of a mapping
            // that started one page earlier, so walk back a page and unmap from there.
            munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
        }
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "solaris",
    all(target_os = "netbsd", not(target_vendor = "rumprun")),
    target_os = "openbsd"
)))]
mod imp {
    pub unsafe fn init() {}

    pub unsafe fn cleanup() {}

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler::null()
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::file_format_common::*;
use byteorder::{LittleEndian, ReadBytesExt};
use proptest::prelude::*;
use std::io::Cursor;

// verify all bytes in the vector have the high bit set except the last one
fn check_vector(buf: &[u8]) {
    let mut last_byte: bool = false;
    for byte in buf {
        assert!(!last_byte);
        if *byte & 0x80 == 0 {
            last_byte = true;
        }
        if !last_byte {
            assert!(*byte & 0x80 > 0, "{} & 0x80", *byte);
        }
    }
    assert!(last_byte);
}

fn test_u16(value: u16, expected_bytes: usize) {
    let mut buf = BinaryData::new();
    write_u16_as_uleb128(&mut buf, value).expect("serialization should work");
    assert_eq!(buf.len(), expected_bytes);
    let buf = buf.into_inner();
    check_vector(&buf);
    let mut cursor = Cursor::new(&buf[..]);
    let val = read_uleb128_as_u16(&mut cursor).expect("deserialization should work");
    assert_eq!(value, val);
}

fn test_u32(value: u32, expected_bytes: usize) {
    let mut buf = BinaryData::new();
    write_u32_as_uleb128(&mut buf, value).expect("serialization should work");
    assert_eq!(buf.len(), expected_bytes);
    let buf = buf.into_inner();
    check_vector(&buf);
    let mut cursor = Cursor::new(&buf[..]);
    let val = read_uleb128_as_u32(&mut cursor).expect("deserialization should work");
    assert_eq!(value, val);
}

#[test]
fn lab128_u16_test() {
    test_u16(0, 1);
    test_u16(16, 1);
    test_u16(2u16.pow(7) - 1, 1);
    test_u16(2u16.pow(7), 2);
    test_u16(2u16.pow(7) + 1, 2);
    test_u16(2u16.pow(14) - 1, 2);
    test_u16(2u16.pow(14), 3);
    test_u16(2u16.pow(14) + 1, 3);
    test_u16(u16::max_value() - 2, 3);
    test_u16(u16::max_value() - 1, 3);
    test_u16(u16::max_value(), 3);
}

#[test]
fn lab128_u32_test() {
    test_u32(0, 1);
    test_u32(16, 1);
    test_u32(2u32.pow(7) - 1, 1);
    test_u32(2u32.pow(7), 2);
    test_u32(2u32.pow(7) + 1, 2);
    test_u32(2u32.pow(14) - 1, 2);
    test_u32(2u32.pow(14), 3);
    test_u32(2u32.pow(14) + 1, 3);
    test_u32(2u32.pow(21) - 1, 3);
    test_u32(2u32.pow(21), 4);
    test_u32(2u32.pow(21) + 1, 4);
    test_u32(2u32.pow(28) - 1, 4);
    test_u32(2u32.pow(28), 5);
    test_u32(2u32.pow(28) + 1, 5);
    test_u32(u32::max_value() - 2, 5);
    test_u32(u32::max_value() - 1, 5);
    test_u32(u32::max_value(), 5);
}

#[test]
fn lab128_malformed_test() {
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x2])).is_err());

    assert!(read_uleb128_as_u32(&mut Cursor::new(&[])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80, 0x80, 0x2])).is_err());
}

proptest! {
    #[test]
    fn u16_uleb128_roundtrip(input in any::<u16>()) {
        let mut serialized = BinaryData::new();
        write_u16_as_uleb128(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = read_uleb128_as_u16(&mut cursor).expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u32_uleb128_roundtrip(input in any::<u32>()) {
        let mut serialized = BinaryData::new();
        write_u32_as_uleb128(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = read_uleb128_as_u32(&mut cursor).expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u16_roundtrip(input in any::<u16>()) {
        let mut serialized = BinaryData::new();
        write_u16(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u16::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u32_roundtrip(input in any::<u32>()) {
        let mut serialized = BinaryData::new();
        write_u32(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u32::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u64_roundtrip(input in any::<u64>()) {
        let mut serialized = BinaryData::new();
        write_u64(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u64::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }
}
<commit_msg>[language] remove duplicated lines in number tests<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::file_format_common::*;
use byteorder::{LittleEndian, ReadBytesExt};
use proptest::prelude::*;
use std::io::Cursor;

// verify all bytes in the vector have the high bit set except the last one
fn check_vector(buf: &[u8]) {
    let mut last_byte: bool = false;
    for byte in buf {
        assert!(!last_byte);
        if *byte & 0x80 == 0 {
            last_byte = true;
        }
        if !last_byte {
            assert!(*byte & 0x80 > 0, "{} & 0x80", *byte);
        }
    }
    assert!(last_byte);
}

fn test_u16(value: u16, expected_bytes: usize) {
    let mut buf = BinaryData::new();
    write_u16_as_uleb128(&mut buf, value).expect("serialization should work");
    assert_eq!(buf.len(), expected_bytes);
    let buf = buf.into_inner();
    check_vector(&buf);
    let mut cursor = Cursor::new(&buf[..]);
    let val = read_uleb128_as_u16(&mut cursor).expect("deserialization should work");
    assert_eq!(value, val);
}

fn test_u32(value: u32, expected_bytes: usize) {
    let mut buf = BinaryData::new();
    write_u32_as_uleb128(&mut buf, value).expect("serialization should work");
    assert_eq!(buf.len(), expected_bytes);
    let buf = buf.into_inner();
    check_vector(&buf);
    let mut cursor = Cursor::new(&buf[..]);
    let val = read_uleb128_as_u32(&mut cursor).expect("deserialization should work");
    assert_eq!(value, val);
}

#[test]
fn lab128_u16_test() {
    test_u16(0, 1);
    test_u16(16, 1);
    test_u16(2u16.pow(7) - 1, 1);
    test_u16(2u16.pow(7), 2);
    test_u16(2u16.pow(7) + 1, 2);
    test_u16(2u16.pow(14) - 1, 2);
    test_u16(2u16.pow(14), 3);
    test_u16(2u16.pow(14) + 1, 3);
    test_u16(u16::max_value() - 2, 3);
    test_u16(u16::max_value() - 1, 3);
    test_u16(u16::max_value(), 3);
}

#[test]
fn lab128_u32_test() {
    test_u32(0, 1);
    test_u32(16, 1);
    test_u32(2u32.pow(7) - 1, 1);
    test_u32(2u32.pow(7), 2);
    test_u32(2u32.pow(7) + 1, 2);
    test_u32(2u32.pow(14) - 1, 2);
    test_u32(2u32.pow(14), 3);
    test_u32(2u32.pow(14) + 1, 3);
    test_u32(2u32.pow(21) - 1, 3);
    test_u32(2u32.pow(21), 4);
    test_u32(2u32.pow(21) + 1, 4);
    test_u32(2u32.pow(28) - 1, 4);
    test_u32(2u32.pow(28), 5);
    test_u32(2u32.pow(28) + 1, 5);
    test_u32(u32::max_value() - 2, 5);
    test_u32(u32::max_value() - 1, 5);
    test_u32(u32::max_value(), 5);
}

#[test]
fn lab128_malformed_test() {
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u16(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x2])).is_err());

    assert!(read_uleb128_as_u32(&mut Cursor::new(&[])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80])).is_err());
    assert!(read_uleb128_as_u32(&mut Cursor::new(&[0x80, 0x80, 0x80, 0x80, 0x80, 0x2])).is_err());
}

proptest! {
    #[test]
    fn u16_uleb128_roundtrip(input in any::<u16>()) {
        let mut serialized = BinaryData::new();
        write_u16_as_uleb128(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = read_uleb128_as_u16(&mut cursor).expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u32_uleb128_roundtrip(input in any::<u32>()) {
        let mut serialized = BinaryData::new();
        write_u32_as_uleb128(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = read_uleb128_as_u32(&mut cursor).expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u16_roundtrip(input in any::<u16>()) {
        let mut serialized = BinaryData::new();
        write_u16(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u16::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u32_roundtrip(input in any::<u32>()) {
        let mut serialized = BinaryData::new();
        write_u32(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u32::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }

    #[test]
    fn u64_roundtrip(input in any::<u64>()) {
        let mut serialized = BinaryData::new();
        write_u64(&mut serialized, input).expect("serialization should work");
        let serialized = serialized.into_inner();
        let mut cursor = Cursor::new(&serialized[..]);
        let output = cursor.read_u64::<LittleEndian>().expect("deserialization should work");
        prop_assert_eq!(input, output);
    }
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for a read and a write to the same variable where
    /// whether the read occurs before or after the write depends on the evaluation
    /// order of sub-expressions.
    ///
    /// ### Why is this bad?
    /// It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// ### Known problems
    /// Code which intentionally depends on the evaluation
    /// order, or which is correct for any evaluation order.
    ///
    /// ### Example
    /// ```rust
    /// let mut x = 0;
    ///
    /// // Bad
    /// let a = {
    ///     x = 1;
    ///     1
    /// } + x;
    /// // Unclear whether a is 1 or 2.
    ///
    /// // Good
    /// let tmp = {
    ///     x = 1;
    ///     1
    /// };
    /// let a = tmp + x;
    /// ```
    pub EVAL_ORDER_DEPENDENCE,
    suspicious,
    "whether a variable read occurs before a write depends on sub-expression evaluation order"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for diverging calls that are not match arms or
    /// statements.
    ///
    /// ### Why is this bad?
    /// It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// ### Known problems
    /// Someone might want to use `some_bool || panic!()` as a
    /// shorthand.
    ///
    /// ### Example
    /// ```rust,no_run
    /// # fn b() -> bool { true }
    /// # fn c() -> bool { true }
    /// let a = b() || panic!() || c();
    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
    /// let x = (a, b, c, panic!());
    /// // can simply be replaced by `panic!()`
    /// ```
    pub DIVERGING_SUB_EXPRESSION,
    complexity,
    "whether an expression contains a diverging sub expression"
}

declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]);

impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // Find a write to a local variable.
        let var = if_chain! {
            if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind;
            if let Some(var) = path_to_local(lhs);
            if expr.span.desugaring_kind().is_none();
            then { var } else { return; }
        };
        let mut visitor = ReadVisitor {
            cx,
            var,
            write_expr: expr,
            last_expr: expr,
        };
        check_for_unsequenced_reads(&mut visitor);
    }
    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
        match stmt.kind {
            StmtKind::Local(local) => {
                if let Local { init: Some(e), .. } = local {
                    DivergenceVisitor { cx }.visit_expr(e);
                }
            },
            StmtKind::Expr(e) | StmtKind::Semi(e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
            StmtKind::Item(..) => {},
        }
    }
}

struct DivergenceVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
}

impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
    fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Closure(..) => {},
            ExprKind::Match(e, arms, _) => {
                self.visit_expr(e);
                for arm in arms {
                    if let Some(Guard::If(if_expr)) = arm.guard {
                        self.visit_expr(if_expr);
                    }
                    // make sure top level arm expressions aren't linted
                    self.maybe_walk_expr(&*arm.body);
                }
            },
            _ => walk_expr(self, e),
        }
    }
    fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
        span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
    }
}

impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
            ExprKind::Call(func, _) => {
                let typ = self.cx.typeck_results().expr_ty(func);
                match typ.kind() {
                    ty::FnDef(..) | ty::FnPtr(_) => {
                        let sig = typ.fn_sig(self.cx.tcx);
                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() {
                            self.report_diverging_sub_expr(e);
                        }
                    },
                    _ => {},
                }
            },
            ExprKind::MethodCall(..) => {
                let borrowed_table = self.cx.typeck_results();
                if borrowed_table.expr_ty(e).is_never() {
                    self.report_diverging_sub_expr(e);
                }
            },
            _ => {
                // do not lint expressions referencing objects of type `!`, as that required a
                // diverging expression
                // to begin with
            },
        }
        self.maybe_walk_expr(e);
    }
    fn visit_block(&mut self, _: &'tcx Block<'_>) {
        // don't continue over blocks, LateLintPass already does that
    }
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

/// Walks up the AST from the given write expression (`vis.write_expr`) looking
/// for reads to the same variable that are unsequenced relative to the write.
///
/// This means reads for which there is a common ancestor between the read and
/// the write such that
///
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
///   and `|| x = 1` don't necessarily evaluate `x`), and
///
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
///   evaluation order.
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
    let map = &vis.cx.tcx.hir();
    let mut cur_id = vis.write_expr.hir_id;
    loop {
        let parent_id = map.get_parent_node(cur_id);
        if parent_id == cur_id {
            break;
        }
        let parent_node = match map.find(parent_id) {
            Some(parent) => parent,
            None => break,
        };

        let stop_early = match parent_node {
            Node::Expr(expr) => check_expr(vis, expr),
            Node::Stmt(stmt) => check_stmt(vis, stmt),
            Node::Item(_) => {
                // We reached the top of the function, stop.
                break;
            },
            _ => StopEarly::KeepGoing,
        };
        match stop_early {
            StopEarly::Stop => break,
            StopEarly::KeepGoing => {},
        }

        cur_id = parent_id;
    }
}

/// Whether to stop early for the loop in `check_for_unsequenced_reads`. (If
/// `check_expr` weren't an independent function, this would be unnecessary and
/// we could just use `break`).
enum StopEarly {
    KeepGoing,
    Stop,
}

fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
    if expr.hir_id == vis.last_expr.hir_id {
        return StopEarly::KeepGoing;
    }

    match expr.kind {
        ExprKind::Array(_)
        | ExprKind::Tup(_)
        | ExprKind::MethodCall(..)
        | ExprKind::Call(_, _)
        | ExprKind::Assign(..)
        | ExprKind::Index(_, _)
        | ExprKind::Repeat(_, _)
        | ExprKind::Struct(_, _, _) => {
            walk_expr(vis, expr);
        },
        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
            if op.node == BinOpKind::And || op.node == BinOpKind::Or {
                // x && y and x || y always evaluate x first, so these are
                // strictly sequenced.
            } else {
                walk_expr(vis, expr);
            }
        },
        ExprKind::Closure(_, _, _, _, _) => {
            // Either
            //
            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
            //   function and can stop, or
            //
            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
            //   positives.
            //
            // This is also the only place we need to stop early (grrr).
            return StopEarly::Stop;
        },
        // All other expressions either have only one child or strictly
        // sequence the evaluation order of their sub-expressions.
        _ => {},
    }

    vis.last_expr = expr;

    StopEarly::KeepGoing
}

fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
    match stmt.kind {
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
        // If the declaration is of a local variable, check its initializer
        // expression if it has one. Otherwise, keep going.
        StmtKind::Local(local) => local
            .init
            .as_ref()
            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
        StmtKind::Item(..) => StopEarly::KeepGoing,
    }
}

/// A visitor that looks for reads from a variable.
struct ReadVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    /// The ID of the variable we're looking for.
    var: HirId,
    /// The expressions where the write to the variable occurred (for reporting
    /// in the lint).
    write_expr: &'tcx Expr<'tcx>,
    /// The last (highest in the AST) expression we've checked, so we know not
    /// to recheck it.
    last_expr: &'tcx Expr<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if expr.hir_id == self.last_expr.hir_id {
            return;
        }

        if path_to_local_id(expr, self.var) {
            // Check that this is a read, not a write.
            if !is_in_assignment_position(self.cx, expr) {
                span_lint_and_note(
                    self.cx,
                    EVAL_ORDER_DEPENDENCE,
                    expr.span,
                    &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
                    Some(self.write_expr.span),
                    "whether read occurs before this write depends on evaluation order",
                );
            }
        }
        match expr.kind {
            // We're about to descend a closure. Since we don't know when (or
            // if) the closure will be evaluated, any reads in it might not
            // occur here (or ever). Like above, bail to avoid false positives.
            ExprKind::Closure(_, _, _, _, _) |

            // We want to avoid a false positive when a variable name occurs
            // only to have its address taken, so we stop here. Technically,
            // this misses some weird cases, eg.
            //
            // ```rust
            // let mut x = 0;
            // let a = foo(&{x = 1; x}, x);
            // ```
            //
            // TODO: fix this
            ExprKind::AddrOf(_, _, _) => {
                return;
            }
            _ => {}
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    if let Some(parent) = get_parent_expr(cx, expr) {
        if let ExprKind::Assign(lhs, ..) = parent.kind {
            return lhs.hir_id == expr.hir_id;
        }
    }
    false
}
<commit_msg>Fix documentation of eval_order_dependence<commit_after>use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for a read and a write to the same variable where
    /// whether the read occurs before or after the write depends on the evaluation
    /// order of sub-expressions.
    ///
    /// ### Why is this bad?
    /// It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
    /// the operands of these expressions are evaluated before applying the effects of the expression.
    ///
    /// ### Known problems
    /// Code which intentionally depends on the evaluation
    /// order, or which is correct for any evaluation order.
    ///
    /// ### Example
    /// ```rust
    /// let mut x = 0;
    ///
    /// // Bad
    /// let a = {
    ///     x = 1;
    ///     1
    /// } + x;
    /// // Unclear whether a is 1 or 2.
    ///
    /// // Good
    /// let tmp = {
    ///     x = 1;
    ///     1
    /// };
    /// let a = tmp + x;
    /// ```
    pub EVAL_ORDER_DEPENDENCE,
    suspicious,
    "whether a variable read occurs before a write depends on sub-expression evaluation order"
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for diverging calls that are not match arms or
    /// statements.
    ///
    /// ### Why is this bad?
    /// It is often confusing to read. In addition, the
    /// sub-expression evaluation order for Rust is not well documented.
    ///
    /// ### Known problems
    /// Someone might want to use `some_bool || panic!()` as a
    /// shorthand.
    ///
    /// ### Example
    /// ```rust,no_run
    /// # fn b() -> bool { true }
    /// # fn c() -> bool { true }
    /// let a = b() || panic!() || c();
    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
    /// let x = (a, b, c, panic!());
    /// // can simply be replaced by `panic!()`
    /// ```
    pub DIVERGING_SUB_EXPRESSION,
    complexity,
    "whether an expression contains a diverging sub expression"
}

declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]);

impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // Find a write to a local variable.
        let var = if_chain! {
            if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind;
            if let Some(var) = path_to_local(lhs);
            if expr.span.desugaring_kind().is_none();
            then { var } else { return; }
        };
        let mut visitor = ReadVisitor {
            cx,
            var,
            write_expr: expr,
            last_expr: expr,
        };
        check_for_unsequenced_reads(&mut visitor);
    }
    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
        match stmt.kind {
            StmtKind::Local(local) => {
                if let Local { init: Some(e), .. } = local {
                    DivergenceVisitor { cx }.visit_expr(e);
                }
            },
            StmtKind::Expr(e) | StmtKind::Semi(e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
            StmtKind::Item(..) => {},
        }
    }
}

struct DivergenceVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
}

impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
    fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Closure(..) => {},
            ExprKind::Match(e, arms, _) => {
                self.visit_expr(e);
                for arm in arms {
                    if let Some(Guard::If(if_expr)) = arm.guard {
                        self.visit_expr(if_expr);
                    }
                    // make sure top level arm expressions aren't linted
                    self.maybe_walk_expr(&*arm.body);
                }
            },
            _ => walk_expr(self, e),
        }
    }
    fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
        span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
    }
}

impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
            ExprKind::Call(func, _) => {
                let typ = self.cx.typeck_results().expr_ty(func);
                match typ.kind() {
                    ty::FnDef(..) | ty::FnPtr(_) => {
                        let sig = typ.fn_sig(self.cx.tcx);
                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() {
                            self.report_diverging_sub_expr(e);
                        }
                    },
                    _ => {},
                }
            },
            ExprKind::MethodCall(..) => {
                let borrowed_table = self.cx.typeck_results();
                if borrowed_table.expr_ty(e).is_never() {
                    self.report_diverging_sub_expr(e);
                }
            },
            _ => {
                // do not lint expressions referencing objects of type `!`, as that required a
                // diverging expression
                // to begin with
            },
        }
        self.maybe_walk_expr(e);
    }
    fn visit_block(&mut self, _: &'tcx Block<'_>) {
        // don't continue over blocks, LateLintPass already does that
    }
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

/// Walks up the AST from the given write expression (`vis.write_expr`) looking
/// for reads to the same variable that are unsequenced relative to the write.
///
/// This means reads for which there is a common ancestor between the read and
/// the write such that
///
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
///   and `|| x = 1` don't necessarily evaluate `x`), and
///
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
///   evaluation order.
///
/// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
    let map = &vis.cx.tcx.hir();
    let mut cur_id = vis.write_expr.hir_id;
    loop {
        let parent_id = map.get_parent_node(cur_id);
        if parent_id == cur_id {
            break;
        }
        let parent_node = match map.find(parent_id) {
            Some(parent) => parent,
            None => break,
        };

        let stop_early = match parent_node {
            Node::Expr(expr) => check_expr(vis, expr),
            Node::Stmt(stmt) => check_stmt(vis, stmt),
            Node::Item(_) => {
                // We reached the top of the function, stop.
                break;
            },
            _ => StopEarly::KeepGoing,
        };
        match stop_early {
            StopEarly::Stop => break,
            StopEarly::KeepGoing => {},
        }

        cur_id = parent_id;
    }
}

/// Whether to stop early for the loop in `check_for_unsequenced_reads`. (If
/// `check_expr` weren't an independent function, this would be unnecessary and
/// we could just use `break`).
enum StopEarly {
    KeepGoing,
    Stop,
}

fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr<'_>) -> StopEarly {
    if expr.hir_id == vis.last_expr.hir_id {
        return StopEarly::KeepGoing;
    }

    match expr.kind {
        ExprKind::Array(_)
        | ExprKind::Tup(_)
        | ExprKind::MethodCall(..)
        | ExprKind::Call(_, _)
        | ExprKind::Assign(..)
        | ExprKind::Index(_, _)
        | ExprKind::Repeat(_, _)
        | ExprKind::Struct(_, _, _) => {
            walk_expr(vis, expr);
        },
        ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
            if op.node == BinOpKind::And || op.node == BinOpKind::Or {
                // x && y and x || y always evaluate x first, so these are
                // strictly sequenced.
            } else {
                walk_expr(vis, expr);
            }
        },
        ExprKind::Closure(_, _, _, _, _) => {
            // Either
            //
            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
            //   function and can stop, or
            //
            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
            //   positives.
            //
            // This is also the only place we need to stop early (grrr).
            return StopEarly::Stop;
        },
        // All other expressions either have only one child or strictly
        // sequence the evaluation order of their sub-expressions.
        _ => {},
    }

    vis.last_expr = expr;

    StopEarly::KeepGoing
}

fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt<'_>) -> StopEarly {
    match stmt.kind {
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => check_expr(vis, expr),
        // If the declaration is of a local variable, check its initializer
        // expression if it has one. Otherwise, keep going.
        StmtKind::Local(local) => local
            .init
            .as_ref()
            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
        StmtKind::Item(..) => StopEarly::KeepGoing,
    }
}

/// A visitor that looks for reads from a variable.
struct ReadVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    /// The ID of the variable we're looking for.
    var: HirId,
    /// The expressions where the write to the variable occurred (for reporting
    /// in the lint).
    write_expr: &'tcx Expr<'tcx>,
    /// The last (highest in the AST) expression we've checked, so we know not
    /// to recheck it.
    last_expr: &'tcx Expr<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if expr.hir_id == self.last_expr.hir_id {
            return;
        }

        if path_to_local_id(expr, self.var) {
            // Check that this is a read, not a write.
            if !is_in_assignment_position(self.cx, expr) {
                span_lint_and_note(
                    self.cx,
                    EVAL_ORDER_DEPENDENCE,
                    expr.span,
                    &format!("unsequenced read of `{}`", self.cx.tcx.hir().name(self.var)),
                    Some(self.write_expr.span),
                    "whether read occurs before this write depends on evaluation order",
                );
            }
        }
        match expr.kind {
            // We're about to descend a closure. Since we don't know when (or
            // if) the closure will be evaluated, any reads in it might not
            // occur here (or ever). Like above, bail to avoid false positives.
            ExprKind::Closure(_, _, _, _, _) |

            // We want to avoid a false positive when a variable name occurs
            // only to have its address taken, so we stop here. Technically,
            // this misses some weird cases, eg.
            //
            // ```rust
            // let mut x = 0;
            // let a = foo(&{x = 1; x}, x);
            // ```
            //
            // TODO: fix this
            ExprKind::AddrOf(_, _, _) => {
                return;
            }
            _ => {}
        }

        walk_expr(self, expr);
    }
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    if let Some(parent) = get_parent_expr(cx, expr) {
        if let ExprKind::Assign(lhs, ..) = parent.kind {
            return lhs.hir_id == expr.hir_id;
        }
    }
    false
}
<|endoftext|>


<commit_before>/* Single-character XOR cipher decryption library
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

#![crate_name="single_char_xor_lib"]
#![crate_type="lib"]

extern crate serialize;

// English characters sorted by frequency
static ENGLISH_CHARS_BY_FREQ: &'static[u8] =
    b" eEtTaAiInNoOsSrRlLdDhHcCuUmMfFpPyYgGwWvVbBkKxXjJqQzZ";

// Result of the decryption
pub enum SingleCharKey {
    Found(u8, Vec<u8>),
    NotFound
}

// Bytes statistics
struct ByteStat {
    byte: u8,
    num: u64,
}

/*
 * Try to decrypt XOR encrypted text in the buffer
 */
pub fn decrypt(buffer: &[u8]) -> SingleCharKey {
    if buffer.is_empty() {
        return SingleCharKey::NotFound;
    }
    let first = get_most_freq_char(buffer);
    for &c in ENGLISH_CHARS_BY_FREQ.iter() {
        // Most frequent characters in the encrypted text probably should
        // correspond to the most frequent characters in English
        let key = first ^ c;
        let decrypted = xor_by_key(buffer, key);
        if is_english(decrypted.as_slice()) {
            return SingleCharKey::Found(key, decrypted);
        }
    }
    SingleCharKey::NotFound
}

/*
 * XOR buffer by the key and return the result
 */
#[inline]
fn xor_by_key(buffer: &[u8], key: u8) -> Vec<u8> {
    buffer.iter().map(|&c| c ^ key).collect()
}

/*
 * Return most frequent character from the buffer
 */
fn get_most_freq_char(buffer: &[u8]) -> u8 {
    if buffer.is_empty() {
        panic!("Buffer is empty");
    }
    // Statistics map for every possible byte value
    let mut chars = Vec::from_fn(256, |i| ByteStat{byte: i as u8, num: 0});
    for &c in buffer.iter() {
        chars[c as uint].num += 1;
    }
    // Sort in reverse order so most frequent character will be the first one
    chars.sort_by(|first, second| second.num.cmp(&first.num));
    chars[0].byte
}

/*
 * Is text in the buffer looks like an English text?
 */
#[inline]
fn is_english(buffer: &[u8]) -> bool {
    /* The check is very simple here, we basically expect only printable
     * characters. But it should work in most of the cases.
     *
     * And we can't use for example n-grams because this library also used for
     * slices of text.
     */
    buffer.iter().all(|&c| is_english_char(c as char))
}

#[inline]
fn is_english_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9'
        | ' ' | '.' | ',' | '!' | '?' | '\'' | '-' | '"' | '&' | '%'
        | '#' | '(' | ')' | '\n' | '\r' | '\t' => true,
        _ => false
    }
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use std::str;
    use serialize::hex::FromHex;
    use super::{xor_by_key, get_most_freq_char, is_english};
    use super::{decrypt, SingleCharKey};

    #[test]
    fn test_xor_by_key() {
        let buffer = [0xafu8, 0xafu8, 0xafu8, 0xafu8];
        let key = 0xfau8;
        assert_eq!(xor_by_key(buffer.as_slice(), key),
                   vec![0x55u8, 0x55u8, 0x55u8, 0x55u8]);
    }

    #[test]
    fn test_get_most_freq_char() {
        let buffer = [1u8, 1u8, 2u8, 2u8, 2u8, 3u8, 3u8, 3u8, 3u8];
        assert_eq!(get_most_freq_char(buffer.as_slice()), 3u8);
    }

    #[test]
    fn test_is_english() {
        let buffer = ['t' as u8, 'e' as u8, 's' as u8, 't' as u8];
        assert_eq!(is_english(buffer.as_slice()), true);
        assert_eq!(is_english([1u8, 2u8, 3u8].as_slice()), false);
    }

    #[test]
    fn test_decrypt() {
        let buffer = "1b37373331363f78151b7f2b783431333d78397828372d363c78\
                      373e783a393b3736";
        let buf = buffer.from_hex().unwrap();
        let (key, decrypted) = match decrypt(buf.as_slice()) {
            SingleCharKey::Found(key, decrypted) => (key, decrypted),
            SingleCharKey::NotFound => panic!("Key not found")
        };
        assert_eq!('X', key as char);
        assert_eq!("Cooking MC's like a pound of bacon".as_slice(),
                   str::from_utf8(decrypted.as_slice()).unwrap());
    }
}
<commit_msg>Remove unneeded check<commit_after>/* Single-character XOR cipher decryption library
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

#![crate_name="single_char_xor_lib"]
#![crate_type="lib"]

extern crate serialize;

// English characters sorted by frequency
static ENGLISH_CHARS_BY_FREQ: &'static[u8] =
    b" eEtTaAiInNoOsSrRlLdDhHcCuUmMfFpPyYgGwWvVbBkKxXjJqQzZ";

// Result of the decryption
pub enum SingleCharKey {
    Found(u8, Vec<u8>),
    NotFound
}

// Bytes statistics
struct ByteStat {
    byte: u8,
    num: u64,
}

/*
 * Try to decrypt XOR encrypted text in the buffer
 */
pub fn decrypt(buffer: &[u8]) -> SingleCharKey {
    if buffer.is_empty() {
        return SingleCharKey::NotFound;
    }
    let first = get_most_freq_char(buffer);
    for &c in ENGLISH_CHARS_BY_FREQ.iter() {
        // Most frequent characters in the encrypted text probably should
        // correspond to the most frequent characters in English
        let key = first ^ c;
        let decrypted = xor_by_key(buffer, key);
        if is_english(decrypted.as_slice()) {
            return SingleCharKey::Found(key, decrypted);
        }
    }
    SingleCharKey::NotFound
}

/*
 * XOR buffer by the key and return the result
 */
#[inline]
fn xor_by_key(buffer: &[u8], key: u8) -> Vec<u8> {
    buffer.iter().map(|&c| c ^ key).collect()
}

/*
 * Return most frequent character from the buffer
 */
fn get_most_freq_char(buffer: &[u8]) -> u8 {
    // Statistics map for every possible byte value
    let mut chars = Vec::from_fn(256, |i| ByteStat{byte: i as u8, num: 0});
    for &c in buffer.iter() {
        chars[c as uint].num += 1;
    }
    // Sort in reverse order so most frequent character will be the first one
    chars.sort_by(|first, second| second.num.cmp(&first.num));
    chars[0].byte
}

/*
 * Is text in the buffer looks like an English text?
 */
#[inline]
fn is_english(buffer: &[u8]) -> bool {
    /* The check is very simple here, we basically expect only printable
     * characters. But it should work in most of the cases.
     *
     * And we can't use for example n-grams because this library also used for
     * slices of text.
     */
    buffer.iter().all(|&c| is_english_char(c as char))
}

#[inline]
fn is_english_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9'
        | ' ' | '.' | ',' | '!' | '?' | '\'' | '-' | '"' | '&' | '%'
        | '#' | '(' | ')' | '\n' | '\r' | '\t' => true,
        _ => false
    }
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use std::str;
    use serialize::hex::FromHex;
    use super::{xor_by_key, get_most_freq_char, is_english};
    use super::{decrypt, SingleCharKey};

    #[test]
    fn test_xor_by_key() {
        let buffer = [0xafu8, 0xafu8, 0xafu8, 0xafu8];
        let key = 0xfau8;
        assert_eq!(xor_by_key(buffer.as_slice(), key),
                   vec![0x55u8, 0x55u8, 0x55u8, 0x55u8]);
    }

    #[test]
    fn test_get_most_freq_char() {
        let buffer = [1u8, 1u8, 2u8, 2u8, 2u8, 3u8, 3u8, 3u8, 3u8];
        assert_eq!(get_most_freq_char(buffer.as_slice()), 3u8);
    }

    #[test]
    fn test_is_english() {
        let buffer = ['t' as u8, 'e' as u8, 's' as u8, 't' as u8];
        assert_eq!(is_english(buffer.as_slice()), true);
        assert_eq!(is_english([1u8, 2u8, 3u8].as_slice()), false);
    }

    #[test]
    fn test_decrypt() {
        let buffer = "1b37373331363f78151b7f2b783431333d78397828372d363c78\
                      373e783a393b3736";
        let buf = buffer.from_hex().unwrap();
        let (key, decrypted) = match decrypt(buf.as_slice()) {
            SingleCharKey::Found(key, decrypted) => (key, decrypted),
            SingleCharKey::NotFound => panic!("Key not found")
        };
        assert_eq!('X', key as char);
        assert_eq!("Cooking MC's like a pound of bacon".as_slice(),
                   str::from_utf8(decrypted.as_slice()).unwrap());
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate ctest;

use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    let windows = target.contains("windows");
    let mingw = target.contains("windows-gnu");
    let linux = target.contains("unknown-linux");
    let android = target.contains("android");
    let apple = target.contains("apple");
    let musl = target.contains("musl");
    let freebsd = target.contains("freebsd");
    let bsdlike = freebsd || apple;
    let mut cfg = ctest::TestGenerator::new();

    // Pull in extra goodies on linux/mingw
    if target.contains("unknown-linux") {
        cfg.define("_GNU_SOURCE", None);
    } else if windows {
        cfg.define("_WIN32_WINNT", Some("0x8000"));
    }

    // Android doesn't actually have in_port_t but it's much easier if we
    // provide one for us to test against
    if android {
        cfg.define("in_port_t", Some("uint16_t"));
    }

    cfg.header("errno.h")
       .header("fcntl.h")
       .header("limits.h")
       .header("stddef.h")
       .header("stdint.h")
       .header("stdio.h")
       .header("stdlib.h")
       .header("sys/stat.h")
       .header("sys/types.h")
       .header("time.h")
       .header("wchar.h");

    if windows {
        cfg.header("winsock2.h"); // must be before windows.h

        cfg.header("direct.h");
        cfg.header("io.h");
        cfg.header("sys/utime.h");
        cfg.header("windows.h");
        cfg.header("process.h");
        cfg.header("ws2ipdef.h");

        if target.contains("gnu") {
            cfg.header("ws2tcpip.h");
        }
    } else {
        cfg.header("ctype.h");
        cfg.header("dirent.h");
        cfg.header("net/if.h");
        cfg.header("netdb.h");
        cfg.header("netinet/in.h");
        cfg.header("netinet/ip.h");
        cfg.header("netinet/tcp.h");
        cfg.header("pthread.h");
        cfg.header("dlfcn.h");
        cfg.header("signal.h");
        cfg.header("string.h");
        cfg.header("sys/file.h");
        cfg.header("sys/ioctl.h");
        cfg.header("sys/mman.h");
        cfg.header("sys/resource.h");
        cfg.header("sys/socket.h");
        cfg.header("sys/time.h");
        cfg.header("sys/un.h");
        cfg.header("sys/wait.h");
        cfg.header("unistd.h");
        cfg.header("utime.h");
        cfg.header("pwd.h");
        cfg.header("grp.h");
    }

    if android {
        cfg.header("arpa/inet.h");
        cfg.header("time64.h");
    } else if !windows {
        cfg.header("glob.h");
        cfg.header("ifaddrs.h");
        cfg.header("sys/statvfs.h");

        if !musl {
            cfg.header("execinfo.h");
            cfg.header("sys/sysctl.h");
        }
    }

    if apple {
        cfg.header("mach-o/dyld.h");
        cfg.header("mach/mach_time.h");
        cfg.header("malloc/malloc.h");
        if target.starts_with("x86") {
            cfg.header("crt_externs.h");
        }
    }

    if linux || android {
        cfg.header("netpacket/packet.h");
        cfg.header("net/ethernet.h");
        cfg.header("malloc.h");
        cfg.header("sys/prctl.h");
        cfg.header("linux/netlink.h");
    }

    if freebsd {
        cfg.header("pthread_np.h");
    }

    cfg.type_name(move |ty, is_struct| {
        match ty {
            // Just pass all these through, no need for a "struct" prefix
            "FILE" |
            "fd_set" |
            "Dl_info" |
            "DIR" => ty.to_string(),

            // Fixup a few types on windows that don't actually exist.
            "time64_t" if windows => "__time64_t".to_string(),
            "ssize_t" if windows => "SSIZE_T".to_string(),

            // OSX calls this something else
            "sighandler_t" if bsdlike => "sig_t".to_string(),

            t if t.ends_with("_t") => t.to_string(),

            // Windows uppercase structs don't have `struct` in front, there's a
            // few special cases for windows, and then otherwise put `struct` in
            // front of everything.
            t if is_struct => {
                if windows && ty.chars().next().unwrap().is_uppercase() {
                    t.to_string()
                } else if windows && t == "stat" {
                    "struct __stat64".to_string()
                } else if windows && t == "utimbuf" {
                    "struct __utimbuf64".to_string()
                } else {
                    format!("struct {}", t)
                }
            }

            t => t.to_string(),
        }
    });

    let target2 = target.clone();
    cfg.field_name(move |struct_, field| {
        match field {
            // Our stat *_nsec fields normally don't actually exist but are part
            // of a timeval struct
            s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
                if target2.contains("apple") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else if target2.contains("android") {
                    s.to_string()
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    });

    cfg.skip_type(move |ty| {
        match ty {
            // sighandler_t is crazy across platforms
            "sighandler_t" => true,

            _ => false
        }
    });

    cfg.skip_signededness(|c| {
        match c {
            "LARGE_INTEGER" |
            "mach_timebase_info_data_t" |
            "float" |
            "double" => true,
            n if n.starts_with("pthread") => true,

            // windows-isms
            n if n.starts_with("P") => true,
            n if n.starts_with("H") => true,
            n if n.starts_with("LP") => true,
            _ => false,
        }
    });

    cfg.skip_const(move |name| {
        match name {
            // Apparently these don't exist in mingw headers?
            "MEM_RESET_UNDO" |
            "FILE_ATTRIBUTE_NO_SCRUB_DATA" |
            "FILE_ATTRIBUTE_INTEGRITY_STREAM" |
            "ERROR_NOTHING_TO_TERMINATE" if mingw => true,

            "SIG_IGN" => true, // sighandler_t weirdness

            // types on musl are defined a little differently
            n if musl && n.contains("__SIZEOF_PTHREAD") => true,

            // Skip constants not defined in MUSL but just passed down to the
            // kernel regardless
            "RLIMIT_NLIMITS" |
            "TCP_COOKIE_TRANSACTIONS" |
            "RLIMIT_RTTIME" if musl => true,

            _ => false,
        }
    });

    cfg.skip_fn(move |name| {
        // skip those that are manually verifiedmanually verified
        match name {
            "execv" |       // crazy stuff with const/mut
            "execve" |
            "execvp" |
            "execvpe" => true,

            "getrlimit" | "getrlimit64" |    // non-int in 1st arg
            "setrlimit" | "setrlimit64" |    // non-int in 1st arg
            "strerror_r" if linux => true,   // actually xpg-something-or-other

            // typed 2nd arg on linux and android
            "gettimeofday" if linux || android || freebsd => true,

            "dlerror" if android => true, // const-ness is added
            "dladdr" if musl => true, // const-ness only added recently

            // OSX has 'struct tm *const' which we can't actually represent in
            // Rust, but is close enough to *mut
            "timegm" if apple => true,

            _ => false,
        }
    });

    // Windows dllimport oddness?
    cfg.skip_fn_ptrcheck(move |_| windows);

    cfg.skip_field_type(move |struct_, field| {
        // This is a weird union, don't check the type.
        (struct_ == "ifaddrs" && field == "ifa_ifu") ||
        // sighandler_t type is super weird
        (struct_ == "sigaction" && field == "sa_sigaction")
    });

    cfg.skip_field(move |struct_, field| {
        // this is actually a union on linux, so we can't represent it well and
        // just insert some padding.
        (struct_ == "siginfo_t" && field == "_pad") ||
        // musl names this __dummy1 but it's still there
        (musl && struct_ == "glob_t" && field == "gl_flags")
    });

    cfg.generate("../src/lib.rs", "all.rs");
}
<commit_msg>Disable sockaddr_nl on musl target<commit_after>#![deny(warnings)]

extern crate ctest;

use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    let windows = target.contains("windows");
    let mingw = target.contains("windows-gnu");
    let linux = target.contains("unknown-linux");
    let android = target.contains("android");
    let apple = target.contains("apple");
    let musl = target.contains("musl");
    let freebsd = target.contains("freebsd");
    let bsdlike = freebsd || apple;
    let mut cfg = ctest::TestGenerator::new();

    // Pull in extra goodies on linux/mingw
    if target.contains("unknown-linux") {
        cfg.define("_GNU_SOURCE", None);
    } else if windows {
        cfg.define("_WIN32_WINNT", Some("0x8000"));
    }

    // Android doesn't actually have in_port_t but it's much easier if we
    // provide one for us to test against
    if android {
        cfg.define("in_port_t", Some("uint16_t"));
    }

    cfg.header("errno.h")
       .header("fcntl.h")
       .header("limits.h")
       .header("stddef.h")
       .header("stdint.h")
       .header("stdio.h")
       .header("stdlib.h")
       .header("sys/stat.h")
       .header("sys/types.h")
       .header("time.h")
       .header("wchar.h");

    if windows {
        cfg.header("winsock2.h"); // must be before windows.h

        cfg.header("direct.h");
        cfg.header("io.h");
        cfg.header("sys/utime.h");
        cfg.header("windows.h");
        cfg.header("process.h");
        cfg.header("ws2ipdef.h");

        if target.contains("gnu") {
            cfg.header("ws2tcpip.h");
        }
    } else {
        cfg.header("ctype.h");
        cfg.header("dirent.h");
        cfg.header("net/if.h");
        cfg.header("netdb.h");
        cfg.header("netinet/in.h");
        cfg.header("netinet/ip.h");
        cfg.header("netinet/tcp.h");
        cfg.header("pthread.h");
        cfg.header("dlfcn.h");
        cfg.header("signal.h");
        cfg.header("string.h");
        cfg.header("sys/file.h");
        cfg.header("sys/ioctl.h");
        cfg.header("sys/mman.h");
        cfg.header("sys/resource.h");
        cfg.header("sys/socket.h");
        cfg.header("sys/time.h");
        cfg.header("sys/un.h");
        cfg.header("sys/wait.h");
        cfg.header("unistd.h");
        cfg.header("utime.h");
        cfg.header("pwd.h");
        cfg.header("grp.h");
    }

    if android {
        cfg.header("arpa/inet.h");
        cfg.header("time64.h");
    } else if !windows {
        cfg.header("glob.h");
        cfg.header("ifaddrs.h");
        cfg.header("sys/statvfs.h");

        if !musl {
            cfg.header("execinfo.h");
            cfg.header("sys/sysctl.h");
        }
    }

    if apple {
        cfg.header("mach-o/dyld.h");
        cfg.header("mach/mach_time.h");
        cfg.header("malloc/malloc.h");
        if target.starts_with("x86") {
            cfg.header("crt_externs.h");
        }
    }

    if linux || android {
        cfg.header("netpacket/packet.h");
        cfg.header("net/ethernet.h");
        cfg.header("malloc.h");
        cfg.header("sys/prctl.h");
        /* linux kernel header */
        if !musl {
            cfg.header("linux/netlink.h");
        }
    }

    if freebsd {
        cfg.header("pthread_np.h");
    }

    cfg.type_name(move |ty, is_struct| {
        match ty {
            // Just pass all these through, no need for a "struct" prefix
            "FILE" |
            "fd_set" |
            "Dl_info" |
            "DIR" => ty.to_string(),

            // Fixup a few types on windows that don't actually exist.
            "time64_t" if windows => "__time64_t".to_string(),
            "ssize_t" if windows => "SSIZE_T".to_string(),

            // OSX calls this something else
            "sighandler_t" if bsdlike => "sig_t".to_string(),

            t if t.ends_with("_t") => t.to_string(),

            // Windows uppercase structs don't have `struct` in front, there's a
            // few special cases for windows, and then otherwise put `struct` in
            // front of everything.
            t if is_struct => {
                if windows && ty.chars().next().unwrap().is_uppercase() {
                    t.to_string()
                } else if windows && t == "stat" {
                    "struct __stat64".to_string()
                } else if windows && t == "utimbuf" {
                    "struct __utimbuf64".to_string()
                } else {
                    format!("struct {}", t)
                }
            }

            t => t.to_string(),
        }
    });

    let target2 = target.clone();
    cfg.field_name(move |struct_, field| {
        match field {
            // Our stat *_nsec fields normally don't actually exist but are part
            // of a timeval struct
            s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
                if target2.contains("apple") {
                    s.replace("_nsec", "spec.tv_nsec")
                } else if target2.contains("android") {
                    s.to_string()
                } else {
                    s.replace("e_nsec", ".tv_nsec")
                }
            }
            s => s.to_string(),
        }
    });

    cfg.skip_type(move |ty| {
        match ty {
            // sighandler_t is crazy across platforms
            "sighandler_t" => true,

            _ => false
        }
    });

    cfg.skip_struct(move |ty| {
        match ty {
            "sockaddr_nl" => musl,
            _ => false
        }
    });

    cfg.skip_signededness(|c| {
        match c {
            "LARGE_INTEGER" |
            "mach_timebase_info_data_t" |
            "float" |
            "double" => true,
            n if n.starts_with("pthread") => true,

            // windows-isms
            n if n.starts_with("P") => true,
            n if n.starts_with("H") => true,
            n if n.starts_with("LP") => true,
            _ => false,
        }
    });

    cfg.skip_const(move |name| {
        match name {
            // Apparently these don't exist in mingw headers?
            "MEM_RESET_UNDO" |
            "FILE_ATTRIBUTE_NO_SCRUB_DATA" |
            "FILE_ATTRIBUTE_INTEGRITY_STREAM" |
            "ERROR_NOTHING_TO_TERMINATE" if mingw => true,

            "SIG_IGN" => true, // sighandler_t weirdness

            // types on musl are defined a little differently
            n if musl && n.contains("__SIZEOF_PTHREAD") => true,

            // Skip constants not defined in MUSL but just passed down to the
            // kernel regardless
            "RLIMIT_NLIMITS" |
            "TCP_COOKIE_TRANSACTIONS" |
            "RLIMIT_RTTIME" if musl => true,

            _ => false,
        }
    });

    cfg.skip_fn(move |name| {
        // skip those that are manually verifiedmanually verified
        match name {
            "execv" |       // crazy stuff with const/mut
            "execve" |
            "execvp" |
            "execvpe" => true,

            "getrlimit" | "getrlimit64" |    // non-int in 1st arg
            "setrlimit" | "setrlimit64" |    // non-int in 1st arg
            "strerror_r" if linux => true,   // actually xpg-something-or-other

            // typed 2nd arg on linux and android
            "gettimeofday" if linux || android || freebsd => true,

            "dlerror" if android => true, // const-ness is added
            "dladdr" if musl => true, // const-ness only added recently

            // OSX has 'struct tm *const' which we can't actually represent in
            // Rust, but is close enough to *mut
            "timegm" if apple => true,

            _ => false,
        }
    });

    // Windows dllimport oddness?
    cfg.skip_fn_ptrcheck(move |_| windows);

    cfg.skip_field_type(move |struct_, field| {
        // This is a weird union, don't check the type.
        (struct_ == "ifaddrs" && field == "ifa_ifu") ||
        // sighandler_t type is super weird
        (struct_ == "sigaction" && field == "sa_sigaction")
    });

    cfg.skip_field(move |struct_, field| {
        // this is actually a union on linux, so we can't represent it well and
        // just insert some padding.
        (struct_ == "siginfo_t" && field == "_pad") ||
        // musl names this __dummy1 but it's still there
        (musl && struct_ == "glob_t" && field == "gl_flags")
    });

    cfg.generate("../src/lib.rs", "all.rs");
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
}

struct Command {
    command: ~str,
    args: ~[~str],
    background: bool,
}

impl Command {
    // Really ugly argument parser.
    fn new(cmd_line: &str) -> Command {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        let mut cmd = Command {
            command: "".to_owned(),
            args: argv.to_owned(),
            background: false
        };
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            cmd = Command {
                command: program.to_owned(),
                args: argv.to_owned(),
                background: false
            };
            if argv.len() > 0 {
                let last = argv.last();
                if *last == ~"&" {
                    cmd.background = true;
                }
            }
        }
        cmd
    }

    fn run(&mut self) {
        if self.cmd_exists() {
            run::process_status(self.command, self.args);
        } else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            // Push run commands onto the history stack
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  { return; }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut cmd = Command::new(cmd_line);
        cmd.run();
    }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>broken impl of background processes<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
}

struct Process {
    command: ~str,
    args: ~[~str],
    exit_status: Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command: ~str,
    args: ~[~str],
    background: bool,
    exit_status: Option<process::ProcessExit>,
    io_port: Option<Port<Option <process::ProcessExit>>>,
}

trait Command {
    fn run(&mut self);
    fn cmd_exists(&mut self) -> bool;
}

impl Process {
    fn new(cmd_line: &str) -> Process {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        let mut cmd = Process {
            command: "".to_owned(),
            args: argv.to_owned(),
            exit_status: None,
        };
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            cmd = Process {
                command: program.to_owned(),
                args: argv.to_owned(),
                exit_status: None,
            };
            if argv.len() > 0 {
                let last = argv.last();
            }
        }
        cmd
    }
}

impl BackgroundProcess {
    fn new(cmd_line: &str) -> BackgroundProcess {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        let mut cmd = BackgroundProcess {
            command: "".to_owned(),
            args: argv.to_owned(),
            background: false,
            exit_status: None,
            io_port: None,
        };
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            cmd = BackgroundProcess {
                command: program.to_owned(),
                args: argv.to_owned(),
                background: false,
                exit_status: None,
                io_port: None,
            };
            if argv.len() > 0 {
                let last = argv.last();
                if *last == ~"&" {
                    cmd.args.pop();
                    cmd.background = true;
                    println!("{:s} is backgrounded.", cmd.command);
                }
            }
        }
        cmd
    }
}

impl Command for Process {
    fn run(&mut self) {
        if self.cmd_exists() {
                run::process_status(self.command, self.args);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        if self.cmd_exists() {
            match self.background {
                true => {
                    let (port, chan) :
                        (Port<Option<process::ProcessExit>>,
                         Chan<Option<process::ProcessExit>>)
                        = Chan::new();
                    let command = self.command.to_owned();
                    let args = self.args.to_owned();
                    spawn(proc() {
                        chan.send(run::process_status(command, args));
                    });
                    self.io_port = Some(port);
                }
                false => {
                    run::process_status(self.command, self.args);
                }
            }
        } else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[]
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            // Push run commands onto the history stack
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  { return; }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut cmd = Process::new(cmd_line);
        cmd.run();
    }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>