tor_allocate.rs 3.1 KB

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