<commit_before>// Copyright 2012-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;
use super::shadow::ShadowGraph;

#[derive(Debug)]
pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // The "shadow graph" is a debugging aid. We give it each message
    // in real time as it arrives and it checks for various errors
    // (for example, a read/write when there is no current task; it
    // can also apply user-defined filters; see `shadow` module for
    // details). This only occurs if debug-assertions are enabled.
    //
    // Note that in some cases the same errors will occur when the
    // data is processed off the main thread, but that's annoying
    // because it lacks precision about the source of the error.
    shadow_graph: ShadowGraph,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            shadow_graph: ShadowGraph::new(),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    /// True if we are actually building the full dep-graph.
    #[inline]
    pub fn is_fully_enabled(&self) -> bool {
        self.enabled
    }

    /// True if (a) we are actually building the full dep-graph, or (b) we are
    /// only enqueuing messages in order to sanity-check them (which happens
    /// when debug assertions are enabled).
    #[inline]
    pub fn is_enqueue_enabled(&self) -> bool {
        self.is_fully_enabled() || self.shadow_graph.enabled()
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.is_fully_enabled(), "should never swap if not fully enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.is_fully_enabled(), "should never query if not fully enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        assert!(self.is_enqueue_enabled(), "should never enqueue if not enqueue-enabled");
        self.shadow_graph.enqueue(&message);
        if self.is_fully_enabled() {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        if let Err(_) = swap_out.send(messages) {
            // the receiver must have been dropped already
            break;
        }
    }
}
<commit_msg>consistent doc wording<commit_after>// Copyright 2012-2015 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;
use super::shadow::ShadowGraph;

#[derive(Debug)]
pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // The "shadow graph" is a debugging aid. We give it each message
    // in real time as it arrives and it checks for various errors
    // (for example, a read/write when there is no current task; it
    // can also apply user-defined filters; see `shadow` module for
    // details). This only occurs if debug-assertions are enabled.
    //
    // Note that in some cases the same errors will occur when the
    // data is processed off the main thread, but that's annoying
    // because it lacks precision about the source of the error.
    shadow_graph: ShadowGraph,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // where to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            shadow_graph: ShadowGraph::new(),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    /// True if we are actually building the full dep-graph.
    #[inline]
    pub fn is_fully_enabled(&self) -> bool {
        self.enabled
    }

    /// True if (a) we are actually building the full dep-graph, or (b) we are
    /// only enqueuing messages in order to sanity-check them (which happens
    /// when debug assertions are enabled).
    #[inline]
    pub fn is_enqueue_enabled(&self) -> bool {
        self.is_fully_enabled() || self.shadow_graph.enabled()
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.is_fully_enabled(), "should never swap if not fully enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.is_fully_enabled(), "should never query if not fully enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        assert!(self.is_enqueue_enabled(), "should never enqueue if not enqueue-enabled");
        self.shadow_graph.enqueue(&message);
        if self.is_fully_enabled() {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        if let Err(_) = swap_out.send(messages) {
            // the receiver must have been dropped already
            break;
        }
    }
}
<|endoftext|>


<commit_before>//! CPU Emulator
//!
//! Emulates the SynCpu architecture.

use byteorder::{LittleEndian, ReadBytesExt};
use instruction::{SynInt, Instruction};

use std::char;
use std::io::{Cursor, Error, stdin, Read};
use std::convert::From;
use std::fmt;

/// The size of RAM for 15-bit addressing.
const RAM_SIZE: usize = 32768;

/// The different error states that the CPU can encounter
#[derive(Debug)]
pub enum SynCpuErr {
    /// There was no error
    Ok,
    /// A pop instruction with an empty stack is an error
    PopOnEmptyStack,
    /// The CPU attempted to read an invalid instruction
    InstructionParseError(Error),
    /// The CPU does not yet support the given instruction
    UnimplementedInstruction(Instruction),
}

impl From<Error> for SynCpuErr {
    #[inline]
    fn from(val: Error) -> SynCpuErr {
        SynCpuErr::InstructionParseError(val)
    }
}

impl fmt::Display for SynCpuErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SynCpuErr::*;
        match *self {
            Ok => write!(f, "Ok"),
            PopOnEmptyStack => write!(f, "Pop called on empty stack"),
            InstructionParseError(ref err) => write!(f, "Instruction parse error: {}", err),
            UnimplementedInstruction(instr) => write!(f, "Unimplemented instruction: {}", instr),
        }
    }
}

/// An emulator for the SynCpu architecture.
pub struct SynCpu {
    /// The programme counter
    pub pc: u16,
    /// Eight 16-bit registers in the CPU
    pub registers: [u16; 8],
    /// Memory with 15-bit address space storing 16-bit values
    pub ram: [u16; RAM_SIZE],
    /// An unbounded stack which holds individual 16-bit values
    pub stack: Vec<u16>,
    /// Set to true if the execution has halted.
    pub halted: bool,
    /// An enum describing the error that halted execution, if any.
    pub error: SynCpuErr,
}

/// Tests whether a given SynInt is a register or a literal
#[inline]
pub fn is_reg(x: SynInt) -> bool {
    (x as usize) >= RAM_SIZE
}

/// Converts a given SynInt into a String
pub fn syn_int_str(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("{}", x)
    }
}

/// Converts a given SynInt into a String. Display literals as hex values.
pub fn syn_int_str_hex(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("0x{:0>4x}", x)
    }
}

impl SynCpu {

    /// Converts the given SynInt into a literal value, either directly
    /// or by reading a register
    #[inline]
    fn val(&self, x: SynInt) -> u16 {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE]
        } else {
            x
        }
    }

    /// Sets the value of the register specified by x to the value a.
    #[inline]
    fn set_reg(&mut self, x: SynInt, a: u16) {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE] = a;
        }
    }

    /// Constructs a new emulator given an input program.
    pub fn new(program: &[u8]) -> Result<SynCpu, SynCpuErr> {
        let mut cpu = SynCpu {
            pc: 0,
            registers: [0; 8],
            ram: [0xbeef; RAM_SIZE],
            stack: Vec::new(),
            halted: false,
            error: SynCpuErr::Ok,
        };

        let prog_len = program.len();
        let mut rdr = Cursor::new(program);
        let mut i = 0;

        while rdr.position() != prog_len as u64 {
            cpu.ram[i] = rdr.read_u16::<LittleEndian>()?;
            i += 1;
        }

        Ok(cpu)
    }

    /// Returns the instruction contained at the program counter offset in memory.
    #[inline]
    pub fn next_instruction(&self) -> Instruction {
        self.instruction_at(self.pc as usize)
    }

    /// Returns the instruction contained at the given offset in memory.
    #[inline]
    pub fn instruction_at(&self, offset: usize) -> Instruction {
        Instruction::read_instr(&self.ram[offset..])
    }

    /// Exectue a single instruction on the CPU.
    pub fn step(&mut self) {

        // If the CPU has halted already, stop.
        if self.halted {
            return;
        }

        // Read the instruction from memory at the program counter
        use instruction::Instruction::*;
        let instr = self.next_instruction();

        // Execute the instruction
        match instr {
            Halt => {
                self.halted = true;
            },

            Set { dst, a } => {
                let val = self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Push { src } => {
                let v = self.val(src);
                self.stack.push(v);
                self.pc += instr.size();
            },
            Pop { dst } => {
                if self.stack.is_empty() {
                    self.halted = true;
                    self.error = SynCpuErr::PopOnEmptyStack;
                }
                let val = self.stack.pop().unwrap();
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Eq { dst, a, b } => {
                let val = if self.val(a) == self.val(b) {
                    1
                } else {
                    0
                };

                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Gt { dst, a, b } => {
                let val = if self.val(a) > self.val(b) {
                    1
                } else {
                    0
                };
                self.set_reg(dst, val);
                self.pc += instr.size();
            },

            Jmp { dst } => {
                self.pc = dst;
            },
            Jt { src, dst } => {
                if self.val(src) != 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },
            Jf { src, dst } => {
                if self.val(src) == 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },

            Add { dst, a, b } => {
                let sum = (self.val(a) as u64) + (self.val(b) as u64);
                self.set_reg(dst, (sum % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mult { dst, a, b } => {
                let mul = (self.val(a) as u64) * (self.val(b) as u64);
                self.set_reg(dst, (mul % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mod { dst, a, b } => {
                let mul = self.val(a) % self.val(b);
                self.set_reg(dst, mul);
                self.pc += instr.size();
            },
            And { dst, a, b } => {
                let val = self.val(a) & self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Or { dst, a, b } => {
                let val = self.val(a) | self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Not { dst, a } => {
                let val = 0b111111111111111 ^ self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            ReadMem { dst, src } => {
                let address = self.val(src);
                let val = self.ram[address as usize];
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            WriteMem { dst, src } => {
                let address = self.val(dst);
                self.ram[address as usize] = self.val(src);
                self.pc += instr.size();
            },
            Call { dst } => {
                let next_instr = self.pc + instr.size();
                self.stack.push(next_instr);
                self.pc = self.val(dst);
            },
            Ret => {
                if self.stack.is_empty() {
                    self.halted = true;
                    self.error = SynCpuErr::PopOnEmptyStack;
                }
                let val = self.stack.pop().unwrap();
                self.pc = val;
            }
            Out { value } => {
                print!("{}", char::from_u32(self.val(value) as u32).unwrap());
                self.pc += instr.size();
            },
            In { dst } => {
                let mut buf = [0; 1];
                stdin().read_exact(&mut buf).unwrap();
                self.set_reg(dst, buf[0] as u16);
                self.pc += instr.size();
            },
            Noop => { self.pc += 1; },
            _ => {
                self.halted = true;
                self.error = SynCpuErr::UnimplementedInstruction(instr);
            }
        };
    }

}
<commit_msg>Fixed incorrect error on Ret CPU instruction.<commit_after>//! CPU Emulator
//!
//! Emulates the SynCpu architecture.

use byteorder::{LittleEndian, ReadBytesExt};
use instruction::{SynInt, Instruction};

use std::char;
use std::io::{Cursor, Error, stdin, Read};
use std::convert::From;
use std::fmt;

/// The size of RAM for 15-bit addressing.
const RAM_SIZE: usize = 32768;

/// The different error states that the CPU can encounter
#[derive(Debug)]
pub enum SynCpuErr {
    /// There was no error
    Ok,
    /// A pop instruction with an empty stack is an error
    PopOnEmptyStack,
    /// The CPU attempted to read an invalid instruction
    InstructionParseError(Error),
    /// The CPU does not yet support the given instruction
    UnimplementedInstruction(Instruction),
}

impl From<Error> for SynCpuErr {
    #[inline]
    fn from(val: Error) -> SynCpuErr {
        SynCpuErr::InstructionParseError(val)
    }
}

impl fmt::Display for SynCpuErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SynCpuErr::*;
        match *self {
            Ok => write!(f, "Ok"),
            PopOnEmptyStack => write!(f, "Pop called on empty stack"),
            InstructionParseError(ref err) => write!(f, "Instruction parse error: {}", err),
            UnimplementedInstruction(instr) => write!(f, "Unimplemented instruction: {}", instr),
        }
    }
}

/// An emulator for the SynCpu architecture.
pub struct SynCpu {
    /// The programme counter
    pub pc: u16,
    /// Eight 16-bit registers in the CPU
    pub registers: [u16; 8],
    /// Memory with 15-bit address space storing 16-bit values
    pub ram: [u16; RAM_SIZE],
    /// An unbounded stack which holds individual 16-bit values
    pub stack: Vec<u16>,
    /// Set to true if the execution has halted.
    pub halted: bool,
    /// An enum describing the error that halted execution, if any.
    pub error: SynCpuErr,
}

/// Tests whether a given SynInt is a register or a literal
#[inline]
pub fn is_reg(x: SynInt) -> bool {
    (x as usize) >= RAM_SIZE
}

/// Converts a given SynInt into a String
pub fn syn_int_str(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("{}", x)
    }
}

/// Converts a given SynInt into a String. Display literals as hex values.
pub fn syn_int_str_hex(x: SynInt) -> String {
    if is_reg(x) {
        format!("r{}", x as usize - RAM_SIZE)
    } else {
        format!("0x{:0>4x}", x)
    }
}

impl SynCpu {

    /// Converts the given SynInt into a literal value, either directly
    /// or by reading a register
    #[inline]
    fn val(&self, x: SynInt) -> u16 {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE]
        } else {
            x
        }
    }

    /// Sets the value of the register specified by x to the value a.
    #[inline]
    fn set_reg(&mut self, x: SynInt, a: u16) {
        if is_reg(x) {
            self.registers[(x as usize) - RAM_SIZE] = a;
        }
    }

    /// Constructs a new emulator given an input program.
    pub fn new(program: &[u8]) -> Result<SynCpu, SynCpuErr> {
        let mut cpu = SynCpu {
            pc: 0,
            registers: [0; 8],
            ram: [0xbeef; RAM_SIZE],
            stack: Vec::new(),
            halted: false,
            error: SynCpuErr::Ok,
        };

        let prog_len = program.len();
        let mut rdr = Cursor::new(program);
        let mut i = 0;

        while rdr.position() != prog_len as u64 {
            cpu.ram[i] = rdr.read_u16::<LittleEndian>()?;
            i += 1;
        }

        Ok(cpu)
    }

    /// Returns the instruction contained at the program counter offset in memory.
    #[inline]
    pub fn next_instruction(&self) -> Instruction {
        self.instruction_at(self.pc as usize)
    }

    /// Returns the instruction contained at the given offset in memory.
    #[inline]
    pub fn instruction_at(&self, offset: usize) -> Instruction {
        Instruction::read_instr(&self.ram[offset..])
    }

    /// Exectue a single instruction on the CPU.
    pub fn step(&mut self) {

        // If the CPU has halted already, stop.
        if self.halted {
            return;
        }

        // Read the instruction from memory at the program counter
        use instruction::Instruction::*;
        let instr = self.next_instruction();

        // Execute the instruction
        match instr {
            Halt => {
                self.halted = true;
            },

            Set { dst, a } => {
                let val = self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Push { src } => {
                let v = self.val(src);
                self.stack.push(v);
                self.pc += instr.size();
            },
            Pop { dst } => {
                if self.stack.is_empty() {
                    self.halted = true;
                    self.error = SynCpuErr::PopOnEmptyStack;
                }
                let val = self.stack.pop().unwrap();
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Eq { dst, a, b } => {
                let val = if self.val(a) == self.val(b) {
                    1
                } else {
                    0
                };

                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Gt { dst, a, b } => {
                let val = if self.val(a) > self.val(b) {
                    1
                } else {
                    0
                };
                self.set_reg(dst, val);
                self.pc += instr.size();
            },

            Jmp { dst } => {
                self.pc = dst;
            },
            Jt { src, dst } => {
                if self.val(src) != 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },
            Jf { src, dst } => {
                if self.val(src) == 0 {
                    self.pc = dst;
                } else {
                    self.pc += instr.size();
                }
            },

            Add { dst, a, b } => {
                let sum = (self.val(a) as u64) + (self.val(b) as u64);
                self.set_reg(dst, (sum % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mult { dst, a, b } => {
                let mul = (self.val(a) as u64) * (self.val(b) as u64);
                self.set_reg(dst, (mul % (RAM_SIZE as u64)) as u16);
                self.pc += instr.size();
            },
            Mod { dst, a, b } => {
                let mul = self.val(a) % self.val(b);
                self.set_reg(dst, mul);
                self.pc += instr.size();
            },
            And { dst, a, b } => {
                let val = self.val(a) & self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Or { dst, a, b } => {
                let val = self.val(a) | self.val(b);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            Not { dst, a } => {
                let val = 0b111111111111111 ^ self.val(a);
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            ReadMem { dst, src } => {
                let address = self.val(src);
                let val = self.ram[address as usize];
                self.set_reg(dst, val);
                self.pc += instr.size();
            },
            WriteMem { dst, src } => {
                let address = self.val(dst);
                self.ram[address as usize] = self.val(src);
                self.pc += instr.size();
            },
            Call { dst } => {
                let next_instr = self.pc + instr.size();
                self.stack.push(next_instr);
                self.pc = self.val(dst);
            },
            Ret => {
                if self.stack.is_empty() {
                    self.halted = true;
                }
                let val = self.stack.pop().unwrap();
                self.pc = val;
            }
            Out { value } => {
                print!("{}", char::from_u32(self.val(value) as u32).unwrap());
                self.pc += instr.size();
            },
            In { dst } => {
                let mut buf = [0; 1];
                stdin().read_exact(&mut buf).unwrap();
                self.set_reg(dst, buf[0] as u16);
                self.pc += instr.size();
            },
            Noop => { self.pc += 1; },
            _ => {
                self.halted = true;
                self.error = SynCpuErr::UnimplementedInstruction(instr);
            }
        };
    }

}
<|endoftext|>


<commit_before>//!
//! # Scheduler
//!

use std::mem;
use std::sync::*;
use std::thread::*;
use std::sync::mpsc::*;
use std::collections::vec_deque::*;

lazy_static! {
    static ref SCHEDULER: Arc<Scheduler> = Arc::new(Scheduler::new());
}

///
/// Trait implemented by things that can be scheduled as a job
///
trait ScheduledJob : Send {
    /// Runs this particular job
    fn run(&mut self);
}

///
/// Basic job is just a FnOnce
///
struct Job<TFn>
where TFn: Send+FnOnce() -> () {
    action: Option<TFn>
}

impl<TFn> Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn new(action: TFn) -> Job<TFn> {
        Job { action: Some(action) }
    }
}

impl<TFn> ScheduledJob for Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn run(&mut self) {
        // Consume the action when it's run
        let mut action = None;
        mem::swap(&mut action, &mut self.action);

        if let Some(action) = action {
            action();
        } else {
            panic!("Cannot schedule an action twice");
        }
    }
}

///
/// The scheduler is used to schedule tasks onto a pool of threads
///
pub struct Scheduler {
    /// The queues that are active in the scheduler
    queues: Arc<Mutex<Vec<Weak<JobQueue>>>>,

    /// Active threads
    threads: Mutex<Vec<SchedulerThread>>
}

///
/// A job queue provides a list of jobs to perform in order
///
pub struct JobQueue {
    /// Jobs scheduled on this queue
    queue: Mutex<VecDeque<Box<ScheduledJob>>>,

    /// True while this queue is running
    running: Mutex<bool>
}

///
/// A scheduler thread reads from the scheduler queue
///
struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<ScheduledJob>>,

    /// The thread itself
    thread: JoinHandle<()>,

    /// Flag that indicates that this thread is busy
    busy: Arc<Mutex<bool>>
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<ScheduledJob>>, Receiver<Box<ScheduledJob>>) = channel();
        let thread = spawn(move || {
            while let Ok(mut job) = jobs_out.recv() {
                job.run();
            }
        });

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread,
            busy:   Arc::new(Mutex::new(false))
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    fn run<Job: 'static+ScheduledJob>(&self, job: Job) {
        self.jobs.send(Box::new(job)).unwrap();
    }
}

impl JobQueue {
    ///
    /// Creates a new job queue
    ///
    fn new() -> JobQueue {
        JobQueue {
            queue:      Mutex::new(VecDeque::new()),
            running:    Mutex::new(false)
        }
    }

    ///
    /// Adds a new job to this queue, returns true if the queue is dormant and needs to be started
    ///
    fn queue<TJob: 'static+ScheduledJob>(&self, job: TJob) -> bool {
        let mut queue   = self.queue.lock().unwrap();
        let running     = self.running.lock().unwrap();

        queue.push_back(Box::new(job));

        !*running
    }

    ///
    /// If there are any jobs waiting, dequeues the next one
    ///
    fn dequeue(&self) -> Option<Box<ScheduledJob>> {
        let mut queue = self.queue.lock().unwrap();

        queue.pop_front()
    }

    ///
    /// Runs jobs on this queue until there are none left, marking the job as inactive when done
    ///
    fn drain(&self) {
        let mut done = false;

        while !done {
            // Run jobs until the queue is drained
            while let Some(mut job) = self.dequeue() {
                job.run();
            }

            // Mark as not running any more
            {
                let queue       = self.queue.lock().unwrap();
                let mut running = self.running.lock().unwrap();

                // If the queue is empty at the point where we obtain the 'running' lock, we can deactivate ourselves
                if queue.len() == 0 {
                    *running    = false;
                    done        = true;
                }
            }
        }
    }
}

impl Scheduler {
    ///
    /// Creates a new scheduler
    ///
    /// (There's only actually one scheduler)
    ///
    fn new() -> Scheduler {
        let result = Scheduler {
            queues:     Arc::new(Mutex::new(vec![])),
            threads:    Mutex::new(vec![])
        };

        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();

        result
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    fn next_to_run(queues: &Arc<Mutex<Vec<Weak<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let queues = queues.lock().unwrap();

        // Find a queue where is_running is false
        for q in queues.iter() {
            // Queue is a weak ref, check that it's still in use
            if let Some(q) = q.upgrade() {
                // If the queue is not running, then mark it as running and return it
                let mut is_running = q.running.lock().unwrap();
                if !*is_running {
                    // Clone here is necessary because the is_running update is borrowing q
                    *is_running = true;
                    return Some(q.clone());
                }
            }
        }

        None
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    fn schedule_dormant<NextJob, RunJob, JobData>(&self, next_job: NextJob, job: RunJob) -> bool
    where RunJob: 'static+Send+Fn(JobData) -> (), NextJob: 'static+Send+Fn() -> Option<JobData> {
        let threads = self.threads.lock().unwrap();

        for thread in threads.iter() {
            let mut busy = thread.busy.lock().unwrap();

            if !*busy {
                let also_busy = thread.busy.clone();

                *busy = true;
                thread.run(Job::new(move || {
                    let mut done = false;

                    while !done {
                        // Obtain the next job
                        let job_data = {
                            let mut busy = also_busy.lock().unwrap();
                            let job_data = next_job();

                            // If there's no next job, then this thread is no longer busy
                            if job_data.is_none() {
                                *busy = false;
                            }

                            job_data
                        };

                        // Run the job if there is one, stop the thread if there is not
                        if let Some(job_data) = job_data {
                            job(job_data);
                        } else {
                            done = true;
                        }
                    }
                }));

                return true;
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    fn schedule_thread(&self) -> bool {
        // Find a dormant thread and activate it
        let queues = self.queues.clone();

        // Schedule work on this dormant thread
        self.schedule_dormant(move || Self::next_to_run(&queues), move |work| work.drain())
    }

    ///
    /// Spawns a thread in this scheduler
    ///
    pub fn spawn_thread(&self) {
        let new_thread = SchedulerThread::new();
        self.threads.lock().unwrap().push(new_thread);
    }

    ///
    /// Creates a new job queue for this scheduler
    ///
    pub fn create_job_queue(&self) -> Arc<JobQueue> {
        let new_queue = Arc::new(JobQueue::new());

        self.queues.lock().unwrap().push(Arc::downgrade(&new_queue));

        new_queue
    }

    ///
    /// Schedules a job on this scheduler
    ///
    pub fn async<TFn: 'static+Send+FnOnce() -> ()>(&self, queue: &Arc<JobQueue>, job: TFn) {
        if queue.queue(Job::new(job)) {
            // A true result indicates that the job was scheduled but the queue is not running. Try to schedule a thread if this occurs.
            self.schedule_thread();
        }
    }
}

///
/// Retrieves the global scheduler
///
pub fn scheduler<'a>() -> &'a Scheduler {
    &SCHEDULER
}

///
/// Creates a scheduler queue
///
pub fn queue() -> Arc<JobQueue> {
    scheduler().create_job_queue()
}

///
/// Creates a scheduler queue
///
pub fn async<TFn: 'static+Send+FnOnce() -> ()>(queue: &Arc<JobQueue>, job: TFn) {
    scheduler().async(queue, job)
}

#[cfg(test)]
mod test {
    use super::*;
    use std::time::*;

    #[test]
    fn can_schedule_async() {
        let (tx, rx)    = channel();
        let queue       = queue();

        async(&queue, move || {
            tx.send(42).unwrap();
        });

        assert!(rx.recv().unwrap() == 42);
    }

    #[test]
    fn will_schedule_in_order() {
        let (tx, rx)    = channel();
        let queue       = queue();

        let (tx1, tx2)  = (tx.clone(), tx.clone());

        async(&queue, move || {
            sleep(Duration::from_millis(100));
            tx1.send(1).unwrap();
        });
        async(&queue, move || {
            tx2.send(2).unwrap();
        });

        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv().unwrap() == 2);
    }

    #[test]
    fn will_schedule_separate_queues_in_parallel() {
        let (tx, rx)        = channel();
        let queue1          = queue();
        let queue2          = queue();
        let queue2_has_run  = Arc::new(Mutex::new(false));

        let queue1_check = queue2_has_run.clone();

        async(&queue1, move || {
            // The other task needs to start within 100ms for this to work
            sleep(Duration::from_millis(100));
            tx.send(*queue1_check.lock().unwrap()).unwrap();
        });
        async(&queue2, move || {
            *queue2_has_run.lock().unwrap() = true;
        });

        assert!(rx.recv().unwrap() == true);
    }
}
<commit_msg>When creating a queue, replace any queues we find that have become unused due to weakness<commit_after>//!
//! # Scheduler
//!

use std::mem;
use std::sync::*;
use std::thread::*;
use std::sync::mpsc::*;
use std::collections::vec_deque::*;

lazy_static! {
    static ref SCHEDULER: Arc<Scheduler> = Arc::new(Scheduler::new());
}

///
/// Trait implemented by things that can be scheduled as a job
///
trait ScheduledJob : Send {
    /// Runs this particular job
    fn run(&mut self);
}

///
/// Basic job is just a FnOnce
///
struct Job<TFn>
where TFn: Send+FnOnce() -> () {
    action: Option<TFn>
}

impl<TFn> Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn new(action: TFn) -> Job<TFn> {
        Job { action: Some(action) }
    }
}

impl<TFn> ScheduledJob for Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn run(&mut self) {
        // Consume the action when it's run
        let mut action = None;
        mem::swap(&mut action, &mut self.action);

        if let Some(action) = action {
            action();
        } else {
            panic!("Cannot schedule an action twice");
        }
    }
}

///
/// The scheduler is used to schedule tasks onto a pool of threads
///
pub struct Scheduler {
    /// The queues that are active in the scheduler
    queues: Arc<Mutex<Vec<Weak<JobQueue>>>>,

    /// Active threads
    threads: Mutex<Vec<SchedulerThread>>
}

///
/// A job queue provides a list of jobs to perform in order
///
pub struct JobQueue {
    /// Jobs scheduled on this queue
    queue: Mutex<VecDeque<Box<ScheduledJob>>>,

    /// True while this queue is running
    running: Mutex<bool>
}

///
/// A scheduler thread reads from the scheduler queue
///
struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<ScheduledJob>>,

    /// The thread itself
    thread: JoinHandle<()>,

    /// Flag that indicates that this thread is busy
    busy: Arc<Mutex<bool>>
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<ScheduledJob>>, Receiver<Box<ScheduledJob>>) = channel();
        let thread = spawn(move || {
            while let Ok(mut job) = jobs_out.recv() {
                job.run();
            }
        });

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread,
            busy:   Arc::new(Mutex::new(false))
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    fn run<Job: 'static+ScheduledJob>(&self, job: Job) {
        self.jobs.send(Box::new(job)).unwrap();
    }
}

impl JobQueue {
    ///
    /// Creates a new job queue
    ///
    fn new() -> JobQueue {
        JobQueue {
            queue:      Mutex::new(VecDeque::new()),
            running:    Mutex::new(false)
        }
    }

    ///
    /// Adds a new job to this queue, returns true if the queue is dormant and needs to be started
    ///
    fn queue<TJob: 'static+ScheduledJob>(&self, job: TJob) -> bool {
        let mut queue   = self.queue.lock().unwrap();
        let running     = self.running.lock().unwrap();

        queue.push_back(Box::new(job));

        !*running
    }

    ///
    /// If there are any jobs waiting, dequeues the next one
    ///
    fn dequeue(&self) -> Option<Box<ScheduledJob>> {
        let mut queue = self.queue.lock().unwrap();

        queue.pop_front()
    }

    ///
    /// Runs jobs on this queue until there are none left, marking the job as inactive when done
    ///
    fn drain(&self) {
        let mut done = false;

        while !done {
            // Run jobs until the queue is drained
            while let Some(mut job) = self.dequeue() {
                job.run();
            }

            // Mark as not running any more
            {
                let queue       = self.queue.lock().unwrap();
                let mut running = self.running.lock().unwrap();

                // If the queue is empty at the point where we obtain the 'running' lock, we can deactivate ourselves
                if queue.len() == 0 {
                    *running    = false;
                    done        = true;
                }
            }
        }
    }
}

impl Scheduler {
    ///
    /// Creates a new scheduler
    ///
    /// (There's only actually one scheduler)
    ///
    fn new() -> Scheduler {
        let result = Scheduler {
            queues:     Arc::new(Mutex::new(vec![])),
            threads:    Mutex::new(vec![])
        };

        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();

        result
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    fn next_to_run(queues: &Arc<Mutex<Vec<Weak<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let queues = queues.lock().unwrap();

        // Find a queue where is_running is false
        for q in queues.iter() {
            // Queue is a weak ref, check that it's still in use
            if let Some(q) = q.upgrade() {
                // If the queue is not running, then mark it as running and return it
                let mut is_running = q.running.lock().unwrap();
                if !*is_running {
                    // Clone here is necessary because the is_running update is borrowing q
                    *is_running = true;
                    return Some(q.clone());
                }
            }
        }

        None
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    fn schedule_dormant<NextJob, RunJob, JobData>(&self, next_job: NextJob, job: RunJob) -> bool
    where RunJob: 'static+Send+Fn(JobData) -> (), NextJob: 'static+Send+Fn() -> Option<JobData> {
        let threads = self.threads.lock().unwrap();

        for thread in threads.iter() {
            let mut busy = thread.busy.lock().unwrap();

            if !*busy {
                let also_busy = thread.busy.clone();

                *busy = true;
                thread.run(Job::new(move || {
                    let mut done = false;

                    while !done {
                        // Obtain the next job
                        let job_data = {
                            let mut busy = also_busy.lock().unwrap();
                            let job_data = next_job();

                            // If there's no next job, then this thread is no longer busy
                            if job_data.is_none() {
                                *busy = false;
                            }

                            job_data
                        };

                        // Run the job if there is one, stop the thread if there is not
                        if let Some(job_data) = job_data {
                            job(job_data);
                        } else {
                            done = true;
                        }
                    }
                }));

                return true;
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    fn schedule_thread(&self) -> bool {
        // Find a dormant thread and activate it
        let queues = self.queues.clone();

        // Schedule work on this dormant thread
        self.schedule_dormant(move || Self::next_to_run(&queues), move |work| work.drain())
    }

    ///
    /// Spawns a thread in this scheduler
    ///
    pub fn spawn_thread(&self) {
        let new_thread = SchedulerThread::new();
        self.threads.lock().unwrap().push(new_thread);
    }

    ///
    /// Creates a new job queue for this scheduler
    ///
    pub fn create_job_queue(&self) -> Arc<JobQueue> {
        // Create the  new queue
        let new_queue = Arc::new(JobQueue::new());

        let mut queues = self.queues.lock().unwrap();

        // Replace an existing weak queue if possible
        let weak_pos = queues.iter().position(|q| q.upgrade().is_none());

        if let Some(weak_pos) = weak_pos {
            // Replace a queue that was present but is no longer in use
            queues[weak_pos] = Arc::downgrade(&new_queue);
        } else {
            // Add to the queues managed by this object (as a weak reference)
            queues.push(Arc::downgrade(&new_queue));
        }

        new_queue
    }

    ///
    /// Schedules a job on this scheduler
    ///
    pub fn async<TFn: 'static+Send+FnOnce() -> ()>(&self, queue: &Arc<JobQueue>, job: TFn) {
        if queue.queue(Job::new(job)) {
            // A true result indicates that the job was scheduled but the queue is not running. Try to schedule a thread if this occurs.
            self.schedule_thread();
        }
    }
}

///
/// Retrieves the global scheduler
///
pub fn scheduler<'a>() -> &'a Scheduler {
    &SCHEDULER
}

///
/// Creates a scheduler queue
///
pub fn queue() -> Arc<JobQueue> {
    scheduler().create_job_queue()
}

///
/// Creates a scheduler queue
///
pub fn async<TFn: 'static+Send+FnOnce() -> ()>(queue: &Arc<JobQueue>, job: TFn) {
    scheduler().async(queue, job)
}

#[cfg(test)]
mod test {
    use super::*;
    use std::time::*;

    #[test]
    fn can_schedule_async() {
        let (tx, rx)    = channel();
        let queue       = queue();

        async(&queue, move || {
            tx.send(42).unwrap();
        });

        assert!(rx.recv().unwrap() == 42);
    }

    #[test]
    fn can_schedule_after_queue_released() {
        {
            let (tx, rx)    = channel();
            let queue1      = queue();

            async(&queue1, move || {
                tx.send(42).unwrap();
            });

            assert!(rx.recv().unwrap() == 42);
        }

        {
            let (tx, rx)    = channel();
            let queue2      = queue();

            async(&queue2, move || {
                tx.send(43).unwrap();
            });

            assert!(rx.recv().unwrap() == 43);
        }
    }

    #[test]
    fn will_schedule_in_order() {
        let (tx, rx)    = channel();
        let queue       = queue();

        let (tx1, tx2)  = (tx.clone(), tx.clone());

        async(&queue, move || {
            sleep(Duration::from_millis(100));
            tx1.send(1).unwrap();
        });
        async(&queue, move || {
            tx2.send(2).unwrap();
        });

        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv().unwrap() == 2);
    }

    #[test]
    fn will_schedule_separate_queues_in_parallel() {
        let (tx, rx)        = channel();
        let queue1          = queue();
        let queue2          = queue();
        let queue2_has_run  = Arc::new(Mutex::new(false));

        let queue1_check = queue2_has_run.clone();

        async(&queue1, move || {
            // The other task needs to start within 100ms for this to work
            sleep(Duration::from_millis(100));
            tx.send(*queue1_check.lock().unwrap()).unwrap();
        });
        async(&queue2, move || {
            *queue2_has_run.lock().unwrap() = true;
        });

        assert!(rx.recv().unwrap() == true);
    }
}
<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use crate::common;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "5e8897b7b51636f157630e6639b711d698e1d101";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // TODO: const trait impls and bounds
        "tests/rust/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs" |
        "tests/rust/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs" |
        "tests/rust/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs" |
        "tests/rust/src/test/ui/rfc-2632-const-trait-impl/syntax.rs" |
        // not actually test cases
        "tests/rust/src/test/rustdoc-ui/test-compile-fail2.rs" |
        "tests/rust/src/test/rustdoc-ui/test-compile-fail3.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
        if common::travis_ci() {
            // Something about this makes the travis build not deadlock...
            errorf!(".");
        }
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Strip common prefix from paths in test path filter<commit_after>mod progress;

use self::progress::Progress;
use crate::common;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "5e8897b7b51636f157630e6639b711d698e1d101";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    assert!(path_string.starts_with("tests/rust/src/"));
    let path = &path_string["tests/rust/src/".len()..];

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path {
        // Deprecated placement syntax
        "test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "test/ui/issues/issue-13105.rs" |
        "test/ui/issues/issue-13775.rs" |
        "test/ui/issues/issue-34074.rs" |
        // 2015-style dyn that libsyntax rejects
        "test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // TODO: const trait impls and bounds
        "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs" |
        "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs" |
        "test/ui/rfc-2632-const-trait-impl/feature-gate.rs" |
        "test/ui/rfc-2632-const-trait-impl/syntax.rs" |
        // not actually test cases
        "test/rustdoc-ui/test-compile-fail2.rs" |
        "test/rustdoc-ui/test-compile-fail3.rs" |
        "test/ui/include-single-expr-helper.rs" |
        "test/ui/include-single-expr-helper-1.rs" |
        "test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "test/ui/macros/auxiliary/macro-comma-support.rs" |
        "test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
        if common::travis_ci() {
            // Something about this makes the travis build not deadlock...
            errorf!(".");
        }
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>//! AccReader is like a BufReader, but supports partial consumption
//! import new data with `fill_buf`, get the current buffer with
//! `current_slice`, and indicate with `consume` how many bytes
//! were used

use std::io;
use std::io::{Read,BufRead};
use std::iter::{repeat,Iterator};
use std::fmt;
use std::cmp;
use std::iter;
//use std::str;

pub struct AccReader<R> {
    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

impl<R: Read> AccReader<R> {
  pub fn new(inner: R) -> AccReader<R> {
    AccReader::with_capacity(10, inner)
  }

  pub fn with_capacity(cap: usize, inner: R) -> AccReader<R> {
    let mut buf = Vec::with_capacity(cap);
    buf.extend(iter::repeat(0).take(cap));
    AccReader {
      inner: inner,
      buf: buf,
      pos: 0,
      cap: 0,
    }
  }

  /// Gets a reference to the underlying reader.
  pub fn get_ref(&self) -> &R { &self.inner }

  /// Gets a mutable reference to the underlying reader.
  pub fn get_mut(&mut self) -> &mut R { &mut self.inner }

  /// Unwraps this `AccReader`, returning the underlying reader.
  ///
  /// Note that any leftover data in the internal buffer is lost.
  pub fn into_inner(self) -> R { self.inner }

  pub fn reset_buffer_position(&mut self) {
    //println!("resetting buffer at pos: {} capacity: {}", self.pos, self.cap);
    if self.cap - self.pos > 0 {
      for i in 0..(self.cap - self.pos) {
        //println!("buf[{}] = buf[{}]", i, self.pos + i);
        self.buf[i] = self.buf[self.pos + i];
      }
    }
    self.cap = self.cap - self.pos;
    self.pos = 0;
  }

  pub fn current_slice(&self) -> &[u8] {
    //println!("current slice pos: {}, cap: {}", self.pos, self.cap);
    &self.buf[self.pos..self.cap]
  }

  pub fn capacity(&self) -> usize {
    self.cap - self.pos
  }
}

impl<R: Read> Read for AccReader<R> {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    //println!("read pos: {} cap: {} buflen: {}", self.pos, self.cap, buf.len());
    if buf.len() < self.cap - self.pos {
      match (&self.buf[self.pos..(self.pos+buf.len())]).read(buf) {
        Ok(len) => {
          self.consume(len);
          Ok(len)
        },
        Err(e) => Err(e)
      }
    } else {
      // If we don't have any buffered data and we're doing a massive read
      // (larger than our internal buffer), bypass our internal buffer
      // entirely.
      if buf.len() > self.buf.len() {
        match (&self.buf[self.pos..self.cap]).read(buf) {
          Ok(len) => {
            self.consume(len);
            self.inner.read(&mut buf[self.cap..])
          },
          Err(e) => Err(e)
        }
      } else {
        let nread = {
          let mut rem = try!(self.fill_buf());
          try!(rem.read(buf))
        };
        self.consume(nread);
        Ok(nread)
      }
    }
  }
}

impl<R: Read> BufRead for AccReader<R> {
  fn fill_buf(&mut self) -> io::Result<&[u8]> {
      //println!("fillbuf current: {:?}", str::from_utf8(&self.buf[self.pos..self.cap]).unwrap());
    if self.pos == 0 && self.cap == self.buf.len() {
      Err(io::Error::new(io::ErrorKind::Interrupted, "buffer completely filled"))
    } else {
      self.reset_buffer_position();
      //println!("buffer reset ended");
      let read = try!(self.inner.read(&mut self.buf[self.cap..]));
      self.cap += read;
      //println!("new pos: {} and cap: {} -> current: {:?}", self.pos, self.cap, str::from_utf8(&self.buf[self.pos..self.cap]).unwrap());
      Ok(&self.buf[self.pos..self.cap])
    }
  }

  fn consume(&mut self, amt: usize) {
    //println!("consumed {} bytes", amt);
    self.pos = cmp::min(self.pos + amt, self.cap);
  }
}

impl<R> fmt::Debug for AccReader<R> where R: fmt::Debug {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    fmt.debug_struct("AccReader")
      .field("reader", &self.inner)
      .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
      .finish()
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::{Cursor,BufRead};

  #[test]
  fn acc_reader_test() {
    let buf = b"AAAA\nAAAB\nAAACAAADAAAEAAAF\ndabcdEEEE";
    let c = Cursor::new(&buf[..]);

    let acc = AccReader::with_capacity(20,c);

    /*for l in acc.lines() {
      println!("l: {:?}", l);
    }*/
    //assert!(false);
    assert_eq!(4, acc.lines().count());

  }
}
<commit_msg>debug_struct is not supported on rust stable<commit_after>//! AccReader is like a BufReader, but supports partial consumption
//! import new data with `fill_buf`, get the current buffer with
//! `current_slice`, and indicate with `consume` how many bytes
//! were used

use std::io;
use std::io::{Read,BufRead};
use std::iter::{repeat,Iterator};
use std::cmp;
use std::iter;
//use std::fmt;
//use std::str;

pub struct AccReader<R> {
    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

impl<R: Read> AccReader<R> {
  pub fn new(inner: R) -> AccReader<R> {
    AccReader::with_capacity(10, inner)
  }

  pub fn with_capacity(cap: usize, inner: R) -> AccReader<R> {
    let mut buf = Vec::with_capacity(cap);
    buf.extend(iter::repeat(0).take(cap));
    AccReader {
      inner: inner,
      buf: buf,
      pos: 0,
      cap: 0,
    }
  }

  /// Gets a reference to the underlying reader.
  pub fn get_ref(&self) -> &R { &self.inner }

  /// Gets a mutable reference to the underlying reader.
  pub fn get_mut(&mut self) -> &mut R { &mut self.inner }

  /// Unwraps this `AccReader`, returning the underlying reader.
  ///
  /// Note that any leftover data in the internal buffer is lost.
  pub fn into_inner(self) -> R { self.inner }

  pub fn reset_buffer_position(&mut self) {
    //println!("resetting buffer at pos: {} capacity: {}", self.pos, self.cap);
    if self.cap - self.pos > 0 {
      for i in 0..(self.cap - self.pos) {
        //println!("buf[{}] = buf[{}]", i, self.pos + i);
        self.buf[i] = self.buf[self.pos + i];
      }
    }
    self.cap = self.cap - self.pos;
    self.pos = 0;
  }

  pub fn current_slice(&self) -> &[u8] {
    //println!("current slice pos: {}, cap: {}", self.pos, self.cap);
    &self.buf[self.pos..self.cap]
  }

  pub fn capacity(&self) -> usize {
    self.cap - self.pos
  }
}

impl<R: Read> Read for AccReader<R> {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    //println!("read pos: {} cap: {} buflen: {}", self.pos, self.cap, buf.len());
    if buf.len() < self.cap - self.pos {
      match (&self.buf[self.pos..(self.pos+buf.len())]).read(buf) {
        Ok(len) => {
          self.consume(len);
          Ok(len)
        },
        Err(e) => Err(e)
      }
    } else {
      // If we don't have any buffered data and we're doing a massive read
      // (larger than our internal buffer), bypass our internal buffer
      // entirely.
      if buf.len() > self.buf.len() {
        match (&self.buf[self.pos..self.cap]).read(buf) {
          Ok(len) => {
            self.consume(len);
            self.inner.read(&mut buf[self.cap..])
          },
          Err(e) => Err(e)
        }
      } else {
        let nread = {
          let mut rem = try!(self.fill_buf());
          try!(rem.read(buf))
        };
        self.consume(nread);
        Ok(nread)
      }
    }
  }
}

impl<R: Read> BufRead for AccReader<R> {
  fn fill_buf(&mut self) -> io::Result<&[u8]> {
      //println!("fillbuf current: {:?}", str::from_utf8(&self.buf[self.pos..self.cap]).unwrap());
    if self.pos == 0 && self.cap == self.buf.len() {
      Err(io::Error::new(io::ErrorKind::Interrupted, "buffer completely filled"))
    } else {
      self.reset_buffer_position();
      //println!("buffer reset ended");
      let read = try!(self.inner.read(&mut self.buf[self.cap..]));
      self.cap += read;
      //println!("new pos: {} and cap: {} -> current: {:?}", self.pos, self.cap, str::from_utf8(&self.buf[self.pos..self.cap]).unwrap());
      Ok(&self.buf[self.pos..self.cap])
    }
  }

  fn consume(&mut self, amt: usize) {
    //println!("consumed {} bytes", amt);
    self.pos = cmp::min(self.pos + amt, self.cap);
  }
}

/*impl<R> fmt::Debug for AccReader<R> where R: fmt::Debug {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    fmt.debug_struct("AccReader")
      .field("reader", &self.inner)
      .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
      .finish()
  }
}*/

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::{Cursor,BufRead};

  #[test]
  fn acc_reader_test() {
    let buf = b"AAAA\nAAAB\nAAACAAADAAAEAAAF\ndabcdEEEE";
    let c = Cursor::new(&buf[..]);

    let acc = AccReader::with_capacity(20,c);

    /*for l in acc.lines() {
      println!("l: {:?}", l);
    }*/
    //assert!(false);
    assert_eq!(4, acc.lines().count());

  }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;

use rustc::ty::layout::{Size};
use rustc_mir::interpret::{Pointer, Memory};
use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let mut bytes = name.to_vec();
    bytes.push(b'=');
    bytes.extend_from_slice(value);
    bytes.push(0);
    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn getcwd(
        &mut self,
        buf_op: OpTy<'tcx, Tag>,
        size_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("Function not available when isolation is enabled")
        }

        let tcx = &{this.tcx.tcx};

        let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
        let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?;
        // If we cannot get the current directory, we return null
        // FIXME: Technically we have to set the `errno` global too
        match env::current_dir() {
            Ok(cwd) =>{
                // It is not clear what happens with non-utf8 paths here
                let mut bytes = cwd.display().to_string().into_bytes();
                // If the buffer is smaller or equal than the path, we return null.
                if (bytes.len() as u64) < size {
                    // We add a `/0` terminator
                    bytes.push(0);
                    // This is ok because the buffer is larger than the path with the null terminator.
                    this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?;
                    return Ok(Scalar::Ptr(buf))
                }
                this.machine.last_error = 34; // ERANGE
            }
            Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32,
        }
        Ok(Scalar::ptr_null(&*this.tcx))
    }
}
<commit_msg>fetch ERANGE value from libc<commit_after>use std::collections::HashMap;
use std::env;

use crate::stacked_borrows::Tag;
use crate::*;
use rustc::ty::layout::Size;
use rustc_mir::interpret::{Memory, Pointer};

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr =
                        alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let mut bytes = name.to_vec();
    bytes.push(b'=');
    bytes.extend_from_slice(value);
    bytes.push(0);
    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => {
                Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?)
            }
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut()
                    .deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut()
                    .deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn getcwd(
        &mut self,
        buf_op: OpTy<'tcx, Tag>,
        size_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        if !this.machine.communicate {
            throw_unsup_format!("Function not available when isolation is enabled")
        }

        let tcx = &{ this.tcx.tcx };

        let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
        let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?;
        // If we cannot get the current directory, we return null
        // FIXME: Technically we have to set the `errno` global too
        match env::current_dir() {
            Ok(cwd) => {
                // It is not clear what happens with non-utf8 paths here
                let mut bytes = cwd.display().to_string().into_bytes();
                // If the buffer is smaller or equal than the path, we return null.
                if (bytes.len() as u64) < size {
                    // We add a `/0` terminator
                    bytes.push(0);
                    // This is ok because the buffer is larger than the path with the null terminator.
                    this.memory_mut()
                        .get_mut(buf.alloc_id)?
                        .write_bytes(tcx, buf, &bytes)?;
                    return Ok(Scalar::Ptr(buf));
                }
                this.machine.last_error = this
                    .eval_path_scalar(&["libc", "ERANGE"])?
                    .unwrap()
                    .to_u32()?;
            }
            Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32,
        }
        Ok(Scalar::ptr_null(&*this.tcx))
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the file stat action.
//!
//! A file stat action responses with stat of a given file

use std::fs::Metadata;
use std::path::PathBuf;

use log::warn;

use crate::session::{self, Error, Session};

impl From<std::io::Error> for Error {

    fn from(e: std::io::Error) -> Error {
        Error::action(e)
    }
}

#[derive(Debug)]
pub struct Request {
    path: PathBuf,
    collect_ext_attrs: bool,
    follow_symlink: bool,
}

#[derive(Debug)]
pub struct Response {
    path: PathBuf,
    metadata: Metadata,
    symlink: Option<PathBuf>,
    #[cfg(target_family = "unix")]
    ext_attrs: Vec<crate::fs::unix::ExtAttr>,
    #[cfg(target_os = "linux")]
    flags_linux: Option<u32>,
}

pub fn handle<S: Session>(session: &mut S, request: Request) -> session::Result<()> {
    let metadata = if request.follow_symlink {
        std::fs::metadata(&request.path)?
    } else {
        std::fs::symlink_metadata(&request.path)?
    };

    let symlink = if metadata.file_type().is_symlink() {
        std::fs::read_link(&request.path).map_err(|error| {
            // TODO: Make the `ack!` macro more expressive and rewrite it.
            warn! {
                "failed to read symlink for '{path}': {cause}",
                path = request.path.display(),
                cause = error,
            }
        }).ok()
    } else {
        None
    };

    #[cfg(target_family = "unix")]
    let ext_attrs = if request.collect_ext_attrs {
        // TODO: Make the `ack!` macro more expressive and then simplify it.
        match crate::fs::unix::ext_attrs(&request.path) {
            Ok(ext_attrs) => ext_attrs.collect(),
            Err(error) => {
                warn! {
                    "failed to collect attributes for '{path}': {cause}",
                    path = request.path.display(),
                    cause = error,
                };
                vec!()
            },
        }
    } else {
        vec!()
    };

    #[cfg(target_os = "linux")]
    let flags_linux = crate::fs::linux::flags(&request.path).map_err(|error| {
        // TODO: Make the `ack!` macro more expressive and rewrite it.
        warn! {
            "failed to collect flags for '{path}': {cause}",
            path = request.path.display(),
            cause = error,
        }
    }).ok();

    let response = Response {
        path: request.path,
        metadata: metadata,
        symlink: symlink,
        #[cfg(target_family = "unix")]
        ext_attrs: ext_attrs,
        #[cfg(target_os = "linux")]
        flags_linux: flags_linux,
    };

    session.reply(response)?;
    Ok(())
}

impl super::Request for Request {

    type Proto = rrg_proto::GetFileStatRequest;

    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError> {
        use std::convert::TryInto as _;

        let path = proto.pathspec
            .ok_or(session::MissingFieldError::new("path spec"))?
            .try_into().map_err(session::ParseError::malformed)?;

        Ok(Request {
            path: path,
            follow_symlink: proto.follow_symlink.unwrap_or(false),
            collect_ext_attrs: proto.collect_ext_attrs.unwrap_or(false),
        })
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("StatEntry");

    type Proto = rrg_proto::StatEntry;

    fn into_proto(self) -> Self::Proto {
        use rrg_proto::convert::IntoLossy as _;

        rrg_proto::StatEntry {
            pathspec: Some(self.path.into()),
            #[cfg(target_family = "unix")]
            ext_attrs: self.ext_attrs.into_iter().map(Into::into).collect(),
            #[cfg(target_os = "linux")]
            st_flags_linux: self.flags_linux,
            ..self.metadata.into_lossy()
        }
    }
}

#[cfg(test)]
mod tests {
}
<commit_msg>Improve error handling in the stat action.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the file stat action.
//!
//! A file stat action responses with stat of a given file

use std::fs::Metadata;
use std::path::PathBuf;

use log::warn;

use crate::session::{self, Session};

#[derive(Debug)]
pub struct Request {
    path: PathBuf,
    collect_ext_attrs: bool,
    follow_symlink: bool,
}

#[derive(Debug)]
pub struct Response {
    path: PathBuf,
    metadata: Metadata,
    symlink: Option<PathBuf>,
    #[cfg(target_family = "unix")]
    ext_attrs: Vec<crate::fs::unix::ExtAttr>,
    #[cfg(target_os = "linux")]
    flags_linux: Option<u32>,
}

#[derive(Debug)]
enum Error {
    Metadata(std::io::Error),
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            Metadata(ref error) => Some(error),
        }
    }
}

impl std::fmt::Display for Error {

    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            Metadata(ref error) => {
                write!(fmt, "unable to collect metadata: {}", error)
            }
        }
    }
}

impl From<Error> for session::Error {

    fn from(error: Error) -> session::Error {
        session::Error::action(error)
    }
}

pub fn handle<S: Session>(session: &mut S, request: Request) -> session::Result<()> {
    let metadata = if request.follow_symlink {
        std::fs::metadata(&request.path)
    } else {
        std::fs::symlink_metadata(&request.path)
    }.map_err(Error::Metadata)?;

    let symlink = if metadata.file_type().is_symlink() {
        std::fs::read_link(&request.path).map_err(|error| {
            // TODO: Make the `ack!` macro more expressive and rewrite it.
            warn! {
                "failed to read symlink for '{path}': {cause}",
                path = request.path.display(),
                cause = error,
            }
        }).ok()
    } else {
        None
    };

    #[cfg(target_family = "unix")]
    let ext_attrs = if request.collect_ext_attrs {
        // TODO: Make the `ack!` macro more expressive and then simplify it.
        match crate::fs::unix::ext_attrs(&request.path) {
            Ok(ext_attrs) => ext_attrs.collect(),
            Err(error) => {
                warn! {
                    "failed to collect attributes for '{path}': {cause}",
                    path = request.path.display(),
                    cause = error,
                };
                vec!()
            },
        }
    } else {
        vec!()
    };

    #[cfg(target_os = "linux")]
    let flags_linux = crate::fs::linux::flags(&request.path).map_err(|error| {
        // TODO: Make the `ack!` macro more expressive and rewrite it.
        warn! {
            "failed to collect flags for '{path}': {cause}",
            path = request.path.display(),
            cause = error,
        }
    }).ok();

    let response = Response {
        path: request.path,
        metadata: metadata,
        symlink: symlink,
        #[cfg(target_family = "unix")]
        ext_attrs: ext_attrs,
        #[cfg(target_os = "linux")]
        flags_linux: flags_linux,
    };

    session.reply(response)?;
    Ok(())
}

impl super::Request for Request {

    type Proto = rrg_proto::GetFileStatRequest;

    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError> {
        use std::convert::TryInto as _;

        let path = proto.pathspec
            .ok_or(session::MissingFieldError::new("path spec"))?
            .try_into().map_err(session::ParseError::malformed)?;

        Ok(Request {
            path: path,
            follow_symlink: proto.follow_symlink.unwrap_or(false),
            collect_ext_attrs: proto.collect_ext_attrs.unwrap_or(false),
        })
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("StatEntry");

    type Proto = rrg_proto::StatEntry;

    fn into_proto(self) -> Self::Proto {
        use rrg_proto::convert::IntoLossy as _;

        rrg_proto::StatEntry {
            pathspec: Some(self.path.into()),
            #[cfg(target_family = "unix")]
            ext_attrs: self.ext_attrs.into_iter().map(Into::into).collect(),
            #[cfg(target_os = "linux")]
            st_flags_linux: self.flags_linux,
            ..self.metadata.into_lossy()
        }
    }
}

#[cfg(test)]
mod tests {
}
<|endoftext|>