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 {
static mut NEXT_PORT: u16 = 4544;
let port = unsafe { NEXT_PORT };
unsafe {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let port = unsafe {
let p = NEXT_PORT;
NEXT_PORT += 1;
}
p
};
port
}

View file

@ -76,7 +76,13 @@ mod dirs {
pub fn home_dir() -> Option<PathBuf> {
std::env::var_os("HOME")
.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)
}

View file

@ -21,7 +21,11 @@ pub fn set_lsp_log_level(level: log::Level) {
pub fn lsp_log_level() -> log::Level {
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

View file

@ -20,6 +20,8 @@ pub fn start(parent_process_id: u32) {
#[cfg(unix)]
fn is_process_active(process_id: u32) -> bool {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
// signal of 0 checks for the existence of the process id
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`.
pub fn raise_fd_limit() {
#[cfg(unix)]
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
let mut limits = libc::rlimit {
rlim_cur: 0,

View file

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

View file

@ -157,12 +157,16 @@ impl<T: 'static> RcRef<T> {
map_fn: F,
) -> RcRef<T> {
let RcRef::<S> { rc, value } = source.into();
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let value = map_fn(unsafe { &*value });
RcRef { rc, value }
}
pub(crate) fn split(rc_ref: &Self) -> (&T, &Rc<dyn Any>) {
let &Self { ref rc, value } = rc_ref;
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
(unsafe { &*value }, rc)
}
}
@ -206,7 +210,11 @@ impl<T: 'static> From<&Rc<T>> for RcRef<T> {
impl<T> Deref for RcRef<T> {
type Target = T;
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
// enqueued waiters, return `None`, even if the current borrow is a shared
// 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() };
if waiters.is_empty() {
// 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 turn = self.turn.get();
let index = {
// TODO(piscisaureus): safety comment
#[allow(clippy::undocumented_unsafe_blocks)]
let waiters = unsafe { &mut *self.waiters.as_ptr() };
waiters.push_back(Some(waiter));
waiters.len() - 1
@ -315,6 +327,8 @@ mod internal {
Poll::Ready(())
} else {
// 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() };
// Sanity check: id cannot be higher than the last queue element.
assert!(id < turn + waiters.len());
@ -330,6 +344,8 @@ mod internal {
fn wake_waiters(&self) {
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 mut turn = self.turn.get();
@ -379,6 +395,8 @@ mod internal {
self.drop_borrow::<M>();
} else {
// 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() };
waiters[id - turn].take().unwrap();
}
@ -411,6 +429,8 @@ mod internal {
type Output = AsyncBorrowImpl<T, M>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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 cell = self_mut.cell.take().unwrap();
Poll::Ready(AsyncBorrowImpl::<T, M>::new(cell))
@ -448,7 +468,11 @@ mod internal {
impl<T, M: BorrowModeTrait> Deref for AsyncBorrowImpl<T, M> {
type Target = T;
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> {
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>,
import_assertions: v8::Local<v8::FixedArray>,
) -> *mut v8::Promise {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) };
// 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>,
meta: v8::Local<v8::Object>,
) {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) };
let module_map_rc = JsRuntime::module_map(scope);
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) {
use v8::PromiseRejectEvent::*;
// SAFETY: `CallbackScope` can be safely constructed from `&PromiseRejectMessage`
let scope = &mut unsafe { v8::CallbackScope::new(&message) };
let state_rc = JsRuntime::state(scope);
@ -418,6 +421,7 @@ pub fn module_resolve_callback<'s>(
import_assertions: v8::Local<'s, v8::FixedArray>,
referrer: 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 module_map_rc = JsRuntime::module_map(scope);

View file

@ -485,6 +485,8 @@ impl task::ArcWake for InspectorWaker {
_isolate: &mut v8::Isolate,
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.poll_sessions(None);
}
@ -521,6 +523,8 @@ impl InspectorSession {
let v8_channel = v8::inspector::ChannelBase::new::<Self>();
let mut v8_inspector = v8_inspector_rc.borrow_mut();
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(
Self::CONTEXT_GROUP_ID,
// Todo(piscisaureus): V8Inspector::connect() should require that
@ -544,6 +548,8 @@ impl InspectorSession {
msg: String,
) {
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 {
(*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> {
let b = Box::new(MaybeUninit::<T>::uninit());
let p = Box::into_raw(b) as *mut T;
unsafe { ptr::write(p, new_fn(p)) };
unsafe { Box::from_raw(p) }
// SAFETY: memory layout for `T` is ensured on first line of this function
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>,
module: v8::Local<v8::Module>,
) -> Option<v8::Local<'a, v8::Value>> {
// SAFETY: `CallbackScope` can be safely constructed from `Local<Context>`
let scope = &mut unsafe { v8::CallbackScope::new(context) };
let tc_scope = &mut v8::TryCatch::new(scope);
let module_map = tc_scope

View file

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

View file

@ -56,12 +56,17 @@ impl OpsTracker {
#[allow(clippy::mut_from_ref)]
#[inline]
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() }
}
#[allow(clippy::mut_from_ref)]
#[inline]
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) }
}

View file

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

View file

@ -333,6 +333,9 @@ impl JsRuntime {
assert!(options.startup_snapshot.is_none());
let mut creator =
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 mut isolate = JsRuntime::setup_isolate(isolate);
{
@ -1028,6 +1031,8 @@ extern "C" fn near_heap_limit_callback<F>(
where
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) };
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
// which symbol wasn't exported. So we'll modify the error
// 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) } {
Ok(value) => Ok(value),
Err(err) => Err(generic_error(format!(
@ -164,6 +166,8 @@ impl DynamicLibraryResource {
// By default, Err returned by this function does not tell
// which symbol wasn't exported. So we'll modify the error
// 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) } {
Ok(value) => Ok(Ok(value)),
Err(err) => Err(generic_error(format!(
@ -743,55 +747,60 @@ fn ffi_call(
let call_args: Vec<Arg> = call_args
.iter()
.enumerate()
.map(|(index, ffi_arg)| unsafe {
ffi_arg.as_arg(*parameter_types.get(index).unwrap())
.map(|(index, ffi_arg)| {
// SAFETY: the union field is initialized
unsafe { ffi_arg.as_arg(*parameter_types.get(index).unwrap()) }
})
.collect();
Ok(match result_type {
NativeType::Void => NativeValue {
void_value: unsafe { cif.call::<()>(fun_ptr, &call_args) },
},
NativeType::U8 => NativeValue {
u8_value: unsafe { cif.call::<u8>(fun_ptr, &call_args) },
},
NativeType::I8 => NativeValue {
i8_value: unsafe { cif.call::<i8>(fun_ptr, &call_args) },
},
NativeType::U16 => NativeValue {
u16_value: unsafe { cif.call::<u16>(fun_ptr, &call_args) },
},
NativeType::I16 => NativeValue {
i16_value: unsafe { cif.call::<i16>(fun_ptr, &call_args) },
},
NativeType::U32 => NativeValue {
u32_value: unsafe { cif.call::<u32>(fun_ptr, &call_args) },
},
NativeType::I32 => NativeValue {
i32_value: unsafe { cif.call::<i32>(fun_ptr, &call_args) },
},
NativeType::U64 => NativeValue {
u64_value: unsafe { cif.call::<u64>(fun_ptr, &call_args) },
},
NativeType::I64 => NativeValue {
i64_value: unsafe { cif.call::<i64>(fun_ptr, &call_args) },
},
NativeType::USize => NativeValue {
usize_value: unsafe { cif.call::<usize>(fun_ptr, &call_args) },
},
NativeType::ISize => NativeValue {
isize_value: unsafe { cif.call::<isize>(fun_ptr, &call_args) },
},
NativeType::F32 => NativeValue {
f32_value: unsafe { cif.call::<f32>(fun_ptr, &call_args) },
},
NativeType::F64 => NativeValue {
f64_value: unsafe { cif.call::<f64>(fun_ptr, &call_args) },
},
NativeType::Pointer | NativeType::Function => NativeValue {
pointer: unsafe { cif.call::<*const u8>(fun_ptr, &call_args) },
},
})
// SAFETY: types in the `Cif` match the actual calling convention and
// types of symbol.
unsafe {
Ok(match result_type {
NativeType::Void => NativeValue {
void_value: cif.call::<()>(fun_ptr, &call_args),
},
NativeType::U8 => NativeValue {
u8_value: cif.call::<u8>(fun_ptr, &call_args),
},
NativeType::I8 => NativeValue {
i8_value: cif.call::<i8>(fun_ptr, &call_args),
},
NativeType::U16 => NativeValue {
u16_value: cif.call::<u16>(fun_ptr, &call_args),
},
NativeType::I16 => NativeValue {
i16_value: cif.call::<i16>(fun_ptr, &call_args),
},
NativeType::U32 => NativeValue {
u32_value: cif.call::<u32>(fun_ptr, &call_args),
},
NativeType::I32 => NativeValue {
i32_value: cif.call::<i32>(fun_ptr, &call_args),
},
NativeType::U64 => NativeValue {
u64_value: cif.call::<u64>(fun_ptr, &call_args),
},
NativeType::I64 => NativeValue {
i64_value: cif.call::<i64>(fun_ptr, &call_args),
},
NativeType::USize => NativeValue {
usize_value: cif.call::<usize>(fun_ptr, &call_args),
},
NativeType::ISize => NativeValue {
isize_value: cif.call::<isize>(fun_ptr, &call_args),
},
NativeType::F32 => NativeValue {
f32_value: cif.call::<f32>(fun_ptr, &call_args),
},
NativeType::F64 => NativeValue {
f64_value: cif.call::<f64>(fun_ptr, &call_args),
},
NativeType::Pointer | NativeType::Function => NativeValue {
pointer: cif.call::<*const u8>(fun_ptr, &call_args),
},
})
}
}
struct UnsafeCallbackResource {
@ -1201,71 +1210,83 @@ fn op_ffi_get_static<'scope>(
return Err(type_error("Invalid FFI static type 'void'"));
}
NativeType::U8 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) };
let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result as u32).into();
number.into()
}
NativeType::I8 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i8) };
let number: v8::Local<v8::Value> =
v8::Integer::new(scope, result as i32).into();
number.into()
}
NativeType::U16 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u16) };
let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result as u32).into();
number.into()
}
NativeType::I16 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i16) };
let number: v8::Local<v8::Value> =
v8::Integer::new(scope, result as i32).into();
number.into()
}
NativeType::U32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u32) };
let number: v8::Local<v8::Value> =
v8::Integer::new_from_unsigned(scope, result).into();
number.into()
}
NativeType::I32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i32) };
let number: v8::Local<v8::Value> = v8::Integer::new(scope, result).into();
number.into()
}
NativeType::U64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) };
let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_u64(scope, result).into();
big_int.into()
}
NativeType::I64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) };
let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_i64(scope, result).into();
big_int.into()
}
NativeType::USize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) };
let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_u64(scope, result as u64).into();
big_int.into()
}
NativeType::ISize => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) };
let big_int: v8::Local<v8::Value> =
v8::BigInt::new_from_i64(scope, result as i64).into();
big_int.into()
}
NativeType::F32 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const f32) };
let number: v8::Local<v8::Value> =
v8::Number::new(scope, result as f64).into();
number.into()
}
NativeType::F64 => {
// SAFETY: ptr is user provided
let result = unsafe { ptr::read_unaligned(data_ptr as *const f64) };
let number: v8::Local<v8::Value> = v8::Number::new(scope, result).into();
number.into()
@ -1339,7 +1360,7 @@ fn op_ffi_call_nonblocking<'scope>(
cif,
ptr,
parameter_types,
..
result_type,
} = symbol.clone();
ffi_call(call_args, &cif, ptr, &parameter_types, result_type)
});
@ -1392,6 +1413,8 @@ where
))
} else {
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) };
Ok(())
}
@ -1411,6 +1434,8 @@ where
permissions.check(None)?;
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())
}
@ -1427,6 +1452,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u8) })
}
@ -1443,6 +1469,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i8) })
}
@ -1459,6 +1486,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u16) })
}
@ -1475,6 +1503,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i16) })
}
@ -1491,6 +1520,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const u32) })
}
@ -1507,6 +1537,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const i32) })
}
@ -1525,6 +1556,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
let result = unsafe { ptr::read_unaligned(ptr as *const u64) };
let big_int: v8::Local<v8::Value> =
@ -1545,6 +1577,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const f32) })
}
@ -1561,6 +1594,7 @@ where
let permissions = state.borrow_mut::<FP>();
permissions.check(None)?;
// SAFETY: ptr is user provided.
Ok(unsafe { ptr::read_unaligned(ptr as *const f64) })
}

View file

@ -375,11 +375,17 @@ impl TlsStreamInner {
ready!(self.poll_io(cx, Flow::Read))?;
if self.rd_state == State::StreamOpen {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let buf_slice =
unsafe { &mut *(buf.unfilled_mut() as *mut [_] as *mut [u8]) };
let bytes_read = self.tls.reader().read(buf_slice)?;
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);
}
@ -581,10 +587,16 @@ impl Shared {
let self_weak = Arc::downgrade(self);
let self_ptr = self_weak.into_raw() as *const ();
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 {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let self_weak = unsafe { Weak::from_raw(self_ptr as *const Self) };
let ptr1 = self_weak.clone().into_raw();
let ptr2 = self_weak.into_raw();
@ -598,6 +610,8 @@ impl Shared {
}
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) };
if let Some(self_arc) = Weak::upgrade(&self_weak) {
self_arc.rd_waker.wake();
@ -607,6 +621,8 @@ impl Shared {
}
fn drop_shared_waker(self_ptr: *const ()) {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
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,
) {
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) };
boxed_sender
.send(match status {
@ -188,6 +190,8 @@ pub fn op_webgpu_buffer_get_mapped_range(
))
.map_err(|e| DomExceptionOperationError::new(&e.to_string()))?;
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let slice = unsafe {
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;
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) };
slice.copy_from_slice(&buffer);
}

View file

@ -42,26 +42,35 @@ use {
// alive for the duration of the application since the last handle/fd
// being dropped will close the corresponding pipe.
#[cfg(unix)]
static STDIN_HANDLE: Lazy<StdFile> =
Lazy::new(|| unsafe { StdFile::from_raw_fd(0) });
static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stdin
unsafe { StdFile::from_raw_fd(0) }
});
#[cfg(unix)]
static STDOUT_HANDLE: Lazy<StdFile> =
Lazy::new(|| unsafe { StdFile::from_raw_fd(1) });
static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stdout
unsafe { StdFile::from_raw_fd(1) }
});
#[cfg(unix)]
static STDERR_HANDLE: Lazy<StdFile> =
Lazy::new(|| unsafe { StdFile::from_raw_fd(2) });
static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stderr
unsafe { StdFile::from_raw_fd(2) }
});
#[cfg(windows)]
static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE))
static STDIN_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stdin
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_INPUT_HANDLE)) }
});
#[cfg(windows)]
static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE))
static STDOUT_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stdout
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_OUTPUT_HANDLE)) }
});
#[cfg(windows)]
static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| unsafe {
StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE))
static STDERR_HANDLE: Lazy<StdFile> = Lazy::new(|| {
// SAFETY: corresponds to OS stderr
unsafe { StdFile::from_raw_handle(GetStdHandle(winbase::STD_ERROR_HANDLE)) }
});
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> {
super::check_unstable(state, "Deno.getGid");
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)]
@ -264,7 +268,11 @@ fn op_getgid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
fn op_getuid(state: &mut OpState) -> Result<Option<u32>, AnyError> {
super::check_unstable(state, "Deno.getUid");
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)]

View file

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

View file

@ -149,6 +149,8 @@ fn create_command(
command.uid(uid);
}
#[cfg(unix)]
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
command.pre_exec(|| {
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 mut test_mode: DWORD = 0;
// 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 })
}
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
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 })
}
})?;
@ -225,6 +229,8 @@ fn op_console_size(
use std::os::unix::io::AsRawFd;
let fd = std_file.as_raw_fd();
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
let mut size: libc::winsize = std::mem::zeroed();
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)]
fn clear_stdin() -> Result<(), AnyError> {
// TODO(bartlomieju):
#[allow(clippy::undocumented_unsafe_blocks)]
let r = unsafe { libc::tcflush(0, libc::TCIFLUSH) };
assert_eq!(r, 0);
Ok(())

View file

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

View file

@ -87,8 +87,10 @@ mod tests {
#[test]
fn bytes_layout() {
// SAFETY: ensuring layout is the same
let u1: [usize; 4] =
unsafe { mem::transmute(from_static(HELLO.as_bytes())) };
// SAFETY: ensuring layout is the same
let u2: [usize; 4] =
unsafe { mem::transmute(bytes::Bytes::from_static(HELLO.as_bytes())) };
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 {
#[inline(always)]
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) };
std::mem::forget(src);
x

View file

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

View file

@ -1,5 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
#![allow(clippy::undocumented_unsafe_blocks)]
use std::os::raw::c_void;
use std::thread::sleep;
use std::time::Duration;
@ -11,23 +13,29 @@ pub extern "C" fn print_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]
pub extern "C" fn print_buffer(ptr: *const u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts(ptr, len) };
pub unsafe extern "C" fn print_buffer(ptr: *const u8, len: usize) {
let buf = std::slice::from_raw_parts(ptr, len);
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]
pub extern "C" fn print_buffer2(
pub unsafe extern "C" fn print_buffer2(
ptr1: *const u8,
len1: usize,
ptr2: *const u8,
len2: usize,
) {
let buf1 = unsafe { std::slice::from_raw_parts(ptr1, len1) };
let buf2 = unsafe { std::slice::from_raw_parts(ptr2, len2) };
let buf1 = std::slice::from_raw_parts(ptr1, len1);
let buf2 = std::slice::from_raw_parts(ptr2, len2);
println!("{:?} {:?}", buf1, buf2);
}
@ -87,19 +95,25 @@ pub extern "C" fn sleep_blocking(ms: u64) {
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]
pub extern "C" fn fill_buffer(value: u8, buf: *mut u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) };
pub unsafe extern "C" fn fill_buffer(value: u8, buf: *mut u8, len: usize) {
let buf = std::slice::from_raw_parts_mut(buf, len);
for itm in buf.iter_mut() {
*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]
pub extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) {
let buf = unsafe { std::slice::from_raw_parts(ptr, len) };
pub unsafe extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) {
let buf = std::slice::from_raw_parts(ptr, len);
assert_eq!(buf, vec![1, 2, 3, 4, 5, 6, 7, 8]);
}

View file

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