tor_allocate.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. use libc::{c_char, c_void};
  2. use std::{ptr, slice};
  3. #[cfg(not(test))]
  4. extern "C" {
  5. fn tor_malloc_ ( size: usize) -> *mut c_void;
  6. }
  7. // Defined only for tests, used for testing purposes, so that we don't need
  8. // to link to tor C files. Uses the system allocator
  9. #[cfg(test)]
  10. extern "C" fn tor_malloc_ ( size: usize) -> *mut c_void {
  11. use libc::malloc;
  12. unsafe { malloc(size) }
  13. }
  14. /// Allocate memory using tor_malloc_ and copy an existing string into the
  15. /// allocated buffer, returning a pointer that can later be called in C.
  16. ///
  17. /// # Inputs
  18. ///
  19. /// * `src`, a reference to a String that will be copied.
  20. ///
  21. /// # Returns
  22. ///
  23. /// A `String` that should be freed by tor_free in C
  24. ///
  25. pub fn allocate_and_copy_string(src: &String) -> *mut c_char {
  26. let bytes = src.as_bytes();
  27. let size = bytes.len();
  28. let size_with_null_byte = size + 1;
  29. let dest = unsafe { tor_malloc_(size_with_null_byte) as *mut u8 };
  30. if dest.is_null() {
  31. return dest as *mut c_char;
  32. }
  33. unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), dest, size) };
  34. // set the last byte as null, using the ability to index into a slice
  35. // rather than doing pointer arithmatic
  36. let slice = unsafe { slice::from_raw_parts_mut(dest, size_with_null_byte) };
  37. slice[size] = 0; // add a null terminator
  38. dest as *mut c_char
  39. }
  40. #[cfg(test)]
  41. mod test {
  42. #[test]
  43. fn test_allocate_and_copy_string_with_empty() {
  44. use std::ffi::CStr;
  45. use libc::{free, c_void};
  46. use tor_allocate::allocate_and_copy_string;
  47. let empty = String::new();
  48. let allocated_empty = allocate_and_copy_string(&empty);
  49. let allocated_empty_rust = unsafe {
  50. CStr::from_ptr(allocated_empty).to_str().unwrap()
  51. };
  52. assert_eq!("", allocated_empty_rust);
  53. unsafe { free(allocated_empty as *mut c_void) };
  54. }
  55. #[test]
  56. fn test_allocate_and_copy_string_with_not_empty_string() {
  57. use std::ffi::CStr;
  58. use libc::{free, c_void};
  59. use tor_allocate::allocate_and_copy_string;
  60. let empty = String::from("foo bar biz");
  61. let allocated_empty = allocate_and_copy_string(&empty);
  62. let allocated_empty_rust = unsafe {
  63. CStr::from_ptr(allocated_empty).to_str().unwrap()
  64. };
  65. assert_eq!("foo bar biz", allocated_empty_rust);
  66. unsafe { free(allocated_empty as *mut c_void) };
  67. }
  68. }