gecko-dev/third_party/rust/plain
Markus Stange c6fc1caf62 Bug 1457481 - Run mach vendor rust. r=froydnj,erahm
Most importantly, this picks up "object" and "goblin" for ELF binary parsing.
We only use the ELF code from goblin, so the mach-O parsing code gets
eliminated by the linker. Overall, this increases the Android installer size
by 20KB.

Try pushes for reference:
before: https://treeherder.mozilla.org/#/jobs?repo=try&revision=834b56dc5ab3d63a43a32f740ee8212296ac726d&selectedJob=201600899
after: https://treeherder.mozilla.org/#/jobs?repo=try&revision=6983b27e8d3cb715d3b7e6cbd276683f6466e3cc&selectedJob=201600475

installer size: 34524820 -> 34542861 (34.52MB -> 34.54MB)

$ mach vendor rust
    Updating registry `https://github.com/rust-lang/crates.io-index`
      Adding goblin v0.0.17
      Adding memmap v0.6.2
      Adding miniz-sys v0.1.10
      Adding object v0.10.0
      Adding parity-wasm v0.31.3
      Adding plain v0.2.3
      Adding profiler_helper v0.1.0 (file:///Users/mstange/code/mozilla/tools/profiler/rust-helper)
      Adding scroll v0.9.1
      Adding scroll_derive v0.9.5
      Adding syn v0.15.5
      Adding thin-vec v0.1.0
      Adding uuid v0.6.5
 0:30.11 The following files exceed the filesize limit of 102400:

third_party/rust/miniz-sys/miniz.c
third_party/rust/syn-0.14.6/src/expr.rs
third_party/rust/syn-0.14.6/src/gen/fold.rs
third_party/rust/syn-0.14.6/src/gen/visit.rs
third_party/rust/syn-0.14.6/src/gen/visit_mut.rs

The syn dependency is not compiled for goblin, as far as I can tell - it's only
needed for the 'syn' feature of scroll_derive, and scroll does not ask for
scroll_derive/syn.

object -> goblin -> scroll -> scroll_derive -/-> syn

But it looks like other versions of syn were already in the tree.

Depends on D7021

Differential Revision: https://phabricator.services.mozilla.com/D7023

--HG--
rename : third_party/rust/syn/src/parsers.rs => third_party/rust/syn-0.14.6/src/parsers.rs
rename : third_party/rust/syn/src/verbatim.rs => third_party/rust/syn-0.14.6/src/verbatim.rs
rename : third_party/rust/uuid/.travis.yml => third_party/rust/uuid-0.5.1/.travis.yml
rename : third_party/rust/uuid/src/rustc_serialize.rs => third_party/rust/uuid-0.5.1/src/rustc_serialize.rs
rename : third_party/rust/uuid/src/serde.rs => third_party/rust/uuid-0.5.1/src/serde.rs
extra : moz-landing-system : lando
2018-10-02 01:50:56 +00:00
..
src Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
.cargo-checksum.json Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
.travis.yml Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
Cargo.toml Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
LICENSE-APACHE Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
LICENSE-MIT Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00
README.md Bug 1457481 - Run mach vendor rust. r=froydnj,erahm 2018-10-02 01:50:56 +00:00

README.md

libplain

Build Status Current Crates.io Version Current Documentation

A small Rust library that allows users to interpret arrays of bytes as certain kinds of structures safely.

This crate provides an unsafe trait Plain, which the user of the crate uses to mark types for which operations of this library are safe. See Plain for the contractual obligation.

Other than that, everything else in this crate is perfectly safe to use as long as the Plain trait is not implemented on inadmissible types (similar to how Send and Sync in the standard library work).

Purpose

In low level systems development, it is sometimes necessary to interpret locations in memory as data structures. Functions of this crate serve to avoid pitfalls associated with that, without having to resort to big, full-featured (de)serialization libraries.

On the other hand, this crate contains no provisions when it comes to handling differences in encoding and byte ordering between platforms. As such, it is entirely unsuitable for processing external data such as file contents or network packets.

Examples

To start using the crate, simply do extern crate plain;.

If you want your plain types to have methods from this crate, also include use plain.Plain;.

Then it's just a matter of marking the right types and using them.


extern crate plain;
use plain::Plain;
use std::mem;


#[repr(C)]
#[derive(Default)]
struct ELF64Header {
    pub e_ident: [u8; 16],
    pub e_type: u16,
    pub e_machine: u16,
    pub e_version: u32,
    pub e_entry: u64,
    pub e_phoff: u64,
    pub e_shoff: u64,
    pub e_flags: u32,
    pub e_ehsize: u16,
    pub e_phentsize: u16,
    pub e_phnum: u16,
    pub e_shentsize: u16,
    pub e_shnum: u16,
    pub e_shstrndx: u16,
}

// SAFE: ELF64Header satisfies all the requirements of `Plain`.
unsafe impl Plain for ELF64Header {}

impl ELF64Header {
	fn from_bytes(buf: &[u8]) -> &ELF64Header {
			plain::from_bytes(buf).expect("The buffer is either too short or not aligned!")
		}

		fn from_mut_bytes(buf: &mut [u8]) -> &mut ELF64Header {
			plain::from_mut_bytes(buf).expect("The buffer is either too short or not aligned!")
		}

		fn copy_from_bytes(buf: &[u8]) -> ELF64Header {
			let mut h = ELF64Header::default();
			h.copy_from_bytes(buf).expect("The buffer is too short!");
			h
		}
}

# fn process_elf(elf: &ELF64Header) {}

// Conditional copying for ultimate hackery.
fn opportunistic_elf_processing(buf: &[u8]) {
	if plain::is_aligned::<ELF64Header>(buf) {
        // No copy necessary.
			let elf_ref = ELF64Header::from_bytes(buf);
			process_elf(elf_ref);
    } else {
        // Not aligned properly, copy to stack first.
			let elf = ELF64Header::copy_from_bytes(buf);
			process_elf(&elf);
    }
}

#[repr(C)]
#[derive(Default, Copy, Clone)]
struct ArrayEntry {
    pub name: [u8; 32],
    pub tag: u32,
    pub score: u32,
}

// SAFE: ArrayEntry satisfies all the requirements of `Plain`.
unsafe impl Plain for ArrayEntry {}

fn array_from_bytes(buf: &[u8]) -> &[ArrayEntry] {
    // NOTE: length is not a concern here,
    // since slice_from_bytes() can return empty slice.

    match plain::slice_from_bytes(buf) {
        Err(_) => panic!("The buffer is not aligned!"),
        Ok(arr) => arr,
    }
}

fn array_from_unaligned_bytes(buf: &[u8]) -> Vec<ArrayEntry> {
		let length = buf.len() / mem::size_of::<ArrayEntry>();
	let mut result = vec![ArrayEntry::default(); length];
 	(&mut result).copy_from_bytes(buf).expect("Cannot fail here.");
		result
}

# fn main() {}

Comparison to pod

pod is another crate created to help working with plain data. The major difference between pod and plain is scope.

plain currently provides only a few functions (+method wrappers) and its implementation involves very few lines of unsafe code. It can be used in no_std code. Also, it doesn't deal with endianness in any way, so it is only suitable for certain kinds of low-level work.

pod, on the other hand, provides a wide arsenal of various methods, most of which may be unnecessary for a given use case. It has dependencies on std as well as other crates, but among other things it provides tools to handle endianness properly.

In short, plain is much, much plainer...