Skip to content

Audit Copies/Conversions #34

@jasoncolburne

Description

@jasoncolburne

We want to minimize these throughout the library, for security reasons if nothing else.

An example of a bad pattern accepting a String or a Vec<u8> as a parameter to a function. Instead, one can always coerce into &str or &[u8] with a simple & from a String or Vec<u8>, so I've found the minimizing application code pattern to be accepting parameters as &str and &[u8] (and &Matter etc). Values returned from functions are typically then the non-borrowed, juiced up version of the types. Here is a concrete example:

Good:

fn trim(input: &[u8], length: usize) -> Vec<u8> {
    input[..length].to_vec()
}

fn string_to_vec(input: &str) -> Vec<u8> {
    input.as_bytes().to_vec()
}

// example usage
fn exercise() {
    let v = trim(&string_to_vec("stuff"), 3);
}

Bad:

fn foo(input: Vec<u8>) -> Vec<u8> {
    input[..len]
}

fn foo(input: String) -> Vec<u8> {
    input
}

// example usage, notice how we need another .to_string() in the
// calling code, and we lose the & on the vec param
fn exercise() {
    let v = trim(string_to_vec("stuff".to_string()), 3);
}

In addition to adding complexity to the application (which we must aim to minimize), the longer one can leave variables as borrowed primitive entities, the more one opens up the door to making efficiency gains from using data in place. It's also less zeroing memory to worry about, as there will be less copies of sensitive information in memory in general.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions