1
0
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:
Aaron Hill
2019-07-17 18:45:17 -04:00
committed by Nikolay Kim
parent 2a2d7f5768
commit b36fdc46db
3 changed files with 37 additions and 38 deletions

View File

@ -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
}
}

View File

@ -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 {