From 2ffeb0e1668fdf7b71aa55ae57deefa060287aea Mon Sep 17 00:00:00 2001 From: DQ Date: Fri, 1 Jul 2022 10:44:24 +0200 Subject: [PATCH] Use strict provenance for pointer tagging (#36) --- .github/workflows/main.yml | 2 +- Cargo.toml | 1 + src/green/element.rs | 4 +++- src/green/token.rs | 6 ++++-- src/lib.rs | 1 + src/syntax/node.rs | 3 ++- src/syntax/token.rs | 7 ++++++- 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 432016b..6462f23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -102,7 +102,7 @@ jobs: rust-version: nightly components: miri env: - MIRIFLAGS: -Zmiri-disable-isolation + MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance - run: cargo miri test --verbose --all-features sanitizers: diff --git a/Cargo.toml b/Cargo.toml index 2aaa045..212956f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ parking_lot = "0.11.2" # Arc triomphe = "0.1.3" +sptr = "0.3.2" [dependencies.serde] version = "1.0" diff --git a/src/green/element.rs b/src/green/element.rs index 8b7af64..5ab0826 100644 --- a/src/green/element.rs +++ b/src/green/element.rs @@ -4,6 +4,8 @@ use std::{fmt, hash, mem}; // This MUST be size=1 such that pointer math actually advances the pointer. type ErasedPtr = *const u8; +use sptr::Strict; + use crate::{ green::{GreenNode, GreenToken, SyntaxKind}, NodeOrToken, TextSize, @@ -114,7 +116,7 @@ impl From for GreenElement { impl PackedGreenElement { pub(crate) fn is_node(&self) -> bool { - self.ptr as usize & 1 == 0 + self.ptr.addr() & super::token::IS_TOKEN_TAG == 0 } pub(crate) fn as_node(&self) -> Option<&GreenNode> { diff --git a/src/green/token.rs b/src/green/token.rs index df54e93..e64be2a 100644 --- a/src/green/token.rs +++ b/src/green/token.rs @@ -5,6 +5,7 @@ use crate::{ interning::{Key, Resolver}, TextSize, }; +use sptr::Strict; use triomphe::Arc; #[repr(align(2))] // to use 1 bit for pointer tagging. NB: this is an at-least annotation @@ -23,17 +24,18 @@ pub struct GreenToken { unsafe impl Send for GreenToken {} // where GreenTokenData: Send + Sync unsafe impl Sync for GreenToken {} // where GreenTokenData: Send + Sync +pub(super) const IS_TOKEN_TAG: usize = 0x1; impl GreenToken { fn add_tag(ptr: ptr::NonNull) -> ptr::NonNull { unsafe { - let ptr = ((ptr.as_ptr() as usize) | 1) as *mut GreenTokenData; + let ptr = ptr.as_ptr().map_addr(|addr| addr | IS_TOKEN_TAG); ptr::NonNull::new_unchecked(ptr) } } fn remove_tag(ptr: ptr::NonNull) -> ptr::NonNull { unsafe { - let ptr = ((ptr.as_ptr() as usize) & !1) as *mut GreenTokenData; + let ptr = ptr.as_ptr().map_addr(|addr| addr & !IS_TOKEN_TAG); ptr::NonNull::new_unchecked(ptr) } } diff --git a/src/lib.rs b/src/lib.rs index 0141070..277f258 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ #![forbid(missing_debug_implementations, unconditional_recursion)] #![deny(unsafe_code, missing_docs, future_incompatible)] +#![allow(unstable_name_collisions)] // strict provenance - must come after `future_incompatible` to take precedence #[allow(unsafe_code)] mod green; diff --git a/src/syntax/node.rs b/src/syntax/node.rs index 28ed4d1..8969e5e 100644 --- a/src/syntax/node.rs +++ b/src/syntax/node.rs @@ -387,7 +387,8 @@ impl SyntaxNode { /// builder.token(TOKEN, "content"); /// builder.finish_node(); /// let (green, cache) = builder.finish(); - /// let root: ResolvedNode = SyntaxNode::new_root_with_resolver(green, cache.unwrap().into_interner().unwrap()); + /// let root: ResolvedNode = + /// SyntaxNode::new_root_with_resolver(green, cache.unwrap().into_interner().unwrap()); /// assert_eq!(root.text(), "content"); /// ``` #[inline] diff --git a/src/syntax/token.rs b/src/syntax/token.rs index b59c9c9..800c21d 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -253,7 +253,12 @@ impl SyntaxToken { /// let tree = parse(&mut builder, "x"); /// # let tree = SyntaxNode::::new_root(builder.finish().0); /// let type_table = &state.type_table; - /// let ident = tree.children_with_tokens().next().unwrap().into_token().unwrap(); + /// let ident = tree + /// .children_with_tokens() + /// .next() + /// .unwrap() + /// .into_token() + /// .unwrap(); /// let typ = type_table.type_of(ident.text_key()); /// ``` #[inline]