Commit 1963ccf5 authored by Emilio Cobos Álvarez's avatar Emilio Cobos Álvarez
Browse files

Bug 1836670 - Use NonNull in cssparser::CowRcStr....

Bug 1836670 - Use NonNull in cssparser::CowRcStr. r=layout-reviewers,glandium,dlrobertson, a=dmeehan

This prevents the compiler from misoptimizing this code due to undefined
behavior.

Upstream PR: https://github.com/servo/rust-cssparser/pull/345

Differential Revision: https://phabricator.services.mozilla.com/D179921
parent 90d71ea7
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -332,7 +332,6 @@ run-if = !headless && (os == 'mac' || toolkit == 'android' || toolkit == 'gtk')
[test_parse_rule.html]
[test_parse_url.html]
[test_parser_diagnostics_unprintables.html]
skip-if = !debug # bug 1836670
[test_pixel_lengths.html]
[test_placeholder_restrictions.html]
[test_pointer-events.html]
+17 −30
Original line number Diff line number Diff line
@@ -3,37 +3,24 @@
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt;
use std::hash;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::slice;
use std::str;
use std::{cmp, fmt, hash, marker, mem, ops, slice, str, ptr};

/// A string that is either shared (heap-allocated and reference-counted) or borrowed.
///
/// Equivalent to `enum { Borrowed(&'a str), Shared(Rc<String>) }`, but stored more compactly.
///
/// FIXME(https://github.com/rust-lang/rfcs/issues/1230): use an actual enum if/when
/// the compiler can do this layout optimization.
pub struct CowRcStr<'a> {
    /// FIXME: https://github.com/rust-lang/rust/issues/27730 use NonZero or Shared.
    /// In the meantime we abuse `&'static _` to get the effect of `NonZero<*const _>`.
    /// `ptr` doesn’t really have the 'static lifetime!
    ptr: &'static (),

/// * If `borrowed_len_or_max == usize::MAX`, then `ptr` represents `NonZero<*const String>`
///   from `Rc::into_raw`.
///   The lifetime parameter `'a` is irrelevant in this case.
///
/// * Otherwise, `ptr` represents the `NonZero<*const u8>` data component of `&'a str`,
///   and `borrowed_len_or_max` its length.
pub struct CowRcStr<'a> {
    ptr: ptr::NonNull<()>,
    borrowed_len_or_max: usize,

    phantom: PhantomData<Result<&'a str, Rc<String>>>,
    phantom: marker::PhantomData<Result<&'a str, Rc<String>>>,
}

fn _static_assert_same_size<'a>() {
@@ -57,9 +44,9 @@ impl<'a> From<&'a str> for CowRcStr<'a> {
        let len = s.len();
        assert!(len < usize::MAX);
        CowRcStr {
            ptr: unsafe { &*(s.as_ptr() as *const ()) },
            ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) },
            borrowed_len_or_max: len,
            phantom: PhantomData,
            phantom: marker::PhantomData,
        }
    }
}
@@ -74,22 +61,22 @@ impl<'a> From<String> for CowRcStr<'a> {
impl<'a> CowRcStr<'a> {
    #[inline]
    fn from_rc(s: Rc<String>) -> Self {
        let ptr = unsafe { &*(Rc::into_raw(s) as *const ()) };
        let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) };
        CowRcStr {
            ptr: ptr,
            ptr,
            borrowed_len_or_max: usize::MAX,
            phantom: PhantomData,
            phantom: marker::PhantomData,
        }
    }

    #[inline]
    fn unpack(&self) -> Result<&'a str, *const String> {
        if self.borrowed_len_or_max == usize::MAX {
            Err(self.ptr as *const () as *const String)
            Err(self.ptr.as_ptr() as *const String)
        } else {
            unsafe {
                Ok(str::from_utf8_unchecked(slice::from_raw_parts(
                    self.ptr as *const () as *const u8,
                    self.ptr.as_ptr() as *const u8,
                    self.borrowed_len_or_max,
                )))
            }
@@ -121,7 +108,7 @@ impl<'a> Drop for CowRcStr<'a> {
    }
}

impl<'a> Deref for CowRcStr<'a> {
impl<'a> ops::Deref for CowRcStr<'a> {
    type Target = str;

    #[inline]