1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-11 16:42:21 -05:00

build: require safety comments on unsafe code (#13870)

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
This commit is contained in:
Luca Casonato 2022-06-26 00:13:24 +02:00 committed by GitHub
parent 38505db391
commit 8d82ba7299
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 294 additions and 87 deletions

View file

@ -153,11 +153,13 @@ fn run(
fn get_port() -> u16 { fn get_port() -> u16 {
static mut NEXT_PORT: u16 = 4544; static mut NEXT_PORT: u16 = 4544;
let port = unsafe { NEXT_PORT }; // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { let port = unsafe {
let p = NEXT_PORT;
NEXT_PORT += 1; NEXT_PORT += 1;
} p
};
port port
} }

View file

@ -76,7 +76,13 @@ mod dirs {
pub fn home_dir() -> Option<PathBuf> { pub fn home_dir() -> Option<PathBuf> {
std::env::var_os("HOME") std::env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) }) .and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| unsafe { fallback() }) .or_else(|| {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
fallback()
}
})
.map(PathBuf::from) .map(PathBuf::from)
} }

View file

@ -21,7 +21,11 @@ pub fn set_lsp_log_level(level: log::Level) {
pub fn lsp_log_level() -> log::Level { pub fn lsp_log_level() -> log::Level {
let level = LSP_LOG_LEVEL.load(Ordering::SeqCst); let level = LSP_LOG_LEVEL.load(Ordering::SeqCst);
unsafe { std::mem::transmute(level) } // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
std::mem::transmute(level)
}
} }
/// Use this macro to do "info" logs in the lsp code. This allows /// Use this macro to do "info" logs in the lsp code. This allows

View file

@ -20,6 +20,8 @@ pub fn start(parent_process_id: u32) {
#[cfg(unix)] #[cfg(unix)]
fn is_process_active(process_id: u32) -> bool { fn is_process_active(process_id: u32) -> bool {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { unsafe {
// signal of 0 checks for the existence of the process id // signal of 0 checks for the existence of the process id
libc::kill(process_id as i32, 0) == 0 libc::kill(process_id as i32, 0) == 0

View file

@ -4,6 +4,8 @@
/// This is the difference between `ulimit -n` and `ulimit -n -H`. /// This is the difference between `ulimit -n` and `ulimit -n -H`.
pub fn raise_fd_limit() { pub fn raise_fd_limit() {
#[cfg(unix)] #[cfg(unix)]
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { unsafe {
let mut limits = libc::rlimit { let mut limits = libc::rlimit {
rlim_cur: 0, rlim_cur: 0,

View file

@ -302,13 +302,19 @@ mod internal {
Some((head, rc)) => { Some((head, rc)) => {
// Register this `Cancelable` node with a `CancelHandle` head node. // Register this `Cancelable` node with a `CancelHandle` head node.
assert_ne!(self, head); assert_ne!(self, head);
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let self_inner = unsafe { &mut *self.inner.get() }; let self_inner = unsafe { &mut *self.inner.get() };
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let head_inner = unsafe { &mut *head.inner.get() }; let head_inner = unsafe { &mut *head.inner.get() };
self_inner.link(waker, head_inner, rc) self_inner.link(waker, head_inner, rc)
} }
None => { None => {
// This `Cancelable` has already been linked to a `CancelHandle` head // This `Cancelable` has already been linked to a `CancelHandle` head
// node; just update our stored `Waker` if necessary. // node; just update our stored `Waker` if necessary.
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let inner = unsafe { &mut *self.inner.get() }; let inner = unsafe { &mut *self.inner.get() };
inner.update_waker(waker) inner.update_waker(waker)
} }
@ -316,11 +322,15 @@ mod internal {
} }
pub fn cancel(&self) { pub fn cancel(&self) {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let inner = unsafe { &mut *self.inner.get() }; let inner = unsafe { &mut *self.inner.get() };
inner.cancel(); inner.cancel();
} }
pub fn is_canceled(&self) -> bool { pub fn is_canceled(&self) -> bool {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let inner = unsafe { &mut *self.inner.get() }; let inner = unsafe { &mut *self.inner.get() };
inner.is_canceled() inner.is_canceled()
} }
@ -337,6 +347,8 @@ mod internal {
impl Drop for Node { impl Drop for Node {
fn drop(&mut self) { fn drop(&mut self) {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let inner = unsafe { &mut *self.inner.get() }; let inner = unsafe { &mut *self.inner.get() };
inner.unlink(); inner.unlink();
} }
@ -392,6 +404,8 @@ mod internal {
prev: next_prev_nn, prev: next_prev_nn,
.. ..
} => { } => {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let prev = unsafe { &mut *next_prev_nn.as_ptr() }; let prev = unsafe { &mut *next_prev_nn.as_ptr() };
match prev { match prev {
NodeInner::Linked { NodeInner::Linked {
@ -444,10 +458,14 @@ mod internal {
if prev_nn == next_nn { if prev_nn == next_nn {
// There were only two nodes in this chain; after unlinking ourselves // There were only two nodes in this chain; after unlinking ourselves
// the other node is no longer linked. // the other node is no longer linked.
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let other = unsafe { prev_nn.as_mut() }; let other = unsafe { prev_nn.as_mut() };
*other = NodeInner::Unlinked; *other = NodeInner::Unlinked;
} else { } else {
// The chain had more than two nodes. // The chain had more than two nodes.
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
match unsafe { prev_nn.as_mut() } { match unsafe { prev_nn.as_mut() } {
NodeInner::Linked { NodeInner::Linked {
next: prev_next_nn, .. next: prev_next_nn, ..
@ -456,6 +474,8 @@ mod internal {
} }
_ => unreachable!(), _ => unreachable!(),
} }
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
match unsafe { next_nn.as_mut() } { match unsafe { next_nn.as_mut() } {
NodeInner::Linked { NodeInner::Linked {
prev: next_prev_nn, .. prev: next_prev_nn, ..
@ -473,6 +493,8 @@ mod internal {
fn cancel(&mut self) { fn cancel(&mut self) {
let mut head_nn = NonNull::from(self); let mut head_nn = NonNull::from(self);
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
// Mark the head node as canceled. // Mark the head node as canceled.
let mut item_nn = let mut item_nn =
match replace(unsafe { head_nn.as_mut() }, NodeInner::Canceled) { match replace(unsafe { head_nn.as_mut() }, NodeInner::Canceled) {
@ -487,6 +509,8 @@ mod internal {
// Cancel all item nodes in the chain, waking each stored `Waker`. // Cancel all item nodes in the chain, waking each stored `Waker`.
while item_nn != head_nn { while item_nn != head_nn {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
match replace(unsafe { item_nn.as_mut() }, NodeInner::Canceled) { match replace(unsafe { item_nn.as_mut() }, NodeInner::Canceled) {
NodeInner::Linked { NodeInner::Linked {
kind: NodeKind::Item { waker }, kind: NodeKind::Item { waker },
@ -745,6 +769,7 @@ mod tests {
assert!(Rc::get_mut(&mut cancel_handle).is_some()); assert!(Rc::get_mut(&mut cancel_handle).is_some());
let mut future = pending::<Never>().or_cancel(&cancel_handle); let mut future = pending::<Never>().or_cancel(&cancel_handle);
// SAFETY: `Cancelable` pins the future
let future = unsafe { Pin::new_unchecked(&mut future) }; let future = unsafe { Pin::new_unchecked(&mut future) };
// There are two `Rc<CancelHandle>` references now, so this fails. // There are two `Rc<CancelHandle>` references now, so this fails.

View file

@ -157,12 +157,16 @@ impl<T: 'static> RcRef<T> {
map_fn: F, map_fn: F,
) -> RcRef<T> { ) -> RcRef<T> {
let RcRef::<S> { rc, value } = source.into(); let RcRef::<S> { rc, value } = source.into();
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let value = map_fn(unsafe { &*value }); let value = map_fn(unsafe { &*value });
RcRef { rc, value } RcRef { rc, value }
} }
pub(crate) fn split(rc_ref: &Self) -> (&T, &Rc<dyn Any>) { pub(crate) fn split(rc_ref: &Self) -> (&T, &Rc<dyn Any>) {
let &Self { ref rc, value } = rc_ref; let &Self { ref rc, value } = rc_ref;
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
(unsafe { &*value }, rc) (unsafe { &*value }, rc)
} }
} }
@ -206,7 +210,11 @@ impl<T: 'static> From<&Rc<T>> for RcRef<T> {
impl<T> Deref for RcRef<T> { impl<T> Deref for RcRef<T> {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { &*self.value } // TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
&*self.value
}
} }
} }
@ -260,6 +268,8 @@ mod internal {
// Don't allow synchronous borrows to cut in line; if there are any // Don't allow synchronous borrows to cut in line; if there are any
// enqueued waiters, return `None`, even if the current borrow is a shared // enqueued waiters, return `None`, even if the current borrow is a shared
// one and the requested borrow is too. // one and the requested borrow is too.
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *cell_ref.waiters.as_ptr() }; let waiters = unsafe { &mut *cell_ref.waiters.as_ptr() };
if waiters.is_empty() { if waiters.is_empty() {
// There are no enqueued waiters, but it is still possible that the cell // There are no enqueued waiters, but it is still possible that the cell
@ -288,6 +298,8 @@ mod internal {
let waiter = Waiter::new(M::borrow_mode()); let waiter = Waiter::new(M::borrow_mode());
let turn = self.turn.get(); let turn = self.turn.get();
let index = { let index = {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *self.waiters.as_ptr() }; let waiters = unsafe { &mut *self.waiters.as_ptr() };
waiters.push_back(Some(waiter)); waiters.push_back(Some(waiter));
waiters.len() - 1 waiters.len() - 1
@ -315,6 +327,8 @@ mod internal {
Poll::Ready(()) Poll::Ready(())
} else { } else {
// This waiter is still in line and has not yet been woken. // This waiter is still in line and has not yet been woken.
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *self.waiters.as_ptr() }; let waiters = unsafe { &mut *self.waiters.as_ptr() };
// Sanity check: id cannot be higher than the last queue element. // Sanity check: id cannot be higher than the last queue element.
assert!(id < turn + waiters.len()); assert!(id < turn + waiters.len());
@ -330,6 +344,8 @@ mod internal {
fn wake_waiters(&self) { fn wake_waiters(&self) {
let mut borrow_count = self.borrow_count.get(); let mut borrow_count = self.borrow_count.get();
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *self.waiters.as_ptr() }; let waiters = unsafe { &mut *self.waiters.as_ptr() };
let mut turn = self.turn.get(); let mut turn = self.turn.get();
@ -379,6 +395,8 @@ mod internal {
self.drop_borrow::<M>(); self.drop_borrow::<M>();
} else { } else {
// This waiter is still in the queue, take it out and leave a "hole". // This waiter is still in the queue, take it out and leave a "hole".
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *self.waiters.as_ptr() }; let waiters = unsafe { &mut *self.waiters.as_ptr() };
waiters[id - turn].take().unwrap(); waiters[id - turn].take().unwrap();
} }
@ -411,6 +429,8 @@ mod internal {
type Output = AsyncBorrowImpl<T, M>; type Output = AsyncBorrowImpl<T, M>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
ready!(self.cell.as_ref().unwrap().poll_waiter::<M>(self.id, cx)); ready!(self.cell.as_ref().unwrap().poll_waiter::<M>(self.id, cx));
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let self_mut = unsafe { Pin::get_unchecked_mut(self) }; let self_mut = unsafe { Pin::get_unchecked_mut(self) };
let cell = self_mut.cell.take().unwrap(); let cell = self_mut.cell.take().unwrap();
Poll::Ready(AsyncBorrowImpl::<T, M>::new(cell)) Poll::Ready(AsyncBorrowImpl::<T, M>::new(cell))
@ -448,7 +468,11 @@ mod internal {
impl<T, M: BorrowModeTrait> Deref for AsyncBorrowImpl<T, M> { impl<T, M: BorrowModeTrait> Deref for AsyncBorrowImpl<T, M> {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
unsafe { &*self.cell.as_ptr() } // TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
&*self.cell.as_ptr()
}
} }
} }
@ -466,7 +490,11 @@ mod internal {
impl<T> DerefMut for AsyncBorrowImpl<T, Exclusive> { impl<T> DerefMut for AsyncBorrowImpl<T, Exclusive> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.cell.as_ptr() } // TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
&mut *self.cell.as_ptr()
}
} }
} }

View file

@ -147,6 +147,7 @@ pub extern "C" fn host_import_module_dynamically_callback(
specifier: v8::Local<v8::String>, specifier: v8::Local<v8::String>,
import_assertions: v8::Local<v8::FixedArray>, import_assertions: v8::Local<v8::FixedArray>,
) -> *mut v8::Promise { ) -> *mut v8::Promise {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) }; let scope = &mut unsafe { v8::CallbackScope::new(context) };
// NOTE(bartlomieju): will crash for non-UTF-8 specifier // NOTE(bartlomieju): will crash for non-UTF-8 specifier
@ -253,6 +254,7 @@ pub extern "C" fn host_initialize_import_meta_object_callback(
module: v8::Local<v8::Module>, module: v8::Local<v8::Module>,
meta: v8::Local<v8::Object>, meta: v8::Local<v8::Object>,
) { ) {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) }; let scope = &mut unsafe { v8::CallbackScope::new(context) };
let module_map_rc = JsRuntime::module_map(scope); let module_map_rc = JsRuntime::module_map(scope);
let module_map = module_map_rc.borrow(); let module_map = module_map_rc.borrow();
@ -274,6 +276,7 @@ pub extern "C" fn host_initialize_import_meta_object_callback(
pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) { pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) {
use v8::PromiseRejectEvent::*; use v8::PromiseRejectEvent::*;
// SAFETY: `CallbackScope` can be safely constructed from `&PromiseRejectMessage`
let scope = &mut unsafe { v8::CallbackScope::new(&message) }; let scope = &mut unsafe { v8::CallbackScope::new(&message) };
let state_rc = JsRuntime::state(scope); let state_rc = JsRuntime::state(scope);
@ -418,6 +421,7 @@ pub fn module_resolve_callback<'s>(
import_assertions: v8::Local<'s, v8::FixedArray>, import_assertions: v8::Local<'s, v8::FixedArray>,
referrer: v8::Local<'s, v8::Module>, referrer: v8::Local<'s, v8::Module>,
) -> Option<v8::Local<'s, v8::Module>> { ) -> Option<v8::Local<'s, v8::Module>> {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) }; let scope = &mut unsafe { v8::CallbackScope::new(context) };
let module_map_rc = JsRuntime::module_map(scope); let module_map_rc = JsRuntime::module_map(scope);

View file

@ -485,6 +485,8 @@ impl task::ArcWake for InspectorWaker {
_isolate: &mut v8::Isolate, _isolate: &mut v8::Isolate,
arg: *mut c_void, arg: *mut c_void,
) { ) {
// SAFETY: `InspectorWaker` is owned by `JsRuntimeInspector`, so the
// pointer to the latter is valid as long as waker is alive.
let inspector = unsafe { &*(arg as *mut JsRuntimeInspector) }; let inspector = unsafe { &*(arg as *mut JsRuntimeInspector) };
let _ = inspector.poll_sessions(None); let _ = inspector.poll_sessions(None);
} }
@ -521,6 +523,8 @@ impl InspectorSession {
let v8_channel = v8::inspector::ChannelBase::new::<Self>(); let v8_channel = v8::inspector::ChannelBase::new::<Self>();
let mut v8_inspector = v8_inspector_rc.borrow_mut(); let mut v8_inspector = v8_inspector_rc.borrow_mut();
let v8_inspector_ptr = v8_inspector.as_mut().unwrap(); let v8_inspector_ptr = v8_inspector.as_mut().unwrap();
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let v8_session = v8_inspector_ptr.connect( let v8_session = v8_inspector_ptr.connect(
Self::CONTEXT_GROUP_ID, Self::CONTEXT_GROUP_ID,
// Todo(piscisaureus): V8Inspector::connect() should require that // Todo(piscisaureus): V8Inspector::connect() should require that
@ -544,6 +548,8 @@ impl InspectorSession {
msg: String, msg: String,
) { ) {
let msg = v8::inspector::StringView::from(msg.as_bytes()); let msg = v8::inspector::StringView::from(msg.as_bytes());
// SAFETY: `InspectorSession` is the only owner of `v8_session_ptr`, so
// the pointer is valid for as long the struct.
unsafe { unsafe {
(*v8_session_ptr).dispatch_protocol_message(msg); (*v8_session_ptr).dispatch_protocol_message(msg);
}; };
@ -731,6 +737,9 @@ impl LocalInspectorSession {
fn new_box_with<T>(new_fn: impl FnOnce(*mut T) -> T) -> Box<T> { fn new_box_with<T>(new_fn: impl FnOnce(*mut T) -> T) -> Box<T> {
let b = Box::new(MaybeUninit::<T>::uninit()); let b = Box::new(MaybeUninit::<T>::uninit());
let p = Box::into_raw(b) as *mut T; let p = Box::into_raw(b) as *mut T;
unsafe { ptr::write(p, new_fn(p)) }; // SAFETY: memory layout for `T` is ensured on first line of this function
unsafe { Box::from_raw(p) } unsafe {
ptr::write(p, new_fn(p));
Box::from_raw(p)
}
} }

View file

@ -122,6 +122,7 @@ fn json_module_evaluation_steps<'a>(
context: v8::Local<'a, v8::Context>, context: v8::Local<'a, v8::Context>,
module: v8::Local<v8::Module>, module: v8::Local<v8::Module>,
) -> Option<v8::Local<'a, v8::Value>> { ) -> Option<v8::Local<'a, v8::Value>> {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) }; let scope = &mut unsafe { v8::CallbackScope::new(context) };
let tc_scope = &mut v8::TryCatch::new(scope); let tc_scope = &mut v8::TryCatch::new(scope);
let module_map = tc_scope let module_map = tc_scope

View file

@ -63,6 +63,8 @@ impl<T> Future for OpCall<T> {
self: std::pin::Pin<&mut Self>, self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>, cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> { ) -> std::task::Poll<Self::Output> {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let inner = unsafe { &mut self.get_unchecked_mut().0 }; let inner = unsafe { &mut self.get_unchecked_mut().0 };
let mut pinned = Pin::new(inner); let mut pinned = Pin::new(inner);
ready!(pinned.as_mut().poll(cx)); ready!(pinned.as_mut().poll(cx));

View file

@ -56,12 +56,17 @@ impl OpsTracker {
#[allow(clippy::mut_from_ref)] #[allow(clippy::mut_from_ref)]
#[inline] #[inline]
fn ops_mut(&self) -> &mut Vec<OpMetrics> { fn ops_mut(&self) -> &mut Vec<OpMetrics> {
// SAFETY: `OpsTracker` is created after registering ops so it is guaranteed
// that that `ops` will be initialized.
unsafe { &mut *self.ops.get() } unsafe { &mut *self.ops.get() }
} }
#[allow(clippy::mut_from_ref)] #[allow(clippy::mut_from_ref)]
#[inline] #[inline]
fn metrics_mut(&self, id: OpId) -> &mut OpMetrics { fn metrics_mut(&self, id: OpId) -> &mut OpMetrics {
// SAFETY: `OpsTracker` is created after registering ops, and ops
// cannot be unregistered during runtime, so it is guaranteed that `id`
// is not causing out-of-bound access.
unsafe { self.ops_mut().get_unchecked_mut(id) } unsafe { self.ops_mut().get_unchecked_mut(id) }
} }

View file

@ -77,6 +77,8 @@ impl dyn Resource {
pub fn downcast_rc<'a, T: Resource>(self: &'a Rc<Self>) -> Option<&'a Rc<T>> { pub fn downcast_rc<'a, T: Resource>(self: &'a Rc<Self>) -> Option<&'a Rc<T>> {
if self.is::<T>() { if self.is::<T>() {
let ptr = self as *const Rc<_> as *const Rc<T>; let ptr = self as *const Rc<_> as *const Rc<T>;
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
Some(unsafe { &*ptr }) Some(unsafe { &*ptr })
} else { } else {
None None

View file

@ -333,6 +333,9 @@ impl JsRuntime {
assert!(options.startup_snapshot.is_none()); assert!(options.startup_snapshot.is_none());
let mut creator = let mut creator =
v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES)); v8::SnapshotCreator::new(Some(&bindings::EXTERNAL_REFERENCES));
// SAFETY: `get_owned_isolate` is unsafe because it may only be called
// once. This is the only place we call this function, so this call is
// safe.
let isolate = unsafe { creator.get_owned_isolate() }; let isolate = unsafe { creator.get_owned_isolate() };
let mut isolate = JsRuntime::setup_isolate(isolate); let mut isolate = JsRuntime::setup_isolate(isolate);
{ {
@ -1028,6 +1031,8 @@ extern "C" fn near_heap_limit_callback<F>(
where where
F: FnMut(usize, usize) -> usize, F: FnMut(usize, usize) -> usize,
{ {
// SAFETY: The data is a pointer to the Rust callback function. It is stored
// in `JsRuntime::allocations` and thus is guaranteed to outlive the isolate.
let callback = unsafe { &mut *(data as *mut F) }; let callback = unsafe { &mut *(data as *mut F) };
callback(current_heap_limit, initial_heap_limit) callback(current_heap_limit, initial_heap_limit)
} }

View file

@ -130,6 +130,8 @@ impl DynamicLibraryResource {
// By default, Err returned by this function does not tell // By default, Err returned by this function does not tell
// which symbol wasn't exported. So we'll modify the error // which symbol wasn't exported. So we'll modify the error
// message to include the name of symbol. // message to include the name of symbol.
//
// SAFETY: The obtained T symbol is the size of a pointer.
let fn_ptr = match unsafe { self.lib.symbol::<*const c_void>(symbol) } { let fn_ptr = match unsafe { self.lib.symbol::<*const c_void>(symbol) } {
Ok(value) => Ok(value), Ok(value) => Ok(value),
Err(err) => Err(generic_error(format!( Err(err) => Err(generic_error(format!(
@ -164,6 +166,8 @@ impl DynamicLibraryResource {
// By default, Err returned by this function does not tell // By default, Err returned by this function does not tell
// which symbol wasn't exported. So we'll modify the error // which symbol wasn't exported. So we'll modify the error
// message to include the name of symbol. // message to include the name of symbol.
//
// SAFETY: The obtained T symbol is the size of a pointer.
match unsafe { self.lib.symbol::<*const c_void>(&symbol) } { match unsafe { self.lib.symbol::<*const c_void>(&symbol) } {
Ok(value) => Ok(Ok(value)), Ok(value) => Ok(Ok(value)),
Err(err) => Err(generic_error(format!( Err(err) => Err(generic_error(format!(
@ -743,55 +747,60 @@ fn ffi_call(
let call_args: Vec<Arg> = call_args let call_args: Vec<Arg> = call_args
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, ffi_arg)| unsafe { .map(|(index, ffi_arg)| {
ffi_arg.as_arg(*parameter_types.get(index).unwrap()) // SAFETY: the union field is initialized
unsafe { ffi_arg.as_arg(*parameter_types.get(index).unwrap()) }
}) })
.collect(); .collect();
// SAFETY: types in the `Cif` match the actual calling convention and
// types of symbol.
unsafe {
Ok(match result_type { Ok(match result_type {
NativeType::Void => NativeValue { NativeType::Void => NativeValue {
void_value: unsafe { cif.call::<()>(fun_ptr, &call_args) }, void_value: cif.call::<()>(fun_ptr, &call_args),
}, },
NativeType::U8 => NativeValue { NativeType::U8 => NativeValue {
u8_value: unsafe { cif.call::<u8>(fun_ptr, &call_args) }, u8_value: cif.call::<u8>(fun_ptr, &call_args),
}, },
NativeType::I8 => NativeValue { NativeType::I8 => NativeValue {
i8_value: unsafe { cif.call::<i8>(fun_ptr, &call_args) }, i8_value: cif.call::<i8>(fun_ptr, &call_args),
}, },
NativeType::U16 => NativeValue { NativeType::U16 => NativeValue {
u16_value: unsafe { cif.call::<u16>(fun_ptr, &call_args) }, u16_value: cif.call::<u16>(fun_ptr, &call_args),
}, },
NativeType::I16 => NativeValue { NativeType::I16 => NativeValue {
i16_value: unsafe { cif.call::<i16>(fun_ptr, &call_args) }, i16_value: cif.call::<i16>(fun_ptr, &call_args),
}, },
NativeType::U32 => NativeValue { NativeType::U32 => NativeValue {
u32_value: unsafe { cif.call::<u32>(fun_ptr, &call_args) }, u32_value: cif.call::<u32>(fun_ptr, &call_args),
}, },
NativeType::I32 => NativeValue { NativeType::I32 => NativeValue {
i32_value: unsafe { cif.call::<i32>(fun_ptr, &call_args) }, i32_value: cif.call::<i32>(fun_ptr, &call_args),
}, },
NativeType::U64 => NativeValue { NativeType::U64 => NativeValue {
u64_value: unsafe { cif.call::<u64>(fun_ptr, &call_args) }, u64_value: cif.call::<u64>(fun_ptr, &call_args),
}, },
NativeType::I64 => NativeValue { NativeType::I64 => NativeValue {
i64_value: unsafe { cif.call::<i64>(fun_ptr, &call_args) }, i64_value: cif.call::<i64>(fun_ptr, &call_args),
}, },
NativeType::USize => NativeValue { NativeType::USize => NativeValue {
usize_value: unsafe { cif.call::<usize>(fun_ptr, &call_args) }, usize_value: cif.call::<usize>(fun_ptr, &call_args),
}, },
NativeType::ISize => NativeValue { NativeType::ISize => NativeValue {
isize_value: unsafe { cif.call::<isize>(fun_ptr, &call_args) }, isize_value: cif.call::<isize>(fun_ptr, &call_args),
}, },
NativeType::F32 => NativeValue { NativeType::F32 => NativeValue {
f32_value: unsafe { cif.call::<f32>(fun_ptr, &call_args) }, f32_value: cif.call::<f32>(fun_ptr, &call_args),
}, },
NativeType::F64 => NativeValue { NativeType::F64 => NativeValue {
f64_value: unsafe { cif.call::<f64>(fun_ptr, &call_args) }, f64_value: cif.call::<f64>(fun_ptr, &call_args),
}, },
NativeType::Pointer | NativeType::Function => NativeValue { NativeType::Pointer | NativeType::Function => NativeValue {
pointer: unsafe { cif.call::<*const u8>(fun_ptr, &call_args) }, pointer: cif.call::<*const u8>(fun_ptr, &call_args),
}, },
}) })
}
} }
struct UnsafeCallbackResource { struct UnsafeCallbackResource {
@ -1201,71 +1210,83 @@ fn op_ffi_get_static<'scope>(
return Err(type_error("Invalid FFI static type 'void'")); return Err(type_error("Invalid FFI static type 'void'"));
} }
NativeType::U8 => { NativeType::U8 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result as u32).into(); v8::Integer::new_from_unsigned(scope, result as u32).into();
number.into() number.into()
} }
NativeType::I8 => { NativeType::I8 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i8) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const i8) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Integer::new(scope, result as i32).into(); v8::Integer::new(scope, result as i32).into();
number.into() number.into()
} }
NativeType::U16 => { NativeType::U16 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u16) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const u16) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result as u32).into(); v8::Integer::new_from_unsigned(scope, result as u32).into();
number.into() number.into()
} }
NativeType::I16 => { NativeType::I16 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i16) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const i16) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Integer::new(scope, result as i32).into(); v8::Integer::new(scope, result as i32).into();
number.into() number.into()
} }
NativeType::U32 => { NativeType::U32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u32) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const u32) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result).into(); v8::Integer::new_from_unsigned(scope, result).into();
number.into() number.into()
} }
NativeType::I32 => { NativeType::I32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i32) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const i32) };
let number: v8::Local<v8::Value> = v8::Integer::new(scope, result).into(); let number: v8::Local<v8::Value> = v8::Integer::new(scope, result).into();
number.into() number.into()
} }
NativeType::U64 => { NativeType::U64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) };
let big_int: v8::Local<v8::Value> = let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_u64(scope, result).into(); v8::BigInt::new_from_u64(scope, result).into();
big_int.into() big_int.into()
} }
NativeType::I64 => { NativeType::I64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) };
let big_int: v8::Local<v8::Value> = let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_i64(scope, result).into(); v8::BigInt::new_from_i64(scope, result).into();
big_int.into() big_int.into()
} }
NativeType::USize => { NativeType::USize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) };
let big_int: v8::Local<v8::Value> = let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_u64(scope, result as u64).into(); v8::BigInt::new_from_u64(scope, result as u64).into();
big_int.into() big_int.into()
} }
NativeType::ISize => { NativeType::ISize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) };
let big_int: v8::Local<v8::Value> = let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_i64(scope, result as i64).into(); v8::BigInt::new_from_i64(scope, result as i64).into();
big_int.into() big_int.into()
} }
NativeType::F32 => { NativeType::F32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const f32) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const f32) };
let number: v8::Local<v8::Value> = let number: v8::Local<v8::Value> =
v8::Number::new(scope, result as f64).into(); v8::Number::new(scope, result as f64).into();
number.into() number.into()
} }
NativeType::F64 => { NativeType::F64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const f64) }; let result = unsafe { ptr::read_unaligned(data_ptr as *const f64) };
let number: v8::Local<v8::Value> = v8::Number::new(scope, result).into(); let number: v8::Local<v8::Value> = v8::Number::new(scope, result).into();
number.into() number.into()
@ -1339,7 +1360,7 @@ fn op_ffi_call_nonblocking<'scope>(
cif, cif,
ptr, ptr,
parameter_types, parameter_types,
.. result_type,
} = symbol.clone(); } = symbol.clone();
ffi_call(call_args, &cif, ptr, &parameter_types, result_type) ffi_call(call_args, &cif, ptr, &parameter_types, result_type)
}); });
@ -1392,6 +1413,8 @@ where
)) ))
} else { } else {
let src = src as *const u8; let src = src as *const u8;
// SAFETY: src is user defined.
// dest is properly aligned and is valid for writes of len * size_of::<T>() bytes.
unsafe { ptr::copy(src, dst.as_mut_ptr(), len) }; unsafe { ptr::copy(src, dst.as_mut_ptr(), len) };
Ok(()) Ok(())
} }
@ -1411,6 +1434,8 @@ where
permissions.check(None)?; permissions.check(None)?;
let ptr = ptr as *const c_char; let ptr = ptr as *const c_char;
// SAFETY: ptr is user provided
// lifetime validity is not an issue because we allocate a new string.
Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string()) Ok(unsafe { CStr::from_ptr(ptr) }.to_str()?.to_string())
} }
@ -1427,6 +1452,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u8) }) Ok(unsafe { ptr::read_unaligned(ptr as *const u8) })
} }
@ -1443,6 +1469,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i8) }) Ok(unsafe { ptr::read_unaligned(ptr as *const i8) })
} }
@ -1459,6 +1486,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u16) }) Ok(unsafe { ptr::read_unaligned(ptr as *const u16) })
} }
@ -1475,6 +1503,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i16) }) Ok(unsafe { ptr::read_unaligned(ptr as *const i16) })
} }
@ -1491,6 +1520,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u32) }) Ok(unsafe { ptr::read_unaligned(ptr as *const u32) })
} }
@ -1507,6 +1537,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i32) }) Ok(unsafe { ptr::read_unaligned(ptr as *const i32) })
} }
@ -1525,6 +1556,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
let result = unsafe { ptr::read_unaligned(ptr as *const u64) }; let result = unsafe { ptr::read_unaligned(ptr as *const u64) };
let big_int: v8::Local<v8::Value> = let big_int: v8::Local<v8::Value> =
@ -1545,6 +1577,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const f32) }) Ok(unsafe { ptr::read_unaligned(ptr as *const f32) })
} }
@ -1561,6 +1594,7 @@ where
let permissions = state.borrow_mut::<FP>(); let permissions = state.borrow_mut::<FP>();
permissions.check(None)?; permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const f64) }) Ok(unsafe { ptr::read_unaligned(ptr as *const f64) })
} }

View file

@ -375,11 +375,17 @@ impl TlsStreamInner {
ready!(self.poll_io(cx, Flow::Read))?; ready!(self.poll_io(cx, Flow::Read))?;
if self.rd_state == State::StreamOpen { if self.rd_state == State::StreamOpen {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let buf_slice = let buf_slice =
unsafe { &mut *(buf.unfilled_mut() as *mut [_] as *mut [u8]) }; unsafe { &mut *(buf.unfilled_mut() as *mut [_] as *mut [u8]) };
let bytes_read = self.tls.reader().read(buf_slice)?; let bytes_read = self.tls.reader().read(buf_slice)?;
assert_ne!(bytes_read, 0); assert_ne!(bytes_read, 0);
unsafe { buf.assume_init(bytes_read) }; // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
buf.assume_init(bytes_read)
};
buf.advance(bytes_read); buf.advance(bytes_read);
} }
@ -581,10 +587,16 @@ impl Shared {
let self_weak = Arc::downgrade(self); let self_weak = Arc::downgrade(self);
let self_ptr = self_weak.into_raw() as *const (); let self_ptr = self_weak.into_raw() as *const ();
let raw_waker = RawWaker::new(self_ptr, &Self::SHARED_WAKER_VTABLE); let raw_waker = RawWaker::new(self_ptr, &Self::SHARED_WAKER_VTABLE);
unsafe { Waker::from_raw(raw_waker) } // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
Waker::from_raw(raw_waker)
}
} }
fn clone_shared_waker(self_ptr: *const ()) -> RawWaker { fn clone_shared_waker(self_ptr: *const ()) -> RawWaker {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let self_weak = unsafe { Weak::from_raw(self_ptr as *const Self) }; let self_weak = unsafe { Weak::from_raw(self_ptr as *const Self) };
let ptr1 = self_weak.clone().into_raw(); let ptr1 = self_weak.clone().into_raw();
let ptr2 = self_weak.into_raw(); let ptr2 = self_weak.into_raw();
@ -598,6 +610,8 @@ impl Shared {
} }
fn wake_shared_waker_by_ref(self_ptr: *const ()) { fn wake_shared_waker_by_ref(self_ptr: *const ()) {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let self_weak = unsafe { Weak::from_raw(self_ptr as *const Self) }; let self_weak = unsafe { Weak::from_raw(self_ptr as *const Self) };
if let Some(self_arc) = Weak::upgrade(&self_weak) { if let Some(self_arc) = Weak::upgrade(&self_weak) {
self_arc.rd_waker.wake(); self_arc.rd_waker.wake();
@ -607,6 +621,8 @@ impl Shared {
} }
fn drop_shared_waker(self_ptr: *const ()) { fn drop_shared_waker(self_ptr: *const ()) {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let _ = unsafe { Weak::from_raw(self_ptr as *const Self) }; let _ = unsafe { Weak::from_raw(self_ptr as *const Self) };
} }

View file

@ -105,6 +105,8 @@ pub async fn op_webgpu_buffer_get_map_async(
user_data: *mut u8, user_data: *mut u8,
) { ) {
let sender_ptr = user_data as *mut oneshot::Sender<Result<(), AnyError>>; let sender_ptr = user_data as *mut oneshot::Sender<Result<(), AnyError>>;
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let boxed_sender = unsafe { Box::from_raw(sender_ptr) }; let boxed_sender = unsafe { Box::from_raw(sender_ptr) };
boxed_sender boxed_sender
.send(match status { .send(match status {
@ -188,6 +190,8 @@ pub fn op_webgpu_buffer_get_mapped_range(
)) ))
.map_err(|e| DomExceptionOperationError::new(&e.to_string()))?; .map_err(|e| DomExceptionOperationError::new(&e.to_string()))?;
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let slice = unsafe { let slice = unsafe {
std::slice::from_raw_parts_mut(slice_pointer, range_size as usize) std::slice::from_raw_parts_mut(slice_pointer, range_size as usize)
}; };
@ -225,6 +229,8 @@ pub fn op_webgpu_buffer_unmap(
let size = mapped_resource.1; let size = mapped_resource.1;
if let Some(buffer) = zero_copy { if let Some(buffer) = zero_copy {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) }; let slice = unsafe { std::slice::from_raw_parts_mut(slice_pointer, size) };
slice.copy_from_slice(&buffer); slice.copy_from_slice(&buffer);
} }

View file

@ -42,26 +42,35 @@ use {
// alive for the duration of the application since the last handle/fd // alive for the duration of the application since the last handle/fd
// being dropped will close the corresponding pipe. // being dropped will close the corresponding pipe.
#[cfg(unix)] #[cfg(unix)]
static STDIN_HANDLE: Lazy<StdFile> = static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
Lazy::new(|| unsafe { StdFile::from_raw_fd(0) }); // SAFETY: corresponds to OS stdin
unsafe { StdFile::from_raw_fd(0) }
});
#[cfg(unix)] #[cfg(unix)]
static STDOUT_HANDLE: Lazy<StdFile> = static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
Lazy::new(|| unsafe { StdFile::from_raw_fd(1) }); // SAFETY: corresponds to OS stdout
unsafe { StdFile::from_raw_fd(1) }
});
#[cfg(unix)] #[cfg(unix)]
static STDERR_HANDLE: Lazy<StdFile> = static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
Lazy::new(|| unsafe { StdFile::from_raw_fd(2) }); // SAFETY: corresponds to OS stderr
unsafe { StdFile::from_raw_fd(2) }
});
#[cfg(windows)] #[cfg(windows)]
static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe { static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE)) // SAFETY: corresponds to OS stdin
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE)) }
}); });
#[cfg(windows)] #[cfg(windows)]
static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe { static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE)) // SAFETY: corresponds to OS stdout
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE)) }
}); });
#[cfg(windows)] #[cfg(windows)]
static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe { static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE)) // SAFETY: corresponds to OS stderr
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE)) }
}); });
pub fn init() -> Extension { pub fn init() -> Extension {

View file

@ -248,7 +248,11 @@ fn op_system_memory_info(
fn op_getgid(state: &mut OpState) -> Result<Option<u32>, AnyError> { fn op_getgid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
super::check_unstable(state, "Deno.getGid"); super::check_unstable(state, "Deno.getGid");
state.borrow_mut::<Permissions>().env.check_all()?; state.borrow_mut::<Permissions>().env.check_all()?;
unsafe { Ok(Some(libc::getgid())) } // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
Ok(Some(libc::getgid()))
}
} }
#[cfg(windows)] #[cfg(windows)]
@ -264,7 +268,11 @@ fn op_getgid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
fn op_getuid(state: &mut OpState) -> Result<Option<u32>, AnyError> { fn op_getuid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
super::check_unstable(state, "Deno.getUid"); super::check_unstable(state, "Deno.getUid");
state.borrow_mut::<Permissions>().env.check_all()?; state.borrow_mut::<Permissions>().env.check_all()?;
unsafe { Ok(Some(libc::getuid())) } // TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
Ok(Some(libc::getuid()))
}
} }
#[cfg(windows)] #[cfg(windows)]

View file

@ -174,6 +174,8 @@ fn op_run(state: &mut OpState, run_args: RunArgs) -> Result<RunInfo, AnyError> {
c.uid(uid); c.uid(uid);
} }
#[cfg(unix)] #[cfg(unix)]
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { unsafe {
c.pre_exec(|| { c.pre_exec(|| {
libc::setgroups(0, std::ptr::null()); libc::setgroups(0, std::ptr::null());

View file

@ -149,6 +149,8 @@ fn create_command(
command.uid(uid); command.uid(uid);
} }
#[cfg(unix)] #[cfg(unix)]
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { unsafe {
command.pre_exec(|| { command.pre_exec(|| {
libc::setgroups(0, std::ptr::null()); libc::setgroups(0, std::ptr::null());

View file

@ -172,12 +172,16 @@ fn op_isatty(state: &mut OpState, rid: ResourceId) -> Result<bool, AnyError> {
let handle = get_windows_handle(std_file)?; let handle = get_windows_handle(std_file)?;
let mut test_mode: DWORD = 0; let mut test_mode: DWORD = 0;
// If I cannot get mode out of console, it is not a console. // If I cannot get mode out of console, it is not a console.
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
Ok(unsafe { consoleapi::GetConsoleMode(handle, &mut test_mode) != FALSE }) Ok(unsafe { consoleapi::GetConsoleMode(handle, &mut test_mode) != FALSE })
} }
#[cfg(unix)] #[cfg(unix)]
{ {
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
let raw_fd = std_file.as_raw_fd(); let raw_fd = std_file.as_raw_fd();
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
Ok(unsafe { libc::isatty(raw_fd as libc::c_int) == 1 }) Ok(unsafe { libc::isatty(raw_fd as libc::c_int) == 1 })
} }
})?; })?;
@ -225,6 +229,8 @@ fn op_console_size(
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
let fd = std_file.as_raw_fd(); let fd = std_file.as_raw_fd();
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe { unsafe {
let mut size: libc::winsize = std::mem::zeroed(); let mut size: libc::winsize = std::mem::zeroed();
if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 { if libc::ioctl(fd, libc::TIOCGWINSZ, &mut size as *mut _) != 0 {

View file

@ -1886,6 +1886,8 @@ fn permission_prompt(message: &str, name: &str) -> bool {
#[cfg(unix)] #[cfg(unix)]
fn clear_stdin() -> Result<(), AnyError> { fn clear_stdin() -> Result<(), AnyError> {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let r = unsafe { libc::tcflush(0, libc::TCIFLUSH) }; let r = unsafe { libc::tcflush(0, libc::TCIFLUSH) };
assert_eq!(r, 0); assert_eq!(r, 0);
Ok(()) Ok(())

View file

@ -52,6 +52,8 @@ fn main() {
println!("x = {}", x); println!("x = {}", x);
} }
// SAFETY: all isolates have been destroyed, so we can now safely let V8 clean
// up its resources.
unsafe { unsafe {
v8::V8::dispose(); v8::V8::dispose();
} }

View file

@ -87,8 +87,10 @@ mod tests {
#[test] #[test]
fn bytes_layout() { fn bytes_layout() {
// SAFETY: ensuring layout is the same
let u1: [usize; 4] = let u1: [usize; 4] =
unsafe { mem::transmute(from_static(HELLO.as_bytes())) }; unsafe { mem::transmute(from_static(HELLO.as_bytes())) };
// SAFETY: ensuring layout is the same
let u2: [usize; 4] = let u2: [usize; 4] =
unsafe { mem::transmute(bytes::Bytes::from_static(HELLO.as_bytes())) }; unsafe { mem::transmute(bytes::Bytes::from_static(HELLO.as_bytes())) };
assert_eq!(u1[..3], u2[..3]); // Struct bytes are equal besides Vtables assert_eq!(u1[..3], u2[..3]); // Struct bytes are equal besides Vtables

View file

@ -97,6 +97,8 @@ impl<T: serde::Serialize + 'static> From<T> for SerializablePkg {
fn from(x: T) -> Self { fn from(x: T) -> Self {
#[inline(always)] #[inline(always)]
fn tc<T, U>(src: T) -> U { fn tc<T, U>(src: T) -> U {
// SAFETY: the caller has ensured via the TypeId that the T and U types
// are the same.
let x = unsafe { transmute_copy(&src) }; let x = unsafe { transmute_copy(&src) };
std::mem::forget(src); std::mem::forget(src);
x x

View file

@ -17,6 +17,7 @@ pub fn v8_init() {
} }
pub fn v8_shutdown() { pub fn v8_shutdown() {
// SAFETY: this is safe, because all isolates have been shut down already.
unsafe { unsafe {
v8::V8::dispose(); v8::V8::dispose();
} }

View file

@ -1,5 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
#![allow(clippy::undocumented_unsafe_blocks)]
use std::os::raw::c_void; use std::os::raw::c_void;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
@ -11,23 +13,29 @@ pub extern "C" fn print_something() {
println!("something"); println!("something");
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)] /// # Safety
///
/// The pointer to the buffer must be valid and initalized, and the length must
/// not be longer than the buffer's allocation.
#[no_mangle] #[no_mangle]
pub extern "C" fn print_buffer(ptr: *const u8, len: usize) { pub unsafe extern "C" fn print_buffer(ptr: *const u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; let buf = std::slice::from_raw_parts(ptr, len);
println!("{:?}", buf); println!("{:?}", buf);
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)] /// # Safety
///
/// The pointer to the buffer must be valid and initalized, and the length must
/// not be longer than the buffer's allocation.
#[no_mangle] #[no_mangle]
pub extern "C" fn print_buffer2( pub unsafe extern "C" fn print_buffer2(
ptr1: *const u8, ptr1: *const u8,
len1: usize, len1: usize,
ptr2: *const u8, ptr2: *const u8,
len2: usize, len2: usize,
) { ) {
let buf1 = unsafe { std::slice::from_raw_parts(ptr1, len1) }; let buf1 = std::slice::from_raw_parts(ptr1, len1);
let buf2 = unsafe { std::slice::from_raw_parts(ptr2, len2) }; let buf2 = std::slice::from_raw_parts(ptr2, len2);
println!("{:?} {:?}", buf1, buf2); println!("{:?} {:?}", buf1, buf2);
} }
@ -87,19 +95,25 @@ pub extern "C" fn sleep_blocking(ms: u64) {
sleep(duration); sleep(duration);
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)] /// # Safety
///
/// The pointer to the buffer must be valid and initalized, and the length must
/// not be longer than the buffer's allocation.
#[no_mangle] #[no_mangle]
pub extern "C" fn fill_buffer(value: u8, buf: *mut u8, len: usize) { pub unsafe extern "C" fn fill_buffer(value: u8, buf: *mut u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) }; let buf = std::slice::from_raw_parts_mut(buf, len);
for itm in buf.iter_mut() { for itm in buf.iter_mut() {
*itm = value; *itm = value;
} }
} }
#[allow(clippy::not_unsafe_ptr_arg_deref)] /// # Safety
///
/// The pointer to the buffer must be valid and initalized, and the length must
/// not be longer than the buffer's allocation.
#[no_mangle] #[no_mangle]
pub extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) { pub unsafe extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; let buf = std::slice::from_raw_parts(ptr, len);
assert_eq!(buf, vec![1, 2, 3, 4, 5, 6, 7, 8]); assert_eq!(buf, vec![1, 2, 3, 4, 5, 6, 7, 8]);
} }

View file

@ -116,6 +116,10 @@ async function clippy() {
"clippy::all", "clippy::all",
"-D", "-D",
"clippy::await_holding_refcell_ref", "clippy::await_holding_refcell_ref",
"-D",
"clippy::missing_safety_doc",
"-D",
"clippy::undocumented_unsafe_blocks",
], ],
stdout: "inherit", stdout: "inherit",
stderr: "inherit", stderr: "inherit",