[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [tor-bugs] #23881 [Core Tor/Tor]: Implement a way to utilise tor's logging system from Rust code
#23881: Implement a way to utilise tor's logging system from Rust code
-----------------------------------------------+---------------------------
Reporter: isis | Owner: isis
Type: enhancement | Status: accepted
Priority: High | Milestone: Tor:
| 0.3.3.x-final
Component: Core Tor/Tor | Version:
Severity: Normal | Resolution:
Keywords: rust, rust-pilot, review-group-29 | Actual Points:
Parent ID: | Points: 3
Reviewer: nickm | Sponsor:
-----------------------------------------------+---------------------------
Comment (by isis):
Okay, to answer the question of "Does `CString::new` perform a copy?"
Manish answered above, but I ''think'' there was a typo in the answer? (It
seems to be missing the word "not" in the latter clause?) I had assumed it
always copied, so I went and dug through the stdlib to figure it out.
So [https://doc.rust-lang.org/src/std/ffi/c_str.rs.html#330-332 looking at
the source of `CString::new`]:
{{{#!rust
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
Self::_new(t.into())
}
fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
match memchr::memchr(0, &bytes) {
Some(i) => Err(NulError(i, bytes)),
None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
}
}
}}}
[wow!!! check out that ↑↑↑↑↑↑ frickin syntax highlighting!!!!! zomg, my
life is changed!!]
it takes a any `T` which has implemented a way (`Into<T>`) to transmute it
into a `Vec<u8>` and calls [https://doc.rust-
lang.org/src/std/ffi/c_str.rs.html#334-339 `Cstring::_new()`] on it. There
[https://doc.rust-lang.org/src/alloc/vec.rs.html#2226-2230 exists]
`impl<'a> From<&'a str> for Vec<u8>`:
{{{#!rust
impl<'a> From<&'a str> for Vec<u8> {
fn from(s: &'a str) -> Vec<u8> {
From::from(s.as_bytes())
}
}
}}}
The `_new()` function checks that is has no NUL bytes, and errors if it
does, then calls [https://doc.rust-
lang.org/src/std/ffi/c_str.rs.html#361-365
`CString::from_vec_unchecked()`]:
{{{#!rust
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
v.reserve_exact(1);
v.push(0);
CString { inner: v.into_boxed_slice() }
}
}}}
And then [https://doc.rust-
lang.org/alloc/vec/struct.Vec.html#method.into_boxed_slice
`Vec::into_boxed_slice()`]:
{{{#!rust
pub fn into_boxed_slice(mut self) -> Box<[T]> {
unsafe {
self.shrink_to_fit();
let buf = ptr::read(&self.buf);
mem::forget(self);
buf.into_box()
}
}
}}}
which is doing some olympic level gymnastics where [https://doc.rust-
lang.org/std/ptr/fn.read.html `std::ptr::read`] is returning a `Rawvec`,
then it `mem::forget()`s itself so that the deallocator never runs, and
finally it `Box`es the memory it forgot about by calling
`RawVec::into_box()`:
{{{#!rust
impl<T> RawVec<T, Heap> {
/// Converts the entire buffer into `Box<[T]>`.
///
/// While it is not *strictly* Undefined Behavior to call
/// this procedure while some of the RawVec is uninitialized,
/// it certainly makes it trivial to trigger it.
///
/// Note that this will correctly reconstitute any `cap` changes
/// that may have been performed. (see description of type for
details)
pub unsafe fn into_box(self) -> Box<[T]> {
// NOTE: not calling `cap()` here, actually using the real `cap`
field!
let slice = slice::from_raw_parts_mut(self.ptr(), self.cap);
let output: Box<[T]> = Box::from_raw(slice);
mem::forget(self);
output
}
}
}}}
which is doing even more olympic level gymnastics with [https://doc.rust-
lang.org/std/slice/fn.from_raw_parts.html `slice::from_raw_parts`], which
is like the King of Capital-U Unsafety, because it just says "N bytes from
this pointer forward are now a slice, with an lifetime that I decided by
royal proclamation, and which is not necessarily the correct lifetime
given that I was handed a raw pointer that I know nothing about". But it
doesn't copy. Then it does a similar pirouette as the trick we saw before
with `std::ptr::read` and then `Box`ing the `RawVec`, but even more
complicated and dangerous, like if the last one was a pirouette, this is
like a pirouette while juggling machetes. `Box::from_raw` is only
''really'' supposed to be called on pointers produced via `Box::into_raw`,
but whatever, so many crazy things have already been done with these
pointers to this memory. So `Box::from_raw` creates a [https://doc.rust-
lang.org/std/ptr/struct.Unique.html `Unique<T>`], which just says, "I own
this raw pointer to a `T` (`*mut T`), and I'm just going to pretend it
''is'' a `T`." and then calls `Box::from_unique` on the resulting
`Unique<T>`:
{{{#!rust
pub unsafe fn from_unique(u: Unique<T>) -> Self {
mem::transmute(u)
}
}}}
which, as you can see, finishes its machete-juggling pirouette off with a
triple axel flamethrower party by calling `mem::transmute`, re-
interpretting the raw bits of the wrapped raw pointer as a `Box`. So much
Unsafe! Seemingly no additional allocations. :)
--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/23881#comment:36>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online
_______________________________________________
tor-bugs mailing list
tor-bugs@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-bugs