mirror of
https://github.com/fafhrd91/actix-web
synced 2025-06-25 14:49:20 +02:00
Remove several usages of 'unsafe' (#968)
* Replace UnsafeCell in DateServiceInner with Cell The previous API was extremely dangerous - calling `get_ref()` followed by `reset()` would trigger instant UB, without requiring any `unsafe` blocks in the caller. By making DateInner `Copy`, we can use a normal `Cell` instead of an `UnsafeCell`. This makes it impossible to cause UB (or even panic) with the API. * Split unsafe block HttpServiceHandlerResponse Also add explanation of the safety of the usage of `unsafe` * Replace UnsafeCell with RefCell in PayloadRef This ensures that a mistake in the usage of 'get_mut' will cause a panic, not undefined behavior.
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use std::cell::UnsafeCell;
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::rc::Rc;
|
||||
@ -172,6 +172,7 @@ impl ServiceConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Date {
|
||||
bytes: [u8; DATE_VALUE_LENGTH],
|
||||
pos: usize,
|
||||
@ -205,28 +206,28 @@ impl fmt::Write for Date {
|
||||
struct DateService(Rc<DateServiceInner>);
|
||||
|
||||
struct DateServiceInner {
|
||||
current: UnsafeCell<Option<(Date, Instant)>>,
|
||||
current: Cell<Option<(Date, Instant)>>,
|
||||
}
|
||||
|
||||
impl DateServiceInner {
|
||||
fn new() -> Self {
|
||||
DateServiceInner {
|
||||
current: UnsafeCell::new(None),
|
||||
current: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ref(&self) -> &Option<(Date, Instant)> {
|
||||
unsafe { &*self.current.get() }
|
||||
fn get(&self) -> Option<(Date, Instant)> {
|
||||
self.current.get()
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
unsafe { (&mut *self.current.get()).take() };
|
||||
self.current.set(None);
|
||||
}
|
||||
|
||||
fn update(&self) {
|
||||
let now = Instant::now();
|
||||
let date = Date::new();
|
||||
*(unsafe { &mut *self.current.get() }) = Some((date, now));
|
||||
self.current.set(Some((date, now)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +237,7 @@ impl DateService {
|
||||
}
|
||||
|
||||
fn check_date(&self) {
|
||||
if self.0.get_ref().is_none() {
|
||||
if self.0.get().is_none() {
|
||||
self.0.update();
|
||||
|
||||
// periodic date update
|
||||
@ -252,14 +253,13 @@ impl DateService {
|
||||
|
||||
fn now(&self) -> Instant {
|
||||
self.check_date();
|
||||
self.0.get_ref().as_ref().unwrap().1
|
||||
self.0.get().unwrap().1
|
||||
}
|
||||
|
||||
fn date(&self) -> &Date {
|
||||
fn date(&self) -> Date {
|
||||
self.check_date();
|
||||
|
||||
let item = self.0.get_ref().as_ref().unwrap();
|
||||
&item.0
|
||||
self.0.get().unwrap().0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,16 +466,18 @@ where
|
||||
State::Unknown(ref mut data) => {
|
||||
if let Some(ref mut item) = data {
|
||||
loop {
|
||||
unsafe {
|
||||
let b = item.1.bytes_mut();
|
||||
let n = try_ready!(item.0.poll_read(b));
|
||||
if n == 0 {
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
item.1.advance_mut(n);
|
||||
if item.1.len() >= HTTP2_PREFACE.len() {
|
||||
break;
|
||||
}
|
||||
// Safety - we only write to the returned slice.
|
||||
let b = unsafe { item.1.bytes_mut() };
|
||||
let n = try_ready!(item.0.poll_read(b));
|
||||
if n == 0 {
|
||||
return Ok(Async::Ready(()));
|
||||
}
|
||||
// Safety - we know that 'n' bytes have
|
||||
// been initialized via the contract of
|
||||
// 'poll_read'
|
||||
unsafe { item.1.advance_mut(n) };
|
||||
if item.1.len() >= HTTP2_PREFACE.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user