Skip to content

Commit 9af7195

Browse files
committed
improve usage of unsafe (#1231)
Inspired by #1231 (comment) . - make sure the type in question isn't use outside of its designated module - improve documentation around safety to make the underlying data structure more obvious.
1 parent 911c05f commit 9af7195

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

gix-pack/src/cache/delta/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ pub mod traverse;
1717
///
1818
pub mod from_offsets;
1919

20-
/// An item stored within the [`Tree`]
20+
/// An item stored within the [`Tree`] whose data is stored in a pack file, identified by
21+
/// the offset of its first (`offset`) and last (`next_offset`) bytes.
22+
///
23+
/// It represents either a root entry, or one that relies on a base to be resolvable,
24+
/// alongside associated `data` `T`.
2125
pub struct Item<T> {
2226
/// The offset into the pack file at which the pack entry's data is located.
2327
pub offset: crate::data::Offset,

gix-pack/src/cache/delta/traverse/resolve.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
data::EntryRange,
1515
};
1616

17-
mod node {
17+
mod root {
1818
use crate::cache::delta::{traverse::util::ItemSliceSync, Item};
1919

2020
/// An item returned by `iter_root_chunks`, allowing access to the `data` stored alongside nodes in a [`Tree`].
@@ -68,7 +68,7 @@ mod node {
6868
}
6969
}
7070

71-
pub(crate) struct State<'items, F, MBFN, T: Send> {
71+
pub(in crate::cache::delta::traverse) struct State<'items, F, MBFN, T: Send> {
7272
pub delta_bytes: Vec<u8>,
7373
pub fully_resolved_delta_bytes: Vec<u8>,
7474
pub progress: Box<dyn Progress>,
@@ -118,9 +118,9 @@ where
118118
// each node is a base, and its children always start out as deltas which become a base after applying them.
119119
// These will be pushed onto our stack until all are processed
120120
let root_level = 0;
121-
// SAFETY: The child items are unique
121+
// SAFETY: The child items are unique, as `item` is the root of a tree of dependent child items.
122122
#[allow(unsafe_code)]
123-
let root_node = unsafe { node::Node::new(item, child_items) };
123+
let root_node = unsafe { root::Node::new(item, child_items) };
124124
let mut nodes: Vec<_> = vec![(root_level, root_node)];
125125
while let Some((level, mut base)) = nodes.pop() {
126126
if should_interrupt.load(Ordering::Relaxed) {
@@ -240,7 +240,7 @@ fn deltas_mt<T, F, MBFN, E, R>(
240240
objects: gix_features::progress::StepShared,
241241
size: gix_features::progress::StepShared,
242242
progress: &dyn Progress,
243-
nodes: Vec<(u16, node::Node<'_, T>)>,
243+
nodes: Vec<(u16, root::Node<'_, T>)>,
244244
resolve: F,
245245
resolve_data: &R,
246246
modify_base: MBFN,

gix-pack/src/cache/delta/traverse/util.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
use std::marker::PhantomData;
22

3-
pub(crate) struct ItemSliceSync<'a, T>
3+
/// SAFETY: This type is used to allow access to a size-optimized vec of items that form a
4+
/// tree, and we need to access it concurrently with each thread taking its own root node,
5+
/// and working its way through all the reachable leaves.
6+
///
7+
/// The tree was built by decoding a pack whose entries refer to its bases only by OFS_DELTA -
8+
/// they are pointing backwards only which assures bases have to be listed first, and that each entry
9+
/// only has a single parent.
10+
///
11+
/// REF_DELTA entries aren't supported here, and cause immediate failure - they are expected to have
12+
/// been resolved before as part of the thin-pack handling.
13+
///
14+
/// If we somehow would allow REF_DELTA entries to point to an in-pack object, then in theory malicious packs could
15+
/// cause all kinds of graphs as they can point anywhere in the pack, but they still can't link an entry to
16+
/// more than one base. And that's what one would really have to do for two threads to encounter the same child.
17+
///
18+
/// Thus I believe it's impossible for this data structure to end up in a place where it violates its assumption.
19+
pub(in crate::cache::delta::traverse) struct ItemSliceSync<'a, T>
420
where
521
T: Send,
622
{

0 commit comments

Comments
 (0)