[tor-commits] [tor/master] add tor allocator for rust
nickm at torproject.org
nickm at torproject.org
Fri Oct 27 14:07:26 UTC 2017
commit 76bbdfbfa9eca46b53d3ec5a44deafce51d2875a
Author: Chelsea Holland Komlo <me at chelseakomlo.com>
Date: Sat Oct 14 23:05:31 2017 -0400
add tor allocator for rust
---
src/rust/protover/ffi.rs | 20 ++++----
src/rust/tor_allocate/Cargo.toml | 13 +++++
src/rust/tor_allocate/include.am | 13 +++++
src/rust/tor_allocate/lib.rs | 12 +++++
src/rust/tor_allocate/tor_allocate.rs | 90 +++++++++++++++++++++++++++++++++++
5 files changed, 138 insertions(+), 10 deletions(-)
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index 539b6c0ba..23a289bd5 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -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)
}
diff --git a/src/rust/tor_allocate/Cargo.toml b/src/rust/tor_allocate/Cargo.toml
new file mode 100644
index 000000000..ceb08b78a
--- /dev/null
+++ b/src/rust/tor_allocate/Cargo.toml
@@ -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"]
+
diff --git a/src/rust/tor_allocate/include.am b/src/rust/tor_allocate/include.am
new file mode 100644
index 000000000..9e770dbc0
--- /dev/null
+++ b/src/rust/tor_allocate/include.am
@@ -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:
+
diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs
new file mode 100644
index 000000000..81afd095f
--- /dev/null
+++ b/src/rust/tor_allocate/lib.rs
@@ -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::*;
diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs
new file mode 100644
index 000000000..de1d13942
--- /dev/null
+++ b/src/rust/tor_allocate/tor_allocate.rs
@@ -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) };
+ }
+}
More information about the tor-commits
mailing list