add tor allocator for rust

This commit is contained in:
Chelsea Holland Komlo
2017-10-14 23:05:31 -04:00
committed by Nick Mathewson
parent d14a83f74f
commit 76bbdfbfa9
5 changed files with 138 additions and 10 deletions
+10 -10
View File
@@ -8,7 +8,7 @@ use std::ffi::CString;
use protover::*;
use smartlist::*;
use tor_allocate::allocate_string;
use tor_allocate::allocate_and_copy_string;
/// Translate C enums to Rust Proto enums, using the integer value of the C
/// enum to map to its associated Rust enum
@@ -124,17 +124,17 @@ pub extern "C" fn protover_compute_vote(
) -> *mut c_char {
if list.is_null() {
let mut empty = String::new();
return allocate_string(&mut empty);
let empty = String::new();
return allocate_and_copy_string(&empty);
}
// Dereference of raw pointer requires an unsafe block. The pointer is
// checked above to ensure it is not null.
let data: Vec<String> = unsafe { (*list).get_list() };
let mut vote = compute_vote(data, threshold);
let vote = compute_vote(data, threshold);
allocate_string(&mut vote)
allocate_and_copy_string(&vote)
}
/// Provide an interface for C to translate arguments and return types for
@@ -162,10 +162,10 @@ pub extern "C" fn protover_compute_for_old_tor(
) -> *mut c_char {
// Not handling errors when unwrapping as the content is controlled
// and is an empty string
let mut empty = String::new();
let empty = String::new();
if version.is_null() {
return allocate_string(&mut empty);
return allocate_and_copy_string(&empty);
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -174,10 +174,10 @@ pub extern "C" fn protover_compute_for_old_tor(
let version = match c_str.to_str() {
Ok(n) => n,
Err(_) => return allocate_string(&mut empty),
Err(_) => return allocate_and_copy_string(&empty),
};
let mut supported = compute_for_old_tor(&version);
let supported = compute_for_old_tor(&version);
allocate_string(&mut supported)
allocate_and_copy_string(&supported)
}
+13
View File
@@ -0,0 +1,13 @@
[package]
authors = ["The Tor Project"]
version = "0.0.1"
name = "tor_allocate"
[dependencies]
libc = "0.2.22"
[lib]
name = "tor_allocate"
path = "lib.rs"
crate_type = ["rlib", "staticlib"]
+13
View File
@@ -0,0 +1,13 @@
EXTRA_DIST +=\
src/rust/tor_allocate/Cargo.toml \
src/rust/tor_allocate/lib.rs \
src/rust/tor_allocate/tor_allocate.rs
src/rust/target/release/@TOR_RUST_C_STRING_STATIC_NAME@: FORCE
( cd "$(abs_top_srcdir)/src/rust/tor_allocate" ; \
CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
CARGO_HOME="$(abs_top_builddir)/src/rust" \
$(CARGO) build --release --quiet $(CARGO_ONLINE) )
FORCE:
+12
View File
@@ -0,0 +1,12 @@
//! Allocation helper functions that allow data to be allocated in Rust
//! using tor's specified allocator. In doing so, this can be later freed
//! from C.
//!
//! This is currently a temporary solution, we will later use tor's allocator
//! by default for any allocation that occurs in Rust. However, as this will
//! stabalize in 2018, we can use this as a temporary measure.
extern crate libc;
mod tor_allocate;
pub use tor_allocate::*;
+90
View File
@@ -0,0 +1,90 @@
use libc::{c_char, c_void};
use std::{ptr, slice};
#[cfg(not(test))]
extern "C" {
fn tor_malloc_ ( size: usize) -> *mut c_void;
}
// Defined only for tests, used for testing purposes, so that we don't need
// to link to tor C files. Uses the system allocator
#[cfg(test)]
extern "C" fn tor_malloc_ ( size: usize) -> *mut c_void {
use libc::malloc;
unsafe { malloc(size) }
}
/// Allocate memory using tor_malloc_ and copy an existing string into the
/// allocated buffer, returning a pointer that can later be called in C.
///
/// # Inputs
///
/// * `src`, a reference to a String that will be copied.
///
/// # Returns
///
/// A `String` that should be freed by tor_free in C
///
pub fn allocate_and_copy_string(src: &String) -> *mut c_char {
let bytes = s.as_bytes();
let size = s.len();
let size_with_null_byte = size + 1;
let dest = unsafe { tor_malloc_(size_with_null_byte) as *mut u8 };
if dest.is_null() {
return dest as *mut c_char;
}
unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), dest, size) };
// set the last byte as null, using the ability to index into a slice
// rather than doing pointer arithmatic
let slice = unsafe { slice::from_raw_parts_mut(dest, size_with_null_byte) };
slice[size] = 0; // add a null terminator
dest as *mut c_char
}
#[cfg(test)]
mod test {
#[test]
fn test_allocate_and_copy_string_with_empty() {
use std::ffi::CStr;
use libc::{free, c_void};
use tor_allocate::allocate_and_copy_string;
let empty = String::new();
let allocated_empty = allocate_and_copy_string(&empty);
let allocated_empty_rust = unsafe {
CStr::from_ptr(allocated_empty).to_str().unwrap()
};
assert_eq!("", allocated_empty_rust);
unsafe { free(allocated_empty as *mut c_void) };
}
#[test]
fn test_allocate_and_copy_string_with_not_empty_string() {
use std::ffi::CStr;
use libc::{free, c_void};
use tor_allocate::allocate_and_copy_string;
let empty = String::from("foo bar biz");
let allocated_empty = allocate_and_copy_string(&empty);
let allocated_empty_rust = unsafe {
CStr::from_ptr(allocated_empty).to_str().unwrap()
};
assert_eq!("foo bar biz", allocated_empty_rust);
unsafe { free(allocated_empty as *mut c_void) };
}
}