D7921: rust-dirs-multiset: improve temporary error message

Alphare (Raphaël Gomès) phabricator at mercurial-scm.org
Fri Jan 17 10:42:27 UTC 2020


Alphare created this revision.
Herald added subscribers: mercurial-devel, kevincox, durin42.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  While we wait on a future patch that could verify that the paths passed to
  `DirsMultiset` have been audited, we still need to handle this error.
  This patch makes it easier to bubble up and makes the error clearer.
  
  Also, this patch introduces the `subslice_index` function that could be useful
  for other - albeit niche - purposes.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D7921

AFFECTED FILES
  rust/hg-core/src/dirstate/dirs_multiset.rs
  rust/hg-core/src/lib.rs
  rust/hg-core/src/utils.rs

CHANGE DETAILS

diff --git a/rust/hg-core/src/utils.rs b/rust/hg-core/src/utils.rs
--- a/rust/hg-core/src/utils.rs
+++ b/rust/hg-core/src/utils.rs
@@ -61,6 +61,36 @@
     }
 }
 
+/// Find the offset of the subslice relative to the original collection
+///
+/// This function panics for zero-sized types.
+/// # Examples:
+///
+/// ```
+/// use crate::hg::utils::subslice_offset;
+/// let mut line = b"Subslice me!".to_vec();
+/// assert_eq!(subslice_offset(&line, &line[8..]), Some(8));
+///
+/// assert_eq!(subslice_offset(&line, b"hahaha"), None);
+///
+/// // Empty array
+/// let v: [u8; 0] = [];
+/// assert_eq!(subslice_offset(&v, &v), Some(0));
+/// assert_eq!(subslice_offset(&v, b"hehe"), None);
+/// ```
+pub fn subslice_offset<T: Sized>(outer: &[T], inner: &[T]) -> Option<usize> {
+    let pointee_size = std::mem::size_of::<T>();
+    assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
+
+    let outer_start = outer.as_ptr() as usize;
+    let inner = inner.as_ptr() as usize;
+    if inner < outer_start || inner > outer_start.wrapping_add(outer.len()) {
+        None
+    } else {
+        Some(inner.wrapping_sub(outer_start))
+    }
+}
+
 pub trait SliceExt {
     fn trim_end(&self) -> &Self;
     fn trim_start(&self) -> &Self;
diff --git a/rust/hg-core/src/lib.rs b/rust/hg-core/src/lib.rs
--- a/rust/hg-core/src/lib.rs
+++ b/rust/hg-core/src/lib.rs
@@ -82,18 +82,17 @@
 pub enum DirstateMapError {
     PathNotFound(HgPathBuf),
     EmptyPath,
-    ConsecutiveSlashes,
+    InvalidPath(HgPathError),
 }
 
 impl ToString for DirstateMapError {
     fn to_string(&self) -> String {
-        use crate::DirstateMapError::*;
         match self {
-            PathNotFound(_) => "expected a value, found none".to_string(),
-            EmptyPath => "Overflow in dirstate.".to_string(),
-            ConsecutiveSlashes => {
-                "found invalid consecutive slashes in path".to_string()
+            DirstateMapError::PathNotFound(_) => {
+                "expected a value, found none".to_string()
             }
+            DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(),
+            DirstateMapError::InvalidPath(e) => e.to_string(),
         }
     }
 }
diff --git a/rust/hg-core/src/dirstate/dirs_multiset.rs b/rust/hg-core/src/dirstate/dirs_multiset.rs
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs
@@ -8,6 +8,8 @@
 //! A multiset of directory names.
 //!
 //! Used to counts the references to directories in a manifest or dirstate.
+use crate::utils::hg_path::HgPathError;
+use crate::utils::subslice_offset;
 use crate::{
     dirstate::EntryState,
     utils::{
@@ -78,7 +80,18 @@
             if subpath.as_bytes().last() == Some(&b'/') {
                 // TODO Remove this once PathAuditor is certified
                 // as the only entrypoint for path data
-                return Err(DirstateMapError::ConsecutiveSlashes);
+                let offset = subslice_offset(
+                    path.as_ref().as_bytes(),
+                    subpath.as_bytes(),
+                );
+                let second_slash_index = offset.unwrap() + subpath.len() - 1;
+
+                return Err(DirstateMapError::InvalidPath(
+                    HgPathError::ConsecutiveSlashes {
+                        bytes: path.as_ref().as_bytes().to_owned(),
+                        second_slash_index,
+                    },
+                ));
             }
             if let Some(val) = self.inner.get_mut(subpath) {
                 *val += 1;



To: Alphare, #hg-reviewers
Cc: durin42, kevincox, mercurial-devel


More information about the Mercurial-devel mailing list