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

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
This commit is contained in:
Emilio Cobos Álvarez 2023-06-09 11:17:44 +00:00
parent b87b4a2527
commit d4a4ca7c15
2 changed files with 17 additions and 31 deletions

View File

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

View File

@ -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.
/// * 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> {
/// 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` doesnt 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.
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]