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-09 21:13:22 -04:00
parent 68bb76beec
commit 9d612f8cd0
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
1 changed files with 13 additions and 16 deletions

View File

@ -1,5 +1,5 @@
//! Multipart payload support //! Multipart payload support
use std::cell::{Cell, RefCell, UnsafeCell}; use std::cell::{Cell, RefCell, RefMut};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
use std::{cmp, fmt}; use std::{cmp, fmt};
@ -112,7 +112,7 @@ impl Stream for Multipart {
Err(err) Err(err)
} else if self.safety.current() { } else if self.safety.current() {
let mut inner = self.inner.as_mut().unwrap().borrow_mut(); let mut inner = self.inner.as_mut().unwrap().borrow_mut();
if let Some(payload) = inner.payload.get_mut(&self.safety) { if let Some(mut payload) = inner.payload.get_mut(&self.safety) {
payload.poll_stream()?; payload.poll_stream()?;
} }
inner.poll(&self.safety) inner.poll(&self.safety)
@ -265,12 +265,12 @@ impl InnerMultipart {
} }
} }
let headers = if let Some(payload) = self.payload.get_mut(safety) { let headers = if let Some(mut payload) = self.payload.get_mut(safety) {
match self.state { match self.state {
// read until first boundary // read until first boundary
InnerState::FirstBoundary => { InnerState::FirstBoundary => {
match InnerMultipart::skip_until_boundary( match InnerMultipart::skip_until_boundary(
payload, &mut *payload,
&self.boundary, &self.boundary,
)? { )? {
Some(eof) => { Some(eof) => {
@ -286,7 +286,7 @@ impl InnerMultipart {
} }
// read boundary // read boundary
InnerState::Boundary => { InnerState::Boundary => {
match InnerMultipart::read_boundary(payload, &self.boundary)? { match InnerMultipart::read_boundary(&mut *payload, &self.boundary)? {
None => return Ok(Async::NotReady), None => return Ok(Async::NotReady),
Some(eof) => { Some(eof) => {
if eof { if eof {
@ -303,7 +303,7 @@ impl InnerMultipart {
// read field headers for next field // read field headers for next field
if self.state == InnerState::Headers { if self.state == InnerState::Headers {
if let Some(headers) = InnerMultipart::read_headers(payload)? { if let Some(headers) = InnerMultipart::read_headers(&mut *payload)? {
self.state = InnerState::Boundary; self.state = InnerState::Boundary;
headers headers
} else { } else {
@ -411,7 +411,7 @@ impl Stream for Field {
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if self.safety.current() { if self.safety.current() {
let mut inner = self.inner.borrow_mut(); let mut inner = self.inner.borrow_mut();
if let Some(payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety) if let Some(mut payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety)
{ {
payload.poll_stream()?; payload.poll_stream()?;
} }
@ -584,12 +584,12 @@ impl InnerField {
return Ok(Async::Ready(None)); return Ok(Async::Ready(None));
} }
let result = if let Some(payload) = self.payload.as_ref().unwrap().get_mut(s) { let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
if !self.eof { if !self.eof {
let res = if let Some(ref mut len) = self.length { let res = if let Some(ref mut len) = self.length {
InnerField::read_len(payload, len)? InnerField::read_len(&mut *payload, len)?
} else { } else {
InnerField::read_stream(payload, &self.boundary)? InnerField::read_stream(&mut *payload, &self.boundary)?
}; };
match res { match res {
@ -620,7 +620,7 @@ impl InnerField {
} }
struct PayloadRef { struct PayloadRef {
payload: Rc<UnsafeCell<PayloadBuffer>>, payload: Rc<RefCell<PayloadBuffer>>,
} }
impl PayloadRef { impl PayloadRef {
@ -630,15 +630,12 @@ impl PayloadRef {
} }
} }
fn get_mut<'a, 'b>(&'a self, s: &'b Safety) -> Option<&'a mut PayloadBuffer> fn get_mut<'a, 'b>(&'a self, s: &'b Safety) -> Option<RefMut<'a, PayloadBuffer>>
where where
'a: 'b, 'a: 'b,
{ {
// Unsafe: Invariant is inforced by Safety Safety is used as ref counter,
// only top most ref can have mutable access to payload.
if s.current() { if s.current() {
let payload: &mut PayloadBuffer = unsafe { &mut *self.payload.get() }; Some(self.payload.borrow_mut())
Some(payload)
} else { } else {
None None
} }