<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::utils::{in_derive_expn, match_def_path};
use rustc::hir::intravisit as visit;
use rustc::hir::{self, ExprKind};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use syntax::{ast, source_map};

declare_lint!(
    UNROOTED_MUST_ROOT,
    Deny,
    "Warn and report usage of unrooted jsmanaged objects"
);

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptThread`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass;

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &LateContext, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::Adt(did, substs) => {
                if cx.tcx.has_attr(did.did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did.did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did.did, &["alloc", "rc", "Rc"]) {
                    // Rc<Promise> is okay
                    let inner = substs.type_at(0);
                    if let ty::Adt(did, _) = inner.sty {
                        if cx.tcx.has_attr(did.did, "allow_unrooted_in_rc") {
                            false
                        } else {
                            true
                        }
                    } else {
                        true
                    }
                } else if match_def_path(cx, did.did, &["core", "cell", "Ref"]) ||
                    match_def_path(cx, did.did, &["core", "cell", "RefMut"]) ||
                    match_def_path(cx, did.did, &["core", "slice", "Iter"]) ||
                    match_def_path(cx, did.did, &["core", "slice", "IterMut"]) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Entry"]) ||
                    match_def_path(
                        cx,
                        did.did,
                        &["std", "collections", "hash", "map", "OccupiedEntry"],
                    ) ||
                    match_def_path(
                        cx,
                        did.did,
                        &["std", "collections", "hash", "map", "VacantEntry"],
                    ) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Iter"]) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "set", "Iter"])
                {
                    // Structures which are semantically similar to an &ptr.
                    false
                } else if did.is_box() && in_new_function {
                    // box in new() is okay
                    false
                } else {
                    true
                }
            },
            ty::Ref(..) => false,    // don't recurse down &ptrs
            ty::RawPtr(..) => false, // don't recurse down *ptrs
            ty::FnDef(..) | ty::FnPtr(_) => false,
            _ => true,
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn name(&self) -> &'static str {
        "ServoUnrootedPass"
    }

    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnrootedPass {
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(
        &mut self,
        cx: &LateContext,
        def: &hir::VariantData,
        _n: ast::Name,
        _gen: &hir::Generics,
        id: ast::NodeId,
    ) {
        let item = match cx.tcx.hir().get(id) {
            hir::Node::Item(item) => item,
            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields() {
                let def_id = cx.tcx.hir().local_def_id(field.id);
                if is_unrooted_ty(cx, cx.tcx.type_of(def_id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }

    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant, _gen: &hir::Generics) {
        let ref map = cx.tcx.hir();
        if map
            .expect_item(map.get_parent(var.node.data.id()))
            .attrs
            .iter()
            .all(|a| !a.check_name("must_root"))
        {
            match var.node.data {
                hir::VariantData::Tuple(ref fields, _) => {
                    for ref field in fields {
                        let def_id = cx.tcx.hir().local_def_id(field.id);
                        if is_unrooted_ty(cx, cx.tcx.type_of(def_id), false) {
                            cx.span_lint(
                                UNROOTED_MUST_ROOT,
                                field.ty.span,
                                "Type must be rooted, use #[must_root] on \
                                 the enum definition to propagate",
                            )
                        }
                    }
                },
                _ => (), // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: visit::FnKind,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        span: source_map::Span,
        id: ast::NodeId,
    ) {
        let in_new_function = match kind {
            visit::FnKind::ItemFn(n, _, _, _, _) | visit::FnKind::Method(n, _, _, _) => {
                &*n.as_str() == "new" || n.as_str().starts_with("new_")
            },
            visit::FnKind::Closure(_) => return,
        };

        if !in_derive_expn(span) {
            let def_id = cx.tcx.hir().local_def_id(id);
            let sig = cx.tcx.type_of(def_id).fn_sig(cx.tcx);

            for (arg, ty) in decl.inputs.iter().zip(sig.inputs().skip_binder().iter()) {
                if is_unrooted_ty(cx, ty, false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, arg.span, "Type must be rooted")
                }
            }

            if !in_new_function {
                if is_unrooted_ty(cx, sig.output().skip_binder(), false) {
                    cx.span_lint(
                        UNROOTED_MUST_ROOT,
                        decl.output.span(),
                        "Type must be rooted",
                    )
                }
            }
        }

        let mut visitor = FnDefVisitor {
            cx: cx,
            in_new_function: in_new_function,
        };
        visit::walk_expr(&mut visitor, &body.value);
    }
}

struct FnDefVisitor<'a, 'b: 'a, 'tcx: 'a + 'b> {
    cx: &'a LateContext<'b, 'tcx>,
    in_new_function: bool,
}

impl<'a, 'b, 'tcx> visit::Visitor<'tcx> for FnDefVisitor<'a, 'b, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        let cx = self.cx;

        fn require_rooted(cx: &LateContext, in_new_function: bool, subexpr: &hir::Expr) {
            let ty = cx.tables.expr_ty(&subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(
                    UNROOTED_MUST_ROOT,
                    subexpr.span,
                    &format!("Expression of type {:?} must be rooted", ty),
                )
            }
        }

        match expr.node {
            // Trait casts from #[must_root] types are not allowed
            ExprKind::Cast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            // This catches assignments... the main point of this would be to catch mutable
            // references to `JS<T>`.
            // FIXME: Enable this? Triggers on certain kinds of uses of DomRefCell.
            // hir::ExprAssign(_, ref rhs) => require_rooted(cx, self.in_new_function, &*rhs),
            // This catches calls; basically, this enforces the constraint that only constructors
            // can call other constructors.
            // FIXME: Enable this? Currently triggers with constructs involving DomRefCell, and
            // constructs like Vec<JS<T>> and RootedVec<JS<T>>.
            // hir::ExprCall(..) if !self.in_new_function => {
            //     require_rooted(cx, self.in_new_function, expr);
            // }
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            },
        }

        visit::walk_expr(self, expr);
    }

    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
        let cx = self.cx;

        // We want to detect pattern bindings that move a value onto the stack.
        // When "default binding modes" https://github.com/rust-lang/rust/issues/42640
        // are implemented, the `Unannotated` case could cause false-positives.
        // These should be fixable by adding an explicit `ref`.
        match pat.node {
            hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, _) |
            hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, _, _) => {
                let ty = cx.tables.pat_ty(pat);
                if is_unrooted_ty(cx, ty, self.in_new_function) {
                    cx.span_lint(
                        UNROOTED_MUST_ROOT,
                        pat.span,
                        &format!("Expression of type {:?} must be rooted", ty),
                    )
                }
            },
            _ => {},
        }

        visit::walk_pat(self, pat);
    }

    fn visit_ty(&mut self, _: &'tcx hir::Ty) {}

    fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
        hir::intravisit::NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<commit_msg>Compat with rustc 1.34.0-nightly (f6fac4225 2019-02-03)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::utils::{in_derive_expn, match_def_path};
use rustc::hir::intravisit as visit;
use rustc::hir::{self, ExprKind};
use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use syntax::{ast, source_map};

declare_lint!(
    UNROOTED_MUST_ROOT,
    Deny,
    "Warn and report usage of unrooted jsmanaged objects"
);

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptThread`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass;

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &LateContext, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::Adt(did, substs) => {
                if cx.tcx.has_attr(did.did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did.did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did.did, &["alloc", "rc", "Rc"]) {
                    // Rc<Promise> is okay
                    let inner = substs.type_at(0);
                    if let ty::Adt(did, _) = inner.sty {
                        if cx.tcx.has_attr(did.did, "allow_unrooted_in_rc") {
                            false
                        } else {
                            true
                        }
                    } else {
                        true
                    }
                } else if match_def_path(cx, did.did, &["core", "cell", "Ref"]) ||
                    match_def_path(cx, did.did, &["core", "cell", "RefMut"]) ||
                    match_def_path(cx, did.did, &["core", "slice", "Iter"]) ||
                    match_def_path(cx, did.did, &["core", "slice", "IterMut"]) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Entry"]) ||
                    match_def_path(
                        cx,
                        did.did,
                        &["std", "collections", "hash", "map", "OccupiedEntry"],
                    ) ||
                    match_def_path(
                        cx,
                        did.did,
                        &["std", "collections", "hash", "map", "VacantEntry"],
                    ) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "map", "Iter"]) ||
                    match_def_path(cx, did.did, &["std", "collections", "hash", "set", "Iter"])
                {
                    // Structures which are semantically similar to an &ptr.
                    false
                } else if did.is_box() && in_new_function {
                    // box in new() is okay
                    false
                } else {
                    true
                }
            },
            ty::Ref(..) => false,    // don't recurse down &ptrs
            ty::RawPtr(..) => false, // don't recurse down *ptrs
            ty::FnDef(..) | ty::FnPtr(_) => false,
            _ => true,
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn name(&self) -> &'static str {
        "ServoUnrootedPass"
    }

    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnrootedPass {
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(
        &mut self,
        cx: &LateContext,
        def: &hir::VariantData,
        _n: ast::Name,
        _gen: &hir::Generics,
        id: ast::NodeId,
    ) {
        let item = match cx.tcx.hir().get(id) {
            hir::Node::Item(item) => item,
            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields() {
                let def_id = cx.tcx.hir().local_def_id(field.id);
                if is_unrooted_ty(cx, cx.tcx.type_of(def_id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }

    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant, _gen: &hir::Generics) {
        let ref map = cx.tcx.hir();
        if map
            .expect_item(map.get_parent(var.node.data.id()))
            .attrs
            .iter()
            .all(|a| !a.check_name("must_root"))
        {
            match var.node.data {
                hir::VariantData::Tuple(ref fields, ..) => {
                    for ref field in fields {
                        let def_id = cx.tcx.hir().local_def_id(field.id);
                        if is_unrooted_ty(cx, cx.tcx.type_of(def_id), false) {
                            cx.span_lint(
                                UNROOTED_MUST_ROOT,
                                field.ty.span,
                                "Type must be rooted, use #[must_root] on \
                                 the enum definition to propagate",
                            )
                        }
                    }
                },
                _ => (), // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: visit::FnKind,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        span: source_map::Span,
        id: ast::NodeId,
    ) {
        let in_new_function = match kind {
            visit::FnKind::ItemFn(n, _, _, _, _) | visit::FnKind::Method(n, _, _, _) => {
                &*n.as_str() == "new" || n.as_str().starts_with("new_")
            },
            visit::FnKind::Closure(_) => return,
        };

        if !in_derive_expn(span) {
            let def_id = cx.tcx.hir().local_def_id(id);
            let sig = cx.tcx.type_of(def_id).fn_sig(cx.tcx);

            for (arg, ty) in decl.inputs.iter().zip(sig.inputs().skip_binder().iter()) {
                if is_unrooted_ty(cx, ty, false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, arg.span, "Type must be rooted")
                }
            }

            if !in_new_function {
                if is_unrooted_ty(cx, sig.output().skip_binder(), false) {
                    cx.span_lint(
                        UNROOTED_MUST_ROOT,
                        decl.output.span(),
                        "Type must be rooted",
                    )
                }
            }
        }

        let mut visitor = FnDefVisitor {
            cx: cx,
            in_new_function: in_new_function,
        };
        visit::walk_expr(&mut visitor, &body.value);
    }
}

struct FnDefVisitor<'a, 'b: 'a, 'tcx: 'a + 'b> {
    cx: &'a LateContext<'b, 'tcx>,
    in_new_function: bool,
}

impl<'a, 'b, 'tcx> visit::Visitor<'tcx> for FnDefVisitor<'a, 'b, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        let cx = self.cx;

        fn require_rooted(cx: &LateContext, in_new_function: bool, subexpr: &hir::Expr) {
            let ty = cx.tables.expr_ty(&subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(
                    UNROOTED_MUST_ROOT,
                    subexpr.span,
                    &format!("Expression of type {:?} must be rooted", ty),
                )
            }
        }

        match expr.node {
            // Trait casts from #[must_root] types are not allowed
            ExprKind::Cast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            // This catches assignments... the main point of this would be to catch mutable
            // references to `JS<T>`.
            // FIXME: Enable this? Triggers on certain kinds of uses of DomRefCell.
            // hir::ExprAssign(_, ref rhs) => require_rooted(cx, self.in_new_function, &*rhs),
            // This catches calls; basically, this enforces the constraint that only constructors
            // can call other constructors.
            // FIXME: Enable this? Currently triggers with constructs involving DomRefCell, and
            // constructs like Vec<JS<T>> and RootedVec<JS<T>>.
            // hir::ExprCall(..) if !self.in_new_function => {
            //     require_rooted(cx, self.in_new_function, expr);
            // }
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            },
        }

        visit::walk_expr(self, expr);
    }

    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
        let cx = self.cx;

        // We want to detect pattern bindings that move a value onto the stack.
        // When "default binding modes" https://github.com/rust-lang/rust/issues/42640
        // are implemented, the `Unannotated` case could cause false-positives.
        // These should be fixable by adding an explicit `ref`.
        match pat.node {
            hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, ..) |
            hir::PatKind::Binding(hir::BindingAnnotation::Mutable, ..) => {
                let ty = cx.tables.pat_ty(pat);
                if is_unrooted_ty(cx, ty, self.in_new_function) {
                    cx.span_lint(
                        UNROOTED_MUST_ROOT,
                        pat.span,
                        &format!("Expression of type {:?} must be rooted", ty),
                    )
                }
            },
            _ => {},
        }

        visit::walk_pat(self, pat);
    }

    fn visit_ty(&mut self, _: &'tcx hir::Ty) {}

    fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'tcx> {
        hir::intravisit::NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
    }
}
<|endoftext|>


<commit_before>pub mod specifiers_iterator;

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                // Might fail if `local_format` contains a null byte. TODO decide if this is a good
                // error-handling strategy, or we should report back to user, or panic, or what
                if let Ok(local_format_cstring) = std::ffi::CString::new(local_format) {
                    let buf_size = 1024usize;
                    let buffer: std::vec::Vec<u8> = std::vec::Vec::with_capacity(buf_size);
                    if let Ok(buffer) = std::ffi::CString::new(buffer) {
                        unsafe {
                            let buffer_ptr = buffer.into_raw();
                            // TODO: check how many bytes were written
                            let bytes_written = libc::snprintf(
                                buffer_ptr,
                                buf_size as libc::size_t,
                                local_format_cstring.as_ptr() as *const libc::c_char,
                                $arg);
                            let buffer = std::ffi::CString::from_raw(buffer_ptr);
                            let _bytes_written = bytes_written as usize;
                            if let Ok(formatted) = buffer.into_string() {
                                result.push_str(&formatted);
                            }
                        }
                    }
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }
}
<commit_msg>Port most numeric tests for strprintf to Rust<commit_after>pub mod specifiers_iterator;

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                // Might fail if `local_format` contains a null byte. TODO decide if this is a good
                // error-handling strategy, or we should report back to user, or panic, or what
                if let Ok(local_format_cstring) = std::ffi::CString::new(local_format) {
                    let buf_size = 1024usize;
                    let buffer: std::vec::Vec<u8> = std::vec::Vec::with_capacity(buf_size);
                    if let Ok(buffer) = std::ffi::CString::new(buffer) {
                        unsafe {
                            let buffer_ptr = buffer.into_raw();
                            // TODO: check how many bytes were written
                            let bytes_written = libc::snprintf(
                                buffer_ptr,
                                buf_size as libc::size_t,
                                local_format_cstring.as_ptr() as *const libc::c_char,
                                $arg);
                            let buffer = std::ffi::CString::from_raw(buffer_ptr);
                            let _bytes_written = bytes_written as usize;
                            if let Ok(formatted) = buffer.into_string() {
                                result.push_str(&formatted);
                            }
                        }
                    }
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_int_x86_64() {
        assert_eq!(fmt!("%i", 42i32), "42");

        let int_min = std::i32::MIN;
        assert_eq!(int_min, -2147483648i32);
        assert_eq!(fmt!("%i", int_min), "-2147483648");

        let int_max = std::i32::MAX;
        assert_eq!(int_max, 2147483647i32);
        assert_eq!(fmt!("%i", int_max), "2147483647");
    }

    #[test]
    fn formats_unsigned_int_x86_64() {
        assert_eq!(fmt!("%u", 42u32), "42");

        assert_eq!(fmt!("%u", 0u32), "0");

        let uint_max = std::u32::MAX;
        assert_eq!(uint_max, 4294967295u32);
        assert_eq!(fmt!("%u", uint_max), "4294967295");
    }

    #[test]
    fn formats_long_int_x86_64() {
        assert_eq!(fmt!("%li", 42i64), "42");

        let int_min = std::i32::MIN as i64;
        let long_min = std::i64::MIN;
        assert!(long_min < int_min);
        assert_eq!(int_min, -2147483648);
        assert_eq!(fmt!("%li", int_min - 1), "-2147483649");

        let int_max = std::i32::MAX as i64;
        let long_max = std::i64::MAX;
        assert!(long_max > int_max);
        assert_eq!(int_max, 2147483647);
        assert_eq!(fmt!("%li", int_max + 1), "2147483648");
    }

    #[test]
    fn formats_long_unsigned_int_x86_64() {
        assert_eq!(fmt!("%lu", 42u64), "42");

        assert_eq!(fmt!("%lu", 0u64), "0");

        let ulong_max = std::u64::MAX;
        assert_eq!(ulong_max, 18446744073709551615u64);
        assert_eq!(fmt!("%lu", ulong_max), "18446744073709551615");
    }

    #[test]
    fn formats_long_long_int_x86_64() {
        assert_eq!(fmt!("%lli", 42i64), "42");

        // This is one bigger than actual std::numeric_limits<long long int>::min()
        // on x86_64. The actual value can't be written in C++ as a literal because both GCC 8 and
        // Clang complain about it being too small to be represented with long long int.
        let input = -9223372036854775807i64;
        let llong_min = std::i64::MIN;
        assert!(llong_min <= input);
        assert_eq!(fmt!("%lli", input), "-9223372036854775807");

        let llong_max = std::i64::MAX;
        assert_eq!(llong_max, 9223372036854775807i64);
        assert_eq!(fmt!("%lli", llong_max), "9223372036854775807");
    }

    #[test]
    fn formats_unsigned_long_long_int_x86_64() {
        assert_eq!(fmt!("%llu", 42u64), "42");

        assert_eq!(fmt!("%llu", 0u64), "0");

        let ullong_max = std::u64::MAX;
        assert_eq!(ullong_max, 18446744073709551615u64);
        assert_eq!(fmt!("%llu", ullong_max), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<|endoftext|>


<commit_before>pub mod specifiers_iterator;

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                // Might fail if `local_format` contains a null byte. TODO decide if this is a good
                // error-handling strategy, or we should report back to user, or panic, or what
                if let Ok(local_format_cstring) = std::ffi::CString::new(local_format) {
                    let buf_size = 1024usize;
                    let buffer: std::vec::Vec<u8> = std::vec::Vec::with_capacity(buf_size);
                    if let Ok(buffer) = std::ffi::CString::new(buffer) {
                        unsafe {
                            let buffer_ptr = buffer.into_raw();
                            // TODO: check how many bytes were written
                            let bytes_written = libc::snprintf(
                                buffer_ptr,
                                buf_size as libc::size_t,
                                local_format_cstring.as_ptr() as *const libc::c_char,
                                $arg);
                            let buffer = std::ffi::CString::from_raw(buffer_ptr);
                            let _bytes_written = bytes_written as usize;
                            if let Ok(formatted) = buffer.into_string() {
                                result.push_str(&formatted);
                            }
                        }
                    }
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_int_x86_64() {
        assert_eq!(fmt!("%i", 42i32), "42");

        let int_min = std::i32::MIN;
        assert_eq!(int_min, -2147483648i32);
        assert_eq!(fmt!("%i", int_min), "-2147483648");

        let int_max = std::i32::MAX;
        assert_eq!(int_max, 2147483647i32);
        assert_eq!(fmt!("%i", int_max), "2147483647");
    }

    #[test]
    fn formats_unsigned_int_x86_64() {
        assert_eq!(fmt!("%u", 42u32), "42");

        assert_eq!(fmt!("%u", 0u32), "0");

        let uint_max = std::u32::MAX;
        assert_eq!(uint_max, 4294967295u32);
        assert_eq!(fmt!("%u", uint_max), "4294967295");
    }

    #[test]
    fn formats_long_int_x86_64() {
        assert_eq!(fmt!("%li", 42i64), "42");

        let int_min = std::i32::MIN as i64;
        let long_min = std::i64::MIN;
        assert!(long_min < int_min);
        assert_eq!(int_min, -2147483648);
        assert_eq!(fmt!("%li", int_min - 1), "-2147483649");

        let int_max = std::i32::MAX as i64;
        let long_max = std::i64::MAX;
        assert!(long_max > int_max);
        assert_eq!(int_max, 2147483647);
        assert_eq!(fmt!("%li", int_max + 1), "2147483648");
    }

    #[test]
    fn formats_long_unsigned_int_x86_64() {
        assert_eq!(fmt!("%lu", 42u64), "42");

        assert_eq!(fmt!("%lu", 0u64), "0");

        let ulong_max = std::u64::MAX;
        assert_eq!(ulong_max, 18446744073709551615u64);
        assert_eq!(fmt!("%lu", ulong_max), "18446744073709551615");
    }

    #[test]
    fn formats_long_long_int_x86_64() {
        assert_eq!(fmt!("%lli", 42i64), "42");

        // This is one bigger than actual std::numeric_limits<long long int>::min()
        // on x86_64. The actual value can't be written in C++ as a literal because both GCC 8 and
        // Clang complain about it being too small to be represented with long long int.
        let input = -9223372036854775807i64;
        let llong_min = std::i64::MIN;
        assert!(llong_min <= input);
        assert_eq!(fmt!("%lli", input), "-9223372036854775807");

        let llong_max = std::i64::MAX;
        assert_eq!(llong_max, 9223372036854775807i64);
        assert_eq!(fmt!("%lli", llong_max), "9223372036854775807");
    }

    #[test]
    fn formats_unsigned_long_long_int_x86_64() {
        assert_eq!(fmt!("%llu", 42u64), "42");

        assert_eq!(fmt!("%llu", 0u64), "0");

        let ullong_max = std::u64::MAX;
        assert_eq!(ullong_max, 18446744073709551615u64);
        assert_eq!(fmt!("%llu", ullong_max), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<commit_msg>Tidy up numeric tests for fmt!<commit_after>pub mod specifiers_iterator;

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                // Might fail if `local_format` contains a null byte. TODO decide if this is a good
                // error-handling strategy, or we should report back to user, or panic, or what
                if let Ok(local_format_cstring) = std::ffi::CString::new(local_format) {
                    let buf_size = 1024usize;
                    let buffer: std::vec::Vec<u8> = std::vec::Vec::with_capacity(buf_size);
                    if let Ok(buffer) = std::ffi::CString::new(buffer) {
                        unsafe {
                            let buffer_ptr = buffer.into_raw();
                            // TODO: check how many bytes were written
                            let bytes_written = libc::snprintf(
                                buffer_ptr,
                                buf_size as libc::size_t,
                                local_format_cstring.as_ptr() as *const libc::c_char,
                                $arg);
                            let buffer = std::ffi::CString::from_raw(buffer_ptr);
                            let _bytes_written = bytes_written as usize;
                            if let Ok(formatted) = buffer.into_string() {
                                result.push_str(&formatted);
                            }
                        }
                    }
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");
    }

    /*
    XXX: can't be easily ported since Rust doesn't let us pass f32 to a variadic function like
    snprintf.
    TEST_CASE("strprintf::fmt() formats float", "[strprintf]")
    {
            const auto x = 42.0f;
            REQUIRE(strprintf::fmt("%f", x) == "42.000000");
            REQUIRE(strprintf::fmt("%.3f", x) == "42.000");

            const auto y = 42e3f;
            REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04");
            REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04");
    }

    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

pub enum Error {
    BadOffset(u64, &'static str),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadOffset(offset, ops) => write!(f, "Bad {} offset: {}", ops, offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_read(&mut self, offset: u64) -> Result<u32> {
        let val;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            val = u32::from(PL031_ID[index]);
        } else {
            val = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                off => {
                    return Err(Error::BadOffset(off, "read"));
                }
            };
        }
        Ok(val)
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            off => {
                return Err(Error::BadOffset(off, "write"));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        if data.len() <= 4 {
            match self.handle_read(offset) {
                Ok(val) => byte_order::write_le_u32(data, val),
                Err(e) => {
                    warn!("Failed to read from the RTC PL031 device: {}", e);
                    METRICS.rtc.error_count.inc();
                }
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() <= 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to the RTC PL031 device: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the DR register. Since this is a RO register, the write
        // function should fail.
        byte_order::write_le_u32(&mut data, 0);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCDR, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCDR, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 0);

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the RIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCRIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCRIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the MIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCMIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCMIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }
}
<commit_msg>rtc: fix noncompliant checks<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

pub enum Error {
    BadOffset(u64, &'static str),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadOffset(offset, ops) => write!(f, "Bad {} offset: {}", ops, offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_read(&mut self, offset: u64) -> Result<u32> {
        let val;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            val = u32::from(PL031_ID[index]);
        } else {
            val = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                off => {
                    return Err(Error::BadOffset(off, "read"));
                }
            };
        }
        Ok(val)
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            off => {
                return Err(Error::BadOffset(off, "write"));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        if data.len() == 4 {
            match self.handle_read(offset) {
                Ok(val) => byte_order::write_le_u32(data, val),
                Err(e) => {
                    warn!("Failed to read from the RTC: {}", e);
                    METRICS.rtc.error_count.inc();
                }
            }
        } else {
            warn!(
                "Found invalid data length while trying to read from the RTC: {}",
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() == 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to the RTC: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!(
                "Found invalid data length while trying to write to the RTC: {}",
                data.len()
            );
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the DR register. Since this is a RO register, the write
        // function should fail.
        byte_order::write_le_u32(&mut data, 0);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCDR, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCDR, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 0);

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the RIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCRIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCRIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the MIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCMIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCMIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }

    #[test]
    fn test_rtc_invalid_buf_len() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [1; 2];

        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCLR, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCLR, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_read - err_cnt_after_write, 1);
    }
}
<|endoftext|>


<commit_before>#![feature(convert)]
extern crate rebar;

use std::io;
use std::io::Write;
//use std::io::Read;
use std::string::String;

pub fn main() {
    let mut sin = io::stdin();
    let mut fred = String::new();
    fred.push_str("Hello there");
    let mut sout = io::stdout();
    print!("{}", fred);
    match sout.flush() {
        Ok(..) => {},
        Err(..) => {},
    };
    match sin.read_line(&mut fred) {
        Ok(..) => {},
        Err(..) => {},
    };
    rebar::refresh_screen(fred.as_ref());
}
<commit_msg>updated to 15/04/11 nightly<commit_after>extern crate rebar;

use std::io;
use std::io::Write;
//use std::io::Read;
use std::string::String;

pub fn main() {
    let mut sin = io::stdin();
    let mut fred = String::new();
    fred.push_str("Hello there");
    let mut sout = io::stdout();
    print!("{}", fred);
    match sout.flush() {
        Ok(..) => {},
        Err(..) => {},
    };
    match sin.read_line(&mut fred) {
        Ok(..) => {},
        Err(..) => {},
    };
    rebar::refresh_screen(fred.as_ref());
}
<|endoftext|>


<commit_before>use data::*;
use util::*;
use secstr::SecStr;
use rusterpassword::*;
use rustc_serialize::base64::{ToBase64, STANDARD};
use sodiumoxide::crypto::sign::ed25519;
use byteorder::{BigEndian, WriteBytesExt};
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use unix_socket::UnixStream;
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::env;
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::io::{Read, Write};
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::net::Shutdown;

pub enum Output {
    PrivateText(SecStr),
    OpenText(String),
    PrivateBinary(SecStr),
    Ed25519Keypair(Ed25519Usage, ed25519::PublicKey, ed25519::SecretKey),
}

fn pick_tpl(tpl: &PasswordTemplate) -> &'static [&'static str] {
    match *tpl {
       PasswordTemplate::Maximum  => TEMPLATES_MAXIMUM,
       PasswordTemplate::Long     => TEMPLATES_LONG,
       PasswordTemplate::Medium   => TEMPLATES_MEDIUM,
       PasswordTemplate::Short    => TEMPLATES_SHORT,
       PasswordTemplate::Basic    => TEMPLATES_BASIC,
       PasswordTemplate::Pin      => TEMPLATES_PIN,
    }
}

pub fn process_output(entry_name: &str, master_key: &SecStr, field: &Field) -> Result<Output> {
    match *field {
        Field::Derived { counter, ref site_name, ref usage } => {
            let site_seed = try!(gen_site_seed(master_key, &site_name.clone().unwrap_or(entry_name.to_string()), counter)
                                 .map_err(|_| Error::SeedGenerationError));
            match *usage {
                DerivedUsage::Password(ref tpl) =>
                    Ok(Output::PrivateText(gen_site_password(&site_seed, pick_tpl(tpl)))),
                DerivedUsage::Ed25519Key(ref keyusage) => {
                    let edseed = try!(ed25519::Seed::from_slice(site_seed.unsecure()).ok_or(Error::WrongDerivedKeyLength));
                    let (pubkey, seckey) = ed25519::keypair_from_seed(&edseed);
                    Ok(Output::Ed25519Keypair(*keyusage, pubkey, seckey))
                },
                DerivedUsage::RawKey =>
                    Ok(Output::PrivateBinary(site_seed)),
            }
        },
        Field::Stored { ref data, ref usage } =>
            match *usage {
                StoredUsage::Password =>
                    Ok(Output::PrivateText(SecStr::new(data.unsecure().to_vec()))),
                StoredUsage::Text =>
                    Ok(Output::OpenText(try!(String::from_utf8(data.unsecure().to_vec()))))
            }
    }
}

pub fn ssh_public_key_output(keypair: &Output, comment: &str) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::SSH, ed25519::PublicKey(pubkey_bytes), _) = keypair {
        let mut raw = vec![];
        try!(raw.write_u32::<BigEndian>(11));
        raw.extend(b"ssh-ed25519");
        try!(raw.write_u32::<BigEndian>(ed25519::PUBLICKEYBYTES as u32));
        raw.extend(&pubkey_bytes);
        Ok("ssh-ed25519 ".to_string() + &raw.to_base64(STANDARD) + " " + comment)
    } else { Err(Error::InappropriateFormat) }
}

pub fn ssh_private_key_agent_message(keypair: &Output, comment: &str) -> Result<SecStr> {
    if let &Output::Ed25519Keypair(Ed25519Usage::SSH, ed25519::PublicKey(pubkey_bytes), ed25519::SecretKey(seckey_bytes)) = keypair {
        let mut msg = vec![17u8];
        try!(msg.write_u32::<BigEndian>(11));
        msg.extend(b"ssh-ed25519");
        try!(msg.write_u32::<BigEndian>(ed25519::PUBLICKEYBYTES as u32));
        msg.extend(&pubkey_bytes);
        try!(msg.write_u32::<BigEndian>(ed25519::SECRETKEYBYTES as u32));
        msg.extend(seckey_bytes.iter()); // LOL, there's no iterator for &[u8, 64] because 64 is a lot
        try!(msg.write_u32::<BigEndian>(comment.as_bytes().len() as u32));
        msg.extend(comment.as_bytes());
        Ok(SecStr::new(msg))
    } else { Err(Error::InappropriateFormat) }
}

#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))]
pub fn ssh_agent_send_message(msg: SecStr) -> Result<()> {
    if let Some(sock_path) = env::var_os("SSH_AUTH_SOCK") {
        let mut stream = try!(UnixStream::connect(sock_path));
        try!(stream.write_u32::<BigEndian>(msg.unsecure().len() as u32));
        try!(stream.write(msg.unsecure()));
        let mut response = vec![0; 5];
        try!(stream.read(&mut response));
        try!(stream.shutdown(Shutdown::Both));
        Ok(())
    } else { Err(Error::SSHAgentSocketNotFound) }
}

#[cfg(any(not(unix), target_os = "android", target_os = "ios"))]
pub fn ssh_agent_send_message(_: SecStr) -> Result<()> {
    Err(Error::NotAvailableOnPlatform)
}

pub fn signify_keynum(pubkey_bytes: &[u8]) -> Vec<u8> {
    blake2b(pubkey_bytes, b"freepass.signify", 8)
}

pub fn signify_public_key_output(keypair: &Output, comment: &str) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::Signify, ed25519::PublicKey(pubkey_bytes), _) = keypair {
        let mut raw = vec![];
        raw.extend(b"Ed");
        raw.extend(&signify_keynum(&pubkey_bytes));
        raw.extend(&pubkey_bytes);
        Ok(format!("untrusted comment: {}\n{}\n", comment, &raw.to_base64(STANDARD)))
    } else { Err(Error::InappropriateFormat) }
}

pub fn signify_sign(keypair: &Output, comment: &str, data: &[u8]) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::Signify, ed25519::PublicKey(pubkey_bytes), ref seckey) = keypair {
        let ed25519::Signature(sig_bytes) = ed25519::sign_detached(data, &seckey);
        let mut raw = vec![];
        raw.extend(b"Ed");
        raw.extend(&signify_keynum(&pubkey_bytes));
        raw.extend(sig_bytes.iter());
        Ok(format!("untrusted comment: {}\n{}\n", comment, &raw.to_base64(STANDARD)))
    } else { Err(Error::InappropriateFormat) }
}

#[cfg(test)]
mod tests {
    use super::*;
    use data::*;
    use sodiumoxide::crypto::sign::ed25519;

    fn keypair(usage: Ed25519Usage) -> Output {
        let (pubkey, seckey) = ed25519::keypair_from_seed(&ed25519::Seed::from_slice(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap());
        Output::Ed25519Keypair(usage, pubkey, seckey)
    }

    #[test]
    fn test_ssh_public_key_output() {
        assert_eq!(ssh_public_key_output(&keypair(Ed25519Usage::SSH), "myComment").unwrap(), "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8Go+MpFxTk81bBnJsVzRlR7G5mYqp3vgdUfyiTgzQd myComment");
    }

    #[test]
    fn test_ssh_private_key_agent_message() {
        let msg = ssh_private_key_agent_message(&keypair(Ed25519Usage::SSH), "myComment").unwrap();
        assert_eq!(Vec::from(msg.unsecure()), vec![17, 0, 0, 0, 11, 115, 115, 104, 45, 101, 100, 50, 53, 53, 49, 57, 0, 0, 0, 32, 175, 6, 163, 227, 41, 23, 20, 228, 243, 86, 193, 156, 155, 21, 205, 25, 81, 236, 110, 102, 98, 170, 119, 190, 7, 84, 127, 40, 147, 131, 52, 29, 0, 0, 0, 64, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 175, 6, 163, 227, 41, 23, 20, 228, 243, 86, 193, 156, 155, 21, 205, 25, 81, 236, 110, 102, 98, 170, 119, 190, 7, 84, 127, 40, 147, 131, 52, 29, 0, 0, 0, 9, 109, 121, 67, 111, 109, 109, 101, 110, 116]);
    }

    #[test]
    fn test_signify_public_key_output() {
        assert_eq!(signify_public_key_output(&keypair(Ed25519Usage::Signify), "myComment").unwrap(), "untrusted comment: myComment\nRWTvU+MamKpB6a8Go+MpFxTk81bBnJsVzRlR7G5mYqp3vgdUfyiTgzQd");
    }

    #[test]
    fn test_signify_sign() {
        assert_eq!(signify_sign(&keypair(Ed25519Usage::Signify), "myComment", b"hello world\n").unwrap(), "untrusted comment: myComment\nRWTvU+MamKpB6auI/gtU4NWNehjKQjhXsPp15mrjGTC1TfZ4SHESosQOOFkOpd+UPSUsoMac2pA5NEi+u5oHwLkKV9UeLm69JAI=");
    }
}
<commit_msg>add missing newlines in signify output tests<commit_after>use data::*;
use util::*;
use secstr::SecStr;
use rusterpassword::*;
use rustc_serialize::base64::{ToBase64, STANDARD};
use sodiumoxide::crypto::sign::ed25519;
use byteorder::{BigEndian, WriteBytesExt};
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use unix_socket::UnixStream;
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::env;
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::io::{Read, Write};
#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))] use std::net::Shutdown;

pub enum Output {
    PrivateText(SecStr),
    OpenText(String),
    PrivateBinary(SecStr),
    Ed25519Keypair(Ed25519Usage, ed25519::PublicKey, ed25519::SecretKey),
}

fn pick_tpl(tpl: &PasswordTemplate) -> &'static [&'static str] {
    match *tpl {
       PasswordTemplate::Maximum  => TEMPLATES_MAXIMUM,
       PasswordTemplate::Long     => TEMPLATES_LONG,
       PasswordTemplate::Medium   => TEMPLATES_MEDIUM,
       PasswordTemplate::Short    => TEMPLATES_SHORT,
       PasswordTemplate::Basic    => TEMPLATES_BASIC,
       PasswordTemplate::Pin      => TEMPLATES_PIN,
    }
}

pub fn process_output(entry_name: &str, master_key: &SecStr, field: &Field) -> Result<Output> {
    match *field {
        Field::Derived { counter, ref site_name, ref usage } => {
            let site_seed = try!(gen_site_seed(master_key, &site_name.clone().unwrap_or(entry_name.to_string()), counter)
                                 .map_err(|_| Error::SeedGenerationError));
            match *usage {
                DerivedUsage::Password(ref tpl) =>
                    Ok(Output::PrivateText(gen_site_password(&site_seed, pick_tpl(tpl)))),
                DerivedUsage::Ed25519Key(ref keyusage) => {
                    let edseed = try!(ed25519::Seed::from_slice(site_seed.unsecure()).ok_or(Error::WrongDerivedKeyLength));
                    let (pubkey, seckey) = ed25519::keypair_from_seed(&edseed);
                    Ok(Output::Ed25519Keypair(*keyusage, pubkey, seckey))
                },
                DerivedUsage::RawKey =>
                    Ok(Output::PrivateBinary(site_seed)),
            }
        },
        Field::Stored { ref data, ref usage } =>
            match *usage {
                StoredUsage::Password =>
                    Ok(Output::PrivateText(SecStr::new(data.unsecure().to_vec()))),
                StoredUsage::Text =>
                    Ok(Output::OpenText(try!(String::from_utf8(data.unsecure().to_vec()))))
            }
    }
}

pub fn ssh_public_key_output(keypair: &Output, comment: &str) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::SSH, ed25519::PublicKey(pubkey_bytes), _) = keypair {
        let mut raw = vec![];
        try!(raw.write_u32::<BigEndian>(11));
        raw.extend(b"ssh-ed25519");
        try!(raw.write_u32::<BigEndian>(ed25519::PUBLICKEYBYTES as u32));
        raw.extend(&pubkey_bytes);
        Ok("ssh-ed25519 ".to_string() + &raw.to_base64(STANDARD) + " " + comment)
    } else { Err(Error::InappropriateFormat) }
}

pub fn ssh_private_key_agent_message(keypair: &Output, comment: &str) -> Result<SecStr> {
    if let &Output::Ed25519Keypair(Ed25519Usage::SSH, ed25519::PublicKey(pubkey_bytes), ed25519::SecretKey(seckey_bytes)) = keypair {
        let mut msg = vec![17u8];
        try!(msg.write_u32::<BigEndian>(11));
        msg.extend(b"ssh-ed25519");
        try!(msg.write_u32::<BigEndian>(ed25519::PUBLICKEYBYTES as u32));
        msg.extend(&pubkey_bytes);
        try!(msg.write_u32::<BigEndian>(ed25519::SECRETKEYBYTES as u32));
        msg.extend(seckey_bytes.iter()); // LOL, there's no iterator for &[u8, 64] because 64 is a lot
        try!(msg.write_u32::<BigEndian>(comment.as_bytes().len() as u32));
        msg.extend(comment.as_bytes());
        Ok(SecStr::new(msg))
    } else { Err(Error::InappropriateFormat) }
}

#[cfg(all(unix, not(target_os = "android"), not(target_os = "ios")))]
pub fn ssh_agent_send_message(msg: SecStr) -> Result<()> {
    if let Some(sock_path) = env::var_os("SSH_AUTH_SOCK") {
        let mut stream = try!(UnixStream::connect(sock_path));
        try!(stream.write_u32::<BigEndian>(msg.unsecure().len() as u32));
        try!(stream.write(msg.unsecure()));
        let mut response = vec![0; 5];
        try!(stream.read(&mut response));
        try!(stream.shutdown(Shutdown::Both));
        Ok(())
    } else { Err(Error::SSHAgentSocketNotFound) }
}

#[cfg(any(not(unix), target_os = "android", target_os = "ios"))]
pub fn ssh_agent_send_message(_: SecStr) -> Result<()> {
    Err(Error::NotAvailableOnPlatform)
}

pub fn signify_keynum(pubkey_bytes: &[u8]) -> Vec<u8> {
    blake2b(pubkey_bytes, b"freepass.signify", 8)
}

pub fn signify_public_key_output(keypair: &Output, comment: &str) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::Signify, ed25519::PublicKey(pubkey_bytes), _) = keypair {
        let mut raw = vec![];
        raw.extend(b"Ed");
        raw.extend(&signify_keynum(&pubkey_bytes));
        raw.extend(&pubkey_bytes);
        Ok(format!("untrusted comment: {}\n{}\n", comment, &raw.to_base64(STANDARD)))
    } else { Err(Error::InappropriateFormat) }
}

pub fn signify_sign(keypair: &Output, comment: &str, data: &[u8]) -> Result<String> {
    if let &Output::Ed25519Keypair(Ed25519Usage::Signify, ed25519::PublicKey(pubkey_bytes), ref seckey) = keypair {
        let ed25519::Signature(sig_bytes) = ed25519::sign_detached(data, &seckey);
        let mut raw = vec![];
        raw.extend(b"Ed");
        raw.extend(&signify_keynum(&pubkey_bytes));
        raw.extend(sig_bytes.iter());
        Ok(format!("untrusted comment: {}\n{}\n", comment, &raw.to_base64(STANDARD)))
    } else { Err(Error::InappropriateFormat) }
}

#[cfg(test)]
mod tests {
    use super::*;
    use data::*;
    use sodiumoxide::crypto::sign::ed25519;

    fn keypair(usage: Ed25519Usage) -> Output {
        let (pubkey, seckey) = ed25519::keypair_from_seed(&ed25519::Seed::from_slice(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap());
        Output::Ed25519Keypair(usage, pubkey, seckey)
    }

    #[test]
    fn test_ssh_public_key_output() {
        assert_eq!(ssh_public_key_output(&keypair(Ed25519Usage::SSH), "myComment").unwrap(), "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8Go+MpFxTk81bBnJsVzRlR7G5mYqp3vgdUfyiTgzQd myComment");
    }

    #[test]
    fn test_ssh_private_key_agent_message() {
        let msg = ssh_private_key_agent_message(&keypair(Ed25519Usage::SSH), "myComment").unwrap();
        assert_eq!(Vec::from(msg.unsecure()), vec![17, 0, 0, 0, 11, 115, 115, 104, 45, 101, 100, 50, 53, 53, 49, 57, 0, 0, 0, 32, 175, 6, 163, 227, 41, 23, 20, 228, 243, 86, 193, 156, 155, 21, 205, 25, 81, 236, 110, 102, 98, 170, 119, 190, 7, 84, 127, 40, 147, 131, 52, 29, 0, 0, 0, 64, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 175, 6, 163, 227, 41, 23, 20, 228, 243, 86, 193, 156, 155, 21, 205, 25, 81, 236, 110, 102, 98, 170, 119, 190, 7, 84, 127, 40, 147, 131, 52, 29, 0, 0, 0, 9, 109, 121, 67, 111, 109, 109, 101, 110, 116]);
    }

    #[test]
    fn test_signify_public_key_output() {
        assert_eq!(signify_public_key_output(&keypair(Ed25519Usage::Signify), "myComment").unwrap(), "untrusted comment: myComment\nRWTvU+MamKpB6a8Go+MpFxTk81bBnJsVzRlR7G5mYqp3vgdUfyiTgzQd\n");
    }

    #[test]
    fn test_signify_sign() {
        assert_eq!(signify_sign(&keypair(Ed25519Usage::Signify), "myComment", b"hello world\n").unwrap(), "untrusted comment: myComment\nRWTvU+MamKpB6auI/gtU4NWNehjKQjhXsPp15mrjGTC1TfZ4SHESosQOOFkOpd+UPSUsoMac2pA5NEi+u5oHwLkKV9UeLm69JAI=\n");
    }
}
<|endoftext|>


<commit_before>#[derive(Copy, Clone)]
pub struct SubscribeError {
    pub driver_number: usize,
    pub subscribe_number: usize,
    pub return_code: isize,
}

#[derive(Copy, Clone)]
pub struct CommandError {
    pub driver_number: usize,
    pub command_number: usize,
    pub arg1: usize,
    pub arg2: usize,
    pub return_code: isize,
}

#[derive(Copy, Clone)]
pub struct AllowError {
    pub driver_number: usize,
    pub allow_number: usize,
    pub return_code: isize,
}

pub const SUCCESS: isize = 0;
pub const FAIL: isize = -1;
pub const EBUSY: isize = -2;
pub const EALREADY: isize = -3;
pub const EOFF: isize = -4;
pub const ERESERVE: isize = -5;
pub const EINVAL: isize = -6;
pub const ESIZE: isize = -7;
pub const ECANCEL: isize = -8;
pub const ENOMEM: isize = -9;
pub const ENOSUPPORT: isize = -10;
pub const ENODEVICE: isize = -11;
pub const EUNINSTALLED: isize = -12;
pub const ENOACK: isize = -13;

<commit_msg>Remove extra newline<commit_after>#[derive(Copy, Clone)]
pub struct SubscribeError {
    pub driver_number: usize,
    pub subscribe_number: usize,
    pub return_code: isize,
}

#[derive(Copy, Clone)]
pub struct CommandError {
    pub driver_number: usize,
    pub command_number: usize,
    pub arg1: usize,
    pub arg2: usize,
    pub return_code: isize,
}

#[derive(Copy, Clone)]
pub struct AllowError {
    pub driver_number: usize,
    pub allow_number: usize,
    pub return_code: isize,
}

pub const SUCCESS: isize = 0;
pub const FAIL: isize = -1;
pub const EBUSY: isize = -2;
pub const EALREADY: isize = -3;
pub const EOFF: isize = -4;
pub const ERESERVE: isize = -5;
pub const EINVAL: isize = -6;
pub const ESIZE: isize = -7;
pub const ECANCEL: isize = -8;
pub const ENOMEM: isize = -9;
pub const ENOSUPPORT: isize = -10;
pub const ENODEVICE: isize = -11;
pub const EUNINSTALLED: isize = -12;
pub const ENOACK: isize = -13;
<|endoftext|>