Skip to content
This repository has been archived by the owner on Jun 8, 2024. It is now read-only.

Commit

Permalink
document all unsafe blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Jun 6, 2024
1 parent cbcf02d commit 046d7a4
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 11 deletions.
14 changes: 10 additions & 4 deletions core/src/ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,13 @@ mod internal {
pub struct Slot<T: ?Sized>(*const T, PhantomData<*mut fn()>);

impl<T: ?Sized> Slot<T> {
// SAFETY: `Slot<T>` must not outlive `&T`
pub(super) unsafe fn new(v: &T) -> Slot<T> {
Slot(v as *const T, PhantomData)
}

pub(super) fn get(&self) -> &T {
// SAFETY: `Slot<T>` must not outlive `&T`, as per `Slot::new`
unsafe { &*self.0 }
}
}
Expand All @@ -256,8 +258,8 @@ mod internal {

#[cfg(feature = "alloc")]
mod alloc_support {
use core::any::Any;
use alloc::boxed::Box;
use core::any::Any;

use crate::props::ErasedProps;

Expand All @@ -275,7 +277,7 @@ mod alloc_support {
use super::ErasedFrame;

pub trait DispatchCtxt {
fn dispatch_with_current(&self, with: &mut dyn FnMut(ErasedCurrent));
fn dispatch_with_current(&self, with: &mut dyn FnMut(&ErasedCurrent));

fn dispatch_open_root(&self, props: &dyn ErasedProps) -> ErasedFrame;
fn dispatch_open_push(&self, props: &dyn ErasedProps) -> ErasedFrame;
Expand All @@ -294,6 +296,7 @@ mod alloc_support {
);

impl ErasedCurrent {
// SAFETY: `ErasedCurrent` must not outlive `&v`
pub(super) unsafe fn new<'a>(v: &'a impl Props) -> Self {
let v: &'a dyn ErasedProps = v;
let v: &'a (dyn ErasedProps + 'static) =
Expand All @@ -303,6 +306,7 @@ mod alloc_support {
}

pub(super) fn get<'a>(&'a self) -> &'a (dyn ErasedProps + 'a) {
// SAFETY: `ErasedCurrent` must not outlive `&v`, as per `ErasedCurrent::new`
unsafe { &*self.0 }
}
}
Expand Down Expand Up @@ -344,8 +348,10 @@ mod alloc_support {
where
C::Frame: Send + 'static,
{
fn dispatch_with_current(&self, with: &mut dyn FnMut(internal::ErasedCurrent)) {
self.with_current(move |props| with(unsafe { internal::ErasedCurrent::new(&props) }))
fn dispatch_with_current(&self, with: &mut dyn FnMut(&internal::ErasedCurrent)) {
// SAFETY: The borrow passed to `with` is arbitarily short, so `ErasedCurrent::get`
// cannot outlive `props`
self.with_current(move |props| with(&unsafe { internal::ErasedCurrent::new(&props) }))
}

fn dispatch_open_root(&self, props: &dyn ErasedProps) -> ErasedFrame {
Expand Down
2 changes: 1 addition & 1 deletion core/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl<'a> serde::Serialize for Path<'a> {

#[cfg(feature = "alloc")]
mod alloc_support {
use alloc::{boxed::Box, borrow::Cow};
use alloc::{borrow::Cow, boxed::Box};

use super::*;

Expand Down
1 change: 1 addition & 0 deletions core/src/props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ mod alloc_support {

impl<P: ?Sized> Dedup<P> {
pub(super) fn new<'a>(props: &'a P) -> &'a Dedup<P> {
// SAFETY: `Dedup<P>` and `P` have the same ABI
unsafe { &*(props as *const P as *const Dedup<P>) }
}
}
Expand Down
12 changes: 8 additions & 4 deletions core/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,8 @@ impl<T: Rng> Rng for AssertInternal<T> {

#[cfg(feature = "std")]
mod std_support {
use core::any::Any;
use alloc::boxed::Box;
use core::any::Any;
use std::sync::OnceLock;

use crate::{
Expand Down Expand Up @@ -726,9 +726,13 @@ mod std_support {

self.0
.get()
.map(|rt| unsafe {
&*(&rt.runtime as *const AmbientSyncRuntime as *const AmbientRuntime)
})
.map(|rt|
// SAFETY: The borrow of `self` cannot outlive the components
// it contains. This block is converting `*const dyn T + Send + Sync`
// to `&'_ dyn T + Send + Sync`
unsafe {
&*(&rt.runtime as *const AmbientSyncRuntime as *const AmbientRuntime)
})
.unwrap_or(&EMPTY_AMBIENT_RUNTIME)
}
}
Expand Down
6 changes: 5 additions & 1 deletion core/src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ impl<'k> Str<'k> {
// NOTE: It's important here that the lifetime returned is not `'k`
// If it was it would be possible to return a `&'static str` from
// an owned value
// SAFETY: `self.value` is guaranteed to outlive the borrow of `self`
unsafe { &(*self.value) }
}

Expand Down Expand Up @@ -339,7 +340,10 @@ impl<'k> serde::Serialize for Str<'k> {

#[cfg(feature = "alloc")]
mod alloc_support {
use alloc::{borrow::{Cow, ToOwned}, string::String};
use alloc::{
borrow::{Cow, ToOwned},
string::String,
};

use super::*;

Expand Down
5 changes: 5 additions & 0 deletions emitter/file/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ path = "../../batcher"

[dependencies.rand]
version = "0.8"

[dev-dependencies.emit]
version = "0.11.0-alpha.1"
path = "../../"
features = ["implicit_rt"]
5 changes: 4 additions & 1 deletion emitter/file/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,10 @@ fn default_writer(
) -> io::Result<()> {
use std::ops::ControlFlow;

use emit::{Props as _, well_known::{KEY_MSG, KEY_TPL, KEY_TS, KEY_TS_START}};
use emit::{
well_known::{KEY_MSG, KEY_TPL, KEY_TS, KEY_TS_START},
Props as _,
};

struct EventValue<'a, P>(&'a emit::Event<'a, P>);

Expand Down
8 changes: 8 additions & 0 deletions emitter/otlp/src/client/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ impl HttpResponse {
type Output = Result<bool, Error>;

fn poll(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
// SAFETY: `self` does not use interior pinning
let BufNext(incoming, body, trailer) = unsafe { Pin::get_unchecked_mut(self) };

match Pin::new(incoming).poll_frame(ctx) {
Expand Down Expand Up @@ -675,13 +676,17 @@ impl<T: tokio::io::AsyncRead> hyper::rt::Read for HttpIo<T> {
cx: &mut Context<'_>,
mut buf: hyper::rt::ReadBufCursor<'_>,
) -> Poll<Result<(), std::io::Error>> {
// SAFETY: `io` inherits the pinning requirements of `self`
let io = unsafe { self.map_unchecked_mut(|io| &mut io.0) };

// SAFETY: `io` does not uninitialize any bytes
let mut read_buf = tokio::io::ReadBuf::uninit(unsafe { buf.as_mut() });

match tokio::io::AsyncRead::poll_read(io, cx, &mut read_buf) {
Poll::Ready(Ok(())) => {
let read = read_buf.filled().len();

// SAFETY: The bytes being advanced have been initialized by `read_buf`
unsafe { buf.advance(read) };

Poll::Ready(Ok(()))
Expand All @@ -698,12 +703,14 @@ impl<T: tokio::io::AsyncWrite> hyper::rt::Write for HttpIo<T> {
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, std::io::Error>> {
// SAFETY: `io` inherits the pinning requirements of `self`
let io = unsafe { self.map_unchecked_mut(|io| &mut io.0) };

tokio::io::AsyncWrite::poll_write(io, cx, buf)
}

fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
// SAFETY: `io` inherits the pinning requirements of `self`
let io = unsafe { self.map_unchecked_mut(|io| &mut io.0) };

tokio::io::AsyncWrite::poll_flush(io, cx)
Expand All @@ -713,6 +720,7 @@ impl<T: tokio::io::AsyncWrite> hyper::rt::Write for HttpIo<T> {
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), std::io::Error>> {
// SAFETY: `io` inherits the pinning requirements of `self`
let io = unsafe { self.map_unchecked_mut(|io| &mut io.0) };

tokio::io::AsyncWrite::poll_shutdown(io, cx)
Expand Down
4 changes: 4 additions & 0 deletions src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ impl<'a, C: Ctxt> Drop for EnterGuard<'a, C> {

impl<C: Ctxt> Drop for Frame<C> {
fn drop(&mut self) {
// SAFETY: We're being dropped, so won't access `scope` again
self.ctxt
.close(unsafe { mem::ManuallyDrop::take(&mut self.scope) })
}
Expand All @@ -150,9 +151,12 @@ impl<C: Ctxt, F: Future> Future for FrameFuture<C, F> {

#[track_caller]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// SAFETY: The fields of `FrameFuture` remain pinned
let unpinned = unsafe { Pin::get_unchecked_mut(self) };

let __guard = unpinned.frame.enter();

// SAFETY: `FrameFuture::future` is pinned
unsafe { Pin::new_unchecked(&mut unpinned.future) }.poll(cx)
}
}
1 change: 1 addition & 0 deletions src/macro_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ impl __PrivateMacroProps<'static> {

impl<'a> __PrivateMacroProps<'a> {
pub fn new_ref<'b>(props: &'b [(Str<'a>, Option<Value<'a>>)]) -> &'b Self {
// SAFETY: `__PrivateMacroProps` and the array have the same ABI
unsafe {
&*(props as *const [(Str<'a>, Option<Value<'a>>)] as *const __PrivateMacroProps<'a>)
}
Expand Down

0 comments on commit 046d7a4

Please sign in to comment.