tor_allocate.rs 2.7 KB

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