inspect_validator/data/
scanner.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::{Data, LazyNode, Metrics, Node, Payload, Property, ROOT_NAME};
6use crate::metrics::{BlockMetrics, BlockStatus};
7use anyhow::{Context, Error, bail, format_err};
8use fuchsia_inspect::reader as ireader;
9use fuchsia_inspect::reader::snapshot::ScannedBlock;
10use inspect_format::constants::MIN_ORDER_SIZE;
11use inspect_format::*;
12use std::cmp::min;
13use std::collections::{HashMap, HashSet};
14use zx::Vmo;
15
16// When reading from a VMO, the keys of the HashMaps are the indexes of the relevant
17// blocks. Thus, they will never collide.
18//
19// Reading from a VMO is a complicated process.
20// 1) Try to take a fuchsia_inspect::reader::snapshot::Snapshot of the VMO.
21// 2) Iterate through it, pedantically examining all its blocks and loading
22//   the relevant blocks into a ScannedObjects structure (which contains
23//   ScannedNode, ScannedName, ScannedProperty, and ScannedExtent).
24// 2.5) ScannedNodes may be added before they're scanned, since they need to
25//   track their child nodes and properties. In this case, their "validated"
26//   field will be false until they're actually scanned.
27// 3) Starting from the "0" node, create Node and Property objects for all the
28//   dependent children and properties (verifying that all dependent objects
29//   exist (and are valid in the case of Nodes)). This is also when Extents are
30//   combined into byte vectors, and in the case of String, verified to be valid UTF-8.
31// 4) Add the Node and Property objects (each with its ID) into the "nodes" and
32//   "properties" HashMaps of a new Data object. Note that these HashMaps do not
33//   hold the hierarchical information; instead, each Node contains a HashSet of
34//   the keys of its children and properties.
35
36#[derive(Debug)]
37pub struct Scanner {
38    nodes: HashMap<BlockIndex, ScannedNode>,
39    names: HashMap<BlockIndex, ScannedName>,
40    properties: HashMap<BlockIndex, ScannedProperty>,
41    extents: HashMap<BlockIndex, ScannedExtent>,
42    final_dereferenced_strings: HashMap<BlockIndex, String>,
43    final_nodes: HashMap<BlockIndex, Node>,
44    final_properties: HashMap<BlockIndex, Property>,
45    metrics: Metrics,
46    child_trees: Option<HashMap<String, LazyNode>>,
47}
48
49impl TryFrom<&[u8]> for Scanner {
50    type Error = Error;
51
52    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
53        let scanner = Scanner::new(None);
54        scanner.scan(ireader::snapshot::Snapshot::try_from(bytes.to_vec())?, bytes)
55    }
56}
57
58impl TryFrom<&Vmo> for Scanner {
59    type Error = Error;
60    fn try_from(vmo: &Vmo) -> Result<Self, Self::Error> {
61        let scanner = Scanner::new(None);
62        scanner.scan(ireader::snapshot::Snapshot::try_from(vmo)?, &vmo_as_buffer(vmo)?)
63    }
64}
65
66impl TryFrom<LazyNode> for Scanner {
67    type Error = Error;
68
69    fn try_from(mut vmo_tree: LazyNode) -> Result<Self, Self::Error> {
70        let snapshot = ireader::snapshot::Snapshot::try_from(vmo_tree.vmo())?;
71        let buffer = vmo_as_buffer(vmo_tree.vmo())?;
72        let scanner = Scanner::new(vmo_tree.take_children());
73        scanner.scan(snapshot, &buffer)
74    }
75}
76
77fn vmo_as_buffer(vmo: &Vmo) -> Result<Vec<u8>, Error> {
78    // NOTE: In any context except a controlled test, it's not safe to read the VMO manually -
79    // the contents may differ or even be invalid (mid-update).
80    let size = vmo.get_size()?;
81    let mut buffer = vec![0u8; size as usize];
82    vmo.read(&mut buffer[..], 0)?;
83    Ok(buffer)
84}
85
86fn low_bits(number: u8, n_bits: usize) -> u8 {
87    let n_bits = min(n_bits, 8);
88    let mask = !(0xff_u16 << n_bits) as u8;
89    number & mask
90}
91
92fn high_bits(number: u8, n_bits: usize) -> u8 {
93    let n_bits = min(n_bits, 8);
94    let mask = !(0xff_u16 >> n_bits) as u8;
95    number & mask
96}
97
98const BITS_PER_BYTE: usize = 8;
99
100/// Get size in bytes of a given |order|. Copied from private mod fuchsia-inspect/src/utils.rs
101fn order_to_size(order: u8) -> usize {
102    MIN_ORDER_SIZE << (order as usize)
103}
104
105// Checks if these bits (start...end) are 0. Restricts the range checked to the given block.
106fn check_zero_bits(
107    buffer: &[u8],
108    block: &ScannedBlock<'_, Unknown>,
109    start: usize,
110    end: usize,
111) -> Result<(), Error> {
112    if end < start {
113        return Err(format_err!("End must be >= start"));
114    }
115    let bits_in_block = order_to_size(block.order()) * BITS_PER_BYTE;
116    if start > bits_in_block - 1 {
117        return Ok(());
118    }
119    let end = min(end, bits_in_block - 1);
120    let block_offset = usize::from(block.index()) * MIN_ORDER_SIZE;
121    let low_byte = start / BITS_PER_BYTE;
122    let high_byte = end / BITS_PER_BYTE;
123    let bottom_bits = high_bits(buffer[low_byte + block_offset], 8 - (start % 8));
124    let top_bits = low_bits(buffer[high_byte + block_offset], (end % 8) + 1);
125    if low_byte == high_byte {
126        match bottom_bits & top_bits {
127            0 => return Ok(()),
128            nonzero => bail!(
129                "Bits {}...{} of block type {:?} at {} have nonzero value {}",
130                start,
131                end,
132                block.block_type(),
133                block.index(),
134                nonzero
135            ),
136        }
137    }
138    if bottom_bits != 0 {
139        bail!(
140            "Non-zero value {} for bits {}.. of block type {:?} at {}",
141            bottom_bits,
142            start,
143            block.block_type(),
144            block.index()
145        );
146    }
147    if top_bits != 0 {
148        bail!(
149            "Non-zero value {} for bits ..{} of block type {:?} at {}",
150            top_bits,
151            end,
152            block.block_type(),
153            block.index()
154        );
155    }
156    for byte in low_byte + 1..high_byte {
157        if buffer[byte + block_offset] != 0 {
158            bail!(
159                "Non-zero value {} for byte {} of block type {:?} at {}",
160                buffer[byte],
161                byte,
162                block.block_type(),
163                block.index()
164            );
165        }
166    }
167    Ok(())
168}
169
170impl Scanner {
171    fn new(child_trees: Option<HashMap<String, LazyNode>>) -> Scanner {
172        let mut ret = Scanner {
173            nodes: HashMap::new(),
174            names: HashMap::new(),
175            properties: HashMap::new(),
176            extents: HashMap::new(),
177            final_dereferenced_strings: HashMap::new(),
178            metrics: Metrics::new(),
179            final_nodes: HashMap::new(),
180            final_properties: HashMap::new(),
181            child_trees,
182        };
183        // The ScannedNode at 0 is the "root" node. It exists to receive pointers to objects
184        // whose parent is 0 while scanning the VMO.
185        ret.nodes.insert(
186            BlockIndex::ROOT,
187            ScannedNode {
188                validated: true,
189                parent: BlockIndex::ROOT,
190                name: BlockIndex::ROOT,
191                children: HashSet::new(),
192                properties: HashSet::new(),
193                metrics: None,
194            },
195        );
196        ret
197    }
198
199    fn scan(mut self, snapshot: ireader::snapshot::Snapshot, buffer: &[u8]) -> Result<Self, Error> {
200        let mut link_blocks: Vec<ScannedBlock<'_, Unknown>> = Vec::new();
201        let mut string_references: Vec<ScannedStringReference> = Vec::new();
202        for block in snapshot.scan() {
203            match block.block_type().ok_or_else(|| format_err!("invalid block type"))? {
204                BlockType::Free => self.process_free(block)?,
205                BlockType::Reserved => self.process_reserved(block)?,
206                BlockType::Header => self.process_header(block)?,
207                BlockType::NodeValue => self.process_node(block)?,
208                BlockType::IntValue => self.process_property::<Int>(block, buffer)?,
209                BlockType::UintValue => self.process_property::<Uint>(block, buffer)?,
210                BlockType::DoubleValue => self.process_property::<Double>(block, buffer)?,
211                BlockType::ArrayValue => self.process_property::<Array<Unknown>>(block, buffer)?,
212                BlockType::BufferValue => self.process_property::<Buffer>(block, buffer)?,
213                BlockType::BoolValue => self.process_property::<Bool>(block, buffer)?,
214                BlockType::LinkValue => link_blocks.push(block),
215                BlockType::Extent => self.process_extent(block, buffer)?,
216                BlockType::Name => self.process_name(block, buffer)?,
217                BlockType::Tombstone => self.process_tombstone(block)?,
218                BlockType::StringReference => {
219                    string_references.push(self.process_string_reference(block)?);
220                }
221            }
222        }
223
224        for block in string_references.drain(..) {
225            let index = block.index;
226            let dereferenced = self.expand_string_reference(block)?;
227            self.final_dereferenced_strings.insert(index, dereferenced);
228        }
229
230        // We defer processing LINK blocks after because the population of the
231        // ScannedPayload::Link depends on all NAME blocks having been read.
232        for block in link_blocks.into_iter() {
233            self.process_property::<Link>(block, buffer)?
234        }
235
236        let (mut new_nodes, mut new_properties) = self.make_valid_node_tree(BlockIndex::ROOT)?;
237        for (node, id) in new_nodes.drain(..) {
238            self.final_nodes.insert(id, node);
239        }
240        for (property, id) in new_properties.drain(..) {
241            self.final_properties.insert(id, property);
242        }
243
244        self.record_unused_metrics();
245        Ok(self)
246    }
247
248    pub fn data(self) -> Data {
249        Data::build(self.final_nodes, self.final_properties)
250    }
251
252    pub fn metrics(self) -> Metrics {
253        self.metrics
254    }
255
256    // ***** Utility functions
257    fn record_unused_metrics(&mut self) {
258        for (_, node) in self.nodes.drain() {
259            if let Some(metrics) = node.metrics {
260                self.metrics.record(&metrics, BlockStatus::NotUsed);
261            }
262        }
263        for (_, name) in self.names.drain() {
264            self.metrics.record(&name.metrics, BlockStatus::NotUsed);
265        }
266        for (_, property) in self.properties.drain() {
267            self.metrics.record(&property.metrics, BlockStatus::NotUsed);
268        }
269        for (_, extent) in self.extents.drain() {
270            self.metrics.record(&extent.metrics, BlockStatus::NotUsed);
271        }
272    }
273
274    fn use_node(&mut self, node_id: BlockIndex) -> Result<ScannedNode, Error> {
275        let mut node = self
276            .nodes
277            .remove(&node_id)
278            .ok_or_else(|| format_err!("No node at index {}", node_id))?;
279        match node.metrics {
280            None => {
281                if node_id != BlockIndex::ROOT {
282                    return Err(format_err!("Invalid node (no metrics) at index {}", node_id));
283                }
284            }
285            Some(metrics) => {
286                // I actually want as_deref() but that's nightly-only.
287                self.metrics.record(&metrics, BlockStatus::Used);
288                node.metrics = Some(metrics); // Put it back after I borrow it.
289            }
290        }
291        Ok(node)
292    }
293
294    fn use_property(&mut self, property_id: BlockIndex) -> Result<ScannedProperty, Error> {
295        let property = self
296            .properties
297            .remove(&property_id)
298            .ok_or_else(|| format_err!("No property at index {}", property_id))?;
299        self.metrics.record(&property.metrics, BlockStatus::Used);
300        Ok(property)
301    }
302
303    // Used to find the value of a name index. This index, `name_id`, may refer to either a
304    // NAME block or a STRING_REFERENCE. If the block is a NAME, it will be removed.
305    fn use_owned_name(&mut self, name_id: BlockIndex) -> Result<String, Error> {
306        match self.names.remove(&name_id) {
307            Some(name) => {
308                self.metrics.record(&name.metrics, BlockStatus::Used);
309                Ok(name.name)
310            }
311            None => match self.final_dereferenced_strings.get(&name_id) {
312                Some(value) => {
313                    // Once a string is de-referenced, it isn't part of the hierarchy,
314                    // so we use metrics.process(block) when we process a STRING_REFERENCE.
315                    Ok(value.clone())
316                }
317                None => Err(format_err!("No string at index {}", name_id)),
318            },
319        }
320    }
321
322    // Used to find the value of an index that points to a NAME or STRING_REFERENCE. In either
323    // case, the value is not consumed.
324    fn lookup_name_or_string_reference(&mut self, name_id: BlockIndex) -> Result<String, Error> {
325        match self.names.get(&name_id) {
326            Some(name) => {
327                self.metrics.record(&name.metrics, BlockStatus::Used);
328                Ok(name.name.clone())
329            }
330            None => match self.final_dereferenced_strings.get(&name_id) {
331                Some(value) => {
332                    // Once a string is de-referenced, it isn't part of the hierarchy,
333                    // so we use metrics.process(block) when we process a STRING_REFERENCE.
334                    Ok(value.clone())
335                }
336                None => Err(format_err!("No string at index {}", name_id)),
337            },
338        }
339    }
340
341    // ***** Functions which read fuchsia_inspect::format::block::Block (actual
342    // ***** VMO blocks), validate them, turn them into Scanned* objects, and
343    // ***** add the ones we care about to Self.
344
345    // Some blocks' metrics can only be calculated in the context of a tree. Metrics aren't run
346    // on those in the process_ functions, but rather while the tree is being built.
347
348    // Note: process_ functions are only called from the scan() iterator on the
349    // VMO's blocks, so indexes of the blocks themselves will never be duplicated; that's one
350    // thing we don't have to verify.
351    fn process_free(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
352        // TODO(https://fxbug.dev/42115894): Uncomment or delete this line depending on the resolution of https://fxbug.dev/42115938.
353        // check_zero_bits(buffer, &block, 64, MAX_BLOCK_BITS)?;
354        self.metrics.process(block)?;
355        Ok(())
356    }
357
358    fn process_header(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
359        self.metrics.process(block)?;
360        Ok(())
361    }
362
363    fn process_tombstone(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
364        self.metrics.process(block)?;
365        Ok(())
366    }
367
368    fn process_reserved(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
369        self.metrics.process(block)?;
370        Ok(())
371    }
372
373    fn process_extent(
374        &mut self,
375        block: ScannedBlock<'_, Unknown>,
376        buffer: &[u8],
377    ) -> Result<(), Error> {
378        check_zero_bits(buffer, &block, 40, 63)?;
379        let extent = block.clone().cast::<Extent>().unwrap();
380        let next = extent.next_extent();
381        let data = extent.contents()?.to_vec();
382        self.extents
383            .insert(block.index(), ScannedExtent { next, data, metrics: Metrics::analyze(block)? });
384        Ok(())
385    }
386
387    fn process_name(
388        &mut self,
389        block: ScannedBlock<'_, Unknown>,
390        buffer: &[u8],
391    ) -> Result<(), Error> {
392        check_zero_bits(buffer, &block, 28, 63)?;
393        let name_block = block.clone().cast::<Name>().unwrap();
394        let name = name_block.contents()?.to_string();
395        self.names.insert(block.index(), ScannedName { name, metrics: Metrics::analyze(block)? });
396        Ok(())
397    }
398
399    fn process_node(&mut self, block: ScannedBlock<'_, Unknown>) -> Result<(), Error> {
400        let node_block = block.clone().cast::<inspect_format::Node>().unwrap();
401        let parent = node_block.parent_index();
402        let id = node_block.index();
403        let name = node_block.name_index();
404        let mut node;
405        let metrics = Some(Metrics::analyze(block)?);
406        if let Some(placeholder) = self.nodes.remove(&id) {
407            // We need to preserve the children and properties.
408            node = placeholder;
409            node.validated = true;
410            node.parent = parent;
411            node.name = name;
412            node.metrics = metrics;
413        } else {
414            node = ScannedNode {
415                validated: true,
416                name,
417                parent,
418                children: HashSet::new(),
419                properties: HashSet::new(),
420                metrics,
421            }
422        }
423        self.nodes.insert(id, node);
424        self.add_to_parent(parent, id, |node| &mut node.children);
425        Ok(())
426    }
427
428    fn add_to_parent<F: FnOnce(&mut ScannedNode) -> &mut HashSet<BlockIndex>>(
429        &mut self,
430        parent: BlockIndex,
431        id: BlockIndex,
432        get_the_hashset: F, // Gets children or properties
433    ) {
434        self.nodes.entry(parent).or_insert_with(|| ScannedNode {
435            validated: false,
436            name: BlockIndex::EMPTY,
437            parent: BlockIndex::ROOT,
438            children: HashSet::new(),
439            properties: HashSet::new(),
440            metrics: None,
441        });
442        if let Some(parent_node) = self.nodes.get_mut(&parent) {
443            get_the_hashset(parent_node).insert(id);
444        }
445    }
446
447    fn process_string_reference(
448        &mut self,
449        block: ScannedBlock<'_, Unknown>,
450    ) -> Result<ScannedStringReference, Error> {
451        let string_ref = block.clone().cast::<StringRef>().unwrap();
452        let scanned = ScannedStringReference {
453            index: block.index(),
454            value: string_ref.inline_data()?.to_vec(),
455            length: string_ref.total_length(),
456            next_extent: string_ref.next_extent(),
457        };
458
459        self.metrics.process(block)?;
460        Ok(scanned)
461    }
462
463    fn process_property<K>(
464        &mut self,
465        block: ScannedBlock<'_, Unknown>,
466        buffer: &[u8],
467    ) -> Result<(), Error>
468    where
469        K: ValueBlockKind + Clone,
470        ScannedPayload: BuildScannedPayload<K>,
471    {
472        if block.block_type() == Some(BlockType::ArrayValue) {
473            check_zero_bits(buffer, &block, 80, 127)?;
474        }
475        let property_block = block.clone().cast::<K>().unwrap();
476        let id = property_block.index();
477        let parent = property_block.parent_index();
478        let name = property_block.name_index();
479        let payload = ScannedPayload::build(property_block, self)?;
480        let property = ScannedProperty { name, parent, payload, metrics: Metrics::analyze(block)? };
481        self.properties.insert(id, property);
482        self.add_to_parent(parent, id, |node| &mut node.properties);
483        Ok(())
484    }
485
486    // ***** Functions which convert Scanned* objects into Node and Property objects.
487
488    #[allow(clippy::type_complexity)]
489    fn make_valid_node_tree(
490        &mut self,
491        id: BlockIndex,
492    ) -> Result<(Vec<(Node, BlockIndex)>, Vec<(Property, BlockIndex)>), Error> {
493        let scanned_node = self.use_node(id)?;
494        if !scanned_node.validated {
495            return Err(format_err!("No node at {}", id));
496        }
497        let mut nodes_in_tree = vec![];
498        let mut properties_under = vec![];
499        for node_id in scanned_node.children.iter() {
500            let (mut nodes_of, mut properties_of) = self.make_valid_node_tree(*node_id)?;
501            nodes_in_tree.append(&mut nodes_of);
502            properties_under.append(&mut properties_of);
503        }
504        for property_id in scanned_node.properties.iter() {
505            properties_under.push((self.make_valid_property(*property_id)?, *property_id));
506        }
507        let name = if id == BlockIndex::ROOT {
508            ROOT_NAME.to_owned()
509        } else {
510            self.use_owned_name(scanned_node.name)?
511        };
512        let this_node = Node {
513            name,
514            parent: scanned_node.parent,
515            children: scanned_node.children.clone(),
516            properties: scanned_node.properties.clone(),
517        };
518        nodes_in_tree.push((this_node, id));
519        Ok((nodes_in_tree, properties_under))
520    }
521
522    fn make_valid_property(&mut self, id: BlockIndex) -> Result<Property, Error> {
523        let scanned_property = self.use_property(id)?;
524        let name = self.use_owned_name(scanned_property.name)?;
525        let payload = self.make_valid_payload(scanned_property.payload)?;
526        Ok(Property { id, name, parent: scanned_property.parent, payload })
527    }
528
529    fn make_valid_payload(&mut self, payload: ScannedPayload) -> Result<Payload, Error> {
530        Ok(match payload {
531            ScannedPayload::Int(data) => Payload::Int(data),
532            ScannedPayload::Uint(data) => Payload::Uint(data),
533            ScannedPayload::Double(data) => Payload::Double(data),
534            ScannedPayload::Bool(data) => Payload::Bool(data),
535            ScannedPayload::IntArray(data, format) => Payload::IntArray(data, format),
536            ScannedPayload::UintArray(data, format) => Payload::UintArray(data, format),
537            ScannedPayload::DoubleArray(data, format) => Payload::DoubleArray(data, format),
538            ScannedPayload::StringArray(indexes) => Payload::StringArray(
539                indexes
540                    .iter()
541                    .map(|i| {
542                        if *i == BlockIndex::EMPTY {
543                            return "".into();
544                        }
545                        self.final_dereferenced_strings.get(i).unwrap().clone()
546                    })
547                    .collect(),
548            ),
549            ScannedPayload::Bytes { length, link } => {
550                Payload::Bytes(self.make_valid_vector(length, link)?)
551            }
552            ScannedPayload::String { length, link } => {
553                Payload::String(if let Some(length) = length {
554                    std::str::from_utf8(&self.make_valid_vector(length, link)?)?.to_owned()
555                } else {
556                    self.final_dereferenced_strings.get(&link).unwrap().clone()
557                })
558            }
559            ScannedPayload::Link { disposition, scanned_tree } => {
560                Payload::Link { disposition, parsed_data: scanned_tree.data() }
561            }
562        })
563    }
564
565    fn expand_string_reference(
566        &mut self,
567        mut block: ScannedStringReference,
568    ) -> Result<String, Error> {
569        let length_of_inlined = block.value.len();
570        if block.next_extent != BlockIndex::EMPTY {
571            block.value.append(
572                &mut self.make_valid_vector(block.length - length_of_inlined, block.next_extent)?,
573            );
574        }
575
576        Ok(String::from_utf8(block.value)?)
577    }
578
579    fn make_valid_vector(&mut self, length: usize, link: BlockIndex) -> Result<Vec<u8>, Error> {
580        let mut dest = vec![];
581        let mut length_remaining = length;
582        let mut next_link = link;
583        while length_remaining > 0 {
584            // This is effectively use_extent()
585            let mut extent = self
586                .extents
587                .remove(&next_link)
588                .ok_or_else(|| format_err!("No extent at {}", next_link))?;
589            let copy_len = min(extent.data.len(), length_remaining);
590            extent.metrics.set_data_bytes(copy_len);
591            self.metrics.record(&extent.metrics, BlockStatus::Used);
592            dest.extend_from_slice(&extent.data[..copy_len]);
593            length_remaining -= copy_len;
594            next_link = extent.next;
595        }
596        Ok(dest)
597    }
598}
599
600#[derive(Debug)]
601struct ScannedNode {
602    // These may be created two ways: Either from being named as a parent, or
603    // from being processed in the VMO. Those named but not yet processed will
604    // have validated = false. Of course after a complete VMO scan,
605    // everything descended from a root node must be validated.
606    // validated refers to the binary contents of this block; it doesn't
607    // guarantee that properties, descendents, name, etc. are valid.
608    validated: bool,
609    name: BlockIndex,
610    parent: BlockIndex,
611    children: HashSet<BlockIndex>,
612    properties: HashSet<BlockIndex>,
613    metrics: Option<BlockMetrics>,
614}
615
616#[derive(Debug)]
617struct ScannedProperty {
618    name: BlockIndex,
619    parent: BlockIndex,
620    payload: ScannedPayload,
621    metrics: BlockMetrics,
622}
623
624#[derive(Debug)]
625struct ScannedStringReference {
626    index: BlockIndex,
627    value: Vec<u8>,
628    length: usize,
629    next_extent: BlockIndex,
630}
631
632#[derive(Debug)]
633struct ScannedName {
634    name: String,
635    metrics: BlockMetrics,
636}
637
638#[derive(Debug)]
639struct ScannedExtent {
640    next: BlockIndex,
641    data: Vec<u8>,
642    metrics: BlockMetrics,
643}
644
645#[derive(Debug)]
646enum ScannedPayload {
647    String {
648        // length might be `None` if `link` points to a `StringReference`, because the
649        // `StringReference` encodes its own length parameter
650        length: Option<usize>,
651        link: BlockIndex,
652    },
653    Bytes {
654        length: usize,
655        link: BlockIndex,
656    },
657    Int(i64),
658    Uint(u64),
659    Double(f64),
660    Bool(bool),
661    IntArray(Vec<i64>, ArrayFormat),
662    UintArray(Vec<u64>, ArrayFormat),
663    DoubleArray(Vec<f64>, ArrayFormat),
664    StringArray(Vec<BlockIndex>),
665    Link {
666        disposition: LinkNodeDisposition,
667        scanned_tree: Box<Scanner>,
668    },
669}
670
671trait BuildScannedPayload<K> {
672    fn build(block: ScannedBlock<'_, K>, _scanner: &mut Scanner) -> Result<ScannedPayload, Error>;
673}
674
675impl BuildScannedPayload<Int> for ScannedPayload {
676    fn build(block: ScannedBlock<'_, Int>, _scanner: &mut Scanner) -> Result<Self, Error> {
677        Ok(Self::Int(block.value()))
678    }
679}
680
681impl BuildScannedPayload<Uint> for ScannedPayload {
682    fn build(block: ScannedBlock<'_, Uint>, _scanner: &mut Scanner) -> Result<Self, Error> {
683        Ok(Self::Uint(block.value()))
684    }
685}
686
687impl BuildScannedPayload<Double> for ScannedPayload {
688    fn build(block: ScannedBlock<'_, Double>, _scanner: &mut Scanner) -> Result<Self, Error> {
689        Ok(Self::Double(block.value()))
690    }
691}
692
693impl BuildScannedPayload<Bool> for ScannedPayload {
694    fn build(block: ScannedBlock<'_, Bool>, _scanner: &mut Scanner) -> Result<Self, Error> {
695        Ok(Self::Bool(block.value()))
696    }
697}
698
699impl BuildScannedPayload<Buffer> for ScannedPayload {
700    fn build(block: ScannedBlock<'_, Buffer>, _scanner: &mut Scanner) -> Result<Self, Error> {
701        let format = block.format().ok_or_else(|| format_err!("invalid format"))?;
702        let link = block.extent_index();
703        Ok(match format {
704            PropertyFormat::String => {
705                let length = Some(block.total_length());
706                ScannedPayload::String { length, link }
707            }
708            PropertyFormat::Bytes => {
709                let length = block.total_length();
710                ScannedPayload::Bytes { length, link }
711            }
712            PropertyFormat::StringReference => ScannedPayload::String { link, length: None },
713        })
714    }
715}
716
717impl BuildScannedPayload<Array<Unknown>> for ScannedPayload {
718    fn build(
719        block: ScannedBlock<'_, Array<Unknown>>,
720        _scanner: &mut Scanner,
721    ) -> Result<Self, Error> {
722        let entry_type =
723            block.entry_type().ok_or_else(|| format_err!("unknown array entry type"))?;
724        let array_format = block.format().ok_or_else(|| format_err!("unknown array format"))?;
725        let slots = block.slots();
726        match entry_type {
727            BlockType::IntValue => {
728                let block = block.cast_array::<Int>().unwrap();
729                let numbers: Result<Vec<i64>, _> = (0..slots)
730                    .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
731                    .collect();
732                Ok(ScannedPayload::IntArray(numbers?, array_format))
733            }
734            BlockType::UintValue => {
735                let block = block.cast_array::<Uint>().unwrap();
736                let numbers: Result<Vec<u64>, _> = (0..slots)
737                    .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
738                    .collect();
739                Ok(ScannedPayload::UintArray(numbers?, array_format))
740            }
741            BlockType::DoubleValue => {
742                let block = block.cast_array::<Double>().unwrap();
743                let numbers: Result<Vec<f64>, _> = (0..slots)
744                    .map(|i| block.get(i).ok_or_else(|| format_err!("no entry at index: {i}")))
745                    .collect();
746                Ok(ScannedPayload::DoubleArray(numbers?, array_format))
747            }
748            BlockType::StringReference => {
749                let block = block.cast_array::<StringRef>().unwrap();
750                let indexes: Result<Vec<BlockIndex>, _> = (0..slots)
751                    .map(|i| {
752                        block
753                            .get_string_index_at(i)
754                            .ok_or_else(|| format_err!("no entry at index: {i}"))
755                    })
756                    .collect();
757                Ok(ScannedPayload::StringArray(indexes?))
758            }
759            illegal_type => {
760                Err(format_err!("No way I should see {:?} for ArrayEntryType", illegal_type))
761            }
762        }
763    }
764}
765
766impl BuildScannedPayload<Link> for ScannedPayload {
767    fn build(block: ScannedBlock<'_, Link>, scanner: &mut Scanner) -> Result<Self, Error> {
768        let child_name = scanner
769            .lookup_name_or_string_reference(block.content_index())
770            .context(format_err!("Child name not found for LinkValue block {}.", block.index()))?;
771        let child_trees = scanner
772            .child_trees
773            .as_mut()
774            .ok_or_else(|| format_err!("LinkValue encountered without child tree."))?;
775        let child_tree = child_trees.remove(&child_name).ok_or_else(|| {
776            format_err!(
777                "Lazy node not found for LinkValue block {} with name {}.",
778                block.index(),
779                child_name
780            )
781        })?;
782        Ok(ScannedPayload::Link {
783            disposition: block
784                .link_node_disposition()
785                .ok_or_else(|| format_err!("invalid disposition"))?,
786            scanned_tree: Box::new(Scanner::try_from(child_tree)?),
787        })
788    }
789}
790
791#[cfg(test)]
792mod tests {
793    use super::*;
794    use crate::*;
795    use fidl_diagnostics_validate::*;
796    use fuchsia_inspect::reader::snapshot::BackingBuffer;
797    use inspect_format::{
798        Block, BlockAccessorExt, BlockAccessorMutExt, HeaderFields, PayloadFields, ReadBytes,
799        constants,
800    };
801    use num_traits::ToPrimitive;
802
803    // TODO(https://fxbug.dev/42115894): Depending on the resolution of https://fxbug.dev/42115938, move this const out of mod test.
804    const MAX_BLOCK_BITS: usize = constants::MAX_ORDER_SIZE * BITS_PER_BYTE;
805
806    fn copy_into(source: &[u8], dest: &mut [u8], offset: usize) {
807        dest[offset..offset + source.len()].copy_from_slice(source);
808    }
809
810    // Run "fx test inspect-validator-test -- --nocapture" to see all the output
811    // and verify you're getting appropriate error messages for each tweaked byte.
812    // (The alternative is hard-coding expected error strings, which is possible but ugh.)
813    fn try_byte(
814        buffer: &mut [u8],
815        (index, offset): (usize, usize),
816        value: u8,
817        predicted: Option<&str>,
818    ) {
819        let location = index * 16 + offset;
820        let previous = buffer[location];
821        buffer[location] = value;
822        let actual = data::Scanner::try_from(buffer as &[u8]).map(|d| d.data().to_string());
823
824        match (&predicted, &actual) {
825            (None, Err(actual)) => {
826                println!("With ({index},{offset}) -> {value}, got expected error {actual:?}");
827            }
828            (None, Ok(actual)) => {
829                println!(
830                    "BAD: With ({},{}) -> {}, expected error but got string {:?}",
831                    index, offset, value, actual
832                );
833            }
834            (Some(_), Err(actual)) => {
835                println!(
836                    "BAD: With ({index},{offset}) -> {value}, got unexpected error {actual:?}"
837                );
838            }
839            (Some(predicted), Ok(actual)) => {
840                if predicted == actual {
841                    println!(
842                        "With ({},{}) -> {}, got expected string {:?}",
843                        index, offset, value, predicted
844                    );
845                } else {
846                    println!(
847                        "BAD: With ({},{}) -> {}, expected string {:?} but got {:?}",
848                        index, offset, value, predicted, actual
849                    );
850                    println!("Raw data: {:?}", data::Scanner::try_from(buffer as &[u8]))
851                }
852            }
853        }
854        assert_eq!(predicted, actual.as_ref().ok().map(|s| &s[..]));
855        buffer[location] = previous;
856    }
857
858    fn put_header<T: ReadBytes>(header: &Block<&mut T, Unknown>, buffer: &mut [u8], index: usize) {
859        copy_into(&HeaderFields::value(header).to_le_bytes(), buffer, index * 16);
860    }
861
862    fn put_payload<T: ReadBytes>(
863        payload: &Block<&mut T, Unknown>,
864        buffer: &mut [u8],
865        index: usize,
866    ) {
867        copy_into(&PayloadFields::value(payload).to_le_bytes(), buffer, index * 16 + 8);
868    }
869
870    #[fuchsia::test]
871    fn test_scanning_string_reference() {
872        let mut buffer = [0u8; 4096];
873        const NODE: BlockIndex = BlockIndex::new(3);
874        const NUMBER_NAME: BlockIndex = BlockIndex::new(4);
875        const NUMBER_EXTENT: BlockIndex = BlockIndex::new(5);
876
877        // VMO Header block (index 0)
878        let mut container = [0u8; 16];
879        let mut header = container.block_at_mut(BlockIndex::EMPTY);
880        HeaderFields::set_order(&mut header, 0);
881        HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
882        HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
883        HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
884        put_header(&header, &mut buffer, (*BlockIndex::HEADER).try_into().unwrap());
885
886        // create a Node named number
887        HeaderFields::set_order(&mut header, 0);
888        HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
889        HeaderFields::set_value_name_index(&mut header, *NUMBER_NAME);
890        HeaderFields::set_value_parent_index(&mut header, *BlockIndex::HEADER);
891        put_header(&header, &mut buffer, (*NODE).try_into().unwrap());
892
893        // create a STRING_REFERENCE with value "number" that is the above Node's name.
894        HeaderFields::set_order(&mut header, 0);
895        HeaderFields::set_block_type(&mut header, BlockType::StringReference.to_u8().unwrap());
896        HeaderFields::set_extent_next_index(&mut header, *NUMBER_EXTENT);
897        put_header(&header, &mut buffer, (*NUMBER_NAME).try_into().unwrap());
898        copy_into(&[6, 0, 0, 0], &mut buffer, (*NUMBER_NAME * 16 + 8).try_into().unwrap());
899        copy_into(b"numb", &mut buffer, (*NUMBER_NAME * 16 + 12).try_into().unwrap());
900        let mut container = [0u8; 16];
901        let mut number_extent = container.block_at_mut(BlockIndex::EMPTY);
902        HeaderFields::set_order(&mut number_extent, 0);
903        HeaderFields::set_block_type(&mut number_extent, BlockType::Extent.to_u8().unwrap());
904        HeaderFields::set_extent_next_index(&mut number_extent, 0);
905        put_header(&number_extent, &mut buffer, (*NUMBER_EXTENT).try_into().unwrap());
906        copy_into(b"er", &mut buffer, (*NUMBER_EXTENT * 16 + 8).try_into().unwrap());
907
908        try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> number ->"));
909    }
910
911    #[fuchsia::test]
912    fn test_scanning_logic() {
913        let mut buffer = [0u8; 4096];
914        // VMO Header block (index 0)
915        const HEADER: usize = 0;
916        {
917            let mut container = [0u8; 16];
918            let mut header = container.block_at_mut(BlockIndex::EMPTY);
919            HeaderFields::set_order(&mut header, 0);
920            HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
921            HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
922            HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
923            put_header(&header, &mut buffer, HEADER);
924        }
925        const ROOT: usize = 1;
926        {
927            let mut container = [0u8; 16];
928            let mut header = container.block_at_mut(BlockIndex::EMPTY);
929            HeaderFields::set_order(&mut header, 0);
930            HeaderFields::set_block_type(&mut header, BlockType::NodeValue.to_u8().unwrap());
931            HeaderFields::set_value_name_index(&mut header, 2);
932            HeaderFields::set_value_parent_index(&mut header, 0);
933            put_header(&header, &mut buffer, ROOT);
934        }
935
936        // Root's Name block
937        const ROOT_NAME: usize = 2;
938        {
939            let mut container = [0u8; 16];
940            let mut header = container.block_at_mut(BlockIndex::EMPTY);
941            HeaderFields::set_order(&mut header, 0);
942            HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
943            HeaderFields::set_name_length(&mut header, 4);
944            put_header(&header, &mut buffer, ROOT_NAME);
945        }
946        copy_into(b"node", &mut buffer, ROOT_NAME * 16 + 8);
947        try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> node ->"));
948        // Mess up HEADER_MAGIC_NUMBER - it should fail to load.
949        try_byte(&mut buffer, (HEADER, 7), 0, None);
950        // Mess up node's parent; should disappear.
951        try_byte(&mut buffer, (ROOT, 1), 1, Some("root ->"));
952        // Mess up root's name; should fail.
953        try_byte(&mut buffer, (ROOT, 5), 1, None);
954        // Mess up generation count; should fail (and not hang).
955        try_byte(&mut buffer, (HEADER, 8), 1, None);
956        // But an even generation count should work.
957        try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->"));
958
959        // Let's give it a property.
960        const NUMBER: usize = 4;
961        let mut container = [0u8; 16];
962        let mut number_header = container.block_at_mut(BlockIndex::EMPTY);
963        HeaderFields::set_order(&mut number_header, 0);
964        HeaderFields::set_block_type(&mut number_header, BlockType::IntValue.to_u8().unwrap());
965        HeaderFields::set_value_name_index(&mut number_header, 3);
966        HeaderFields::set_value_parent_index(&mut number_header, 1);
967        put_header(&number_header, &mut buffer, NUMBER);
968        const NUMBER_NAME: usize = 3;
969        {
970            let mut container = [0u8; 16];
971            let mut header = container.block_at_mut(BlockIndex::EMPTY);
972            HeaderFields::set_order(&mut header, 0);
973            HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
974            HeaderFields::set_name_length(&mut header, 6);
975            put_header(&header, &mut buffer, NUMBER_NAME);
976            copy_into(b"number", &mut buffer, NUMBER_NAME * 16 + 8);
977        }
978
979        try_byte(&mut buffer, (HEADER, 8), 2, Some("root ->\n> node ->\n> > number: Int(0)"));
980        try_byte(&mut buffer, (NUMBER, 1), 5, Some("root ->\n> node ->\n> > number: Uint(0)"));
981        try_byte(&mut buffer, (NUMBER, 1), 6, Some("root ->\n> node ->\n> > number: Double(0.0)"));
982        try_byte(&mut buffer, (NUMBER, 1), 7, Some("root ->\n> node ->\n> > number: String(\"\")"));
983        // Array block will have illegal Array Entry Type of 0.
984        try_byte(&mut buffer, (NUMBER, 1), 0xb0, None);
985        // 15 is an illegal block type.
986        try_byte(&mut buffer, (NUMBER, 1), 0xf, None);
987        HeaderFields::set_order(&mut number_header, 2);
988        HeaderFields::set_block_type(&mut number_header, BlockType::ArrayValue.to_u8().unwrap());
989        put_header(&number_header, &mut buffer, NUMBER);
990        // Array block again has illegal Array Entry Type of 0.
991        try_byte(&mut buffer, (128, 0), 0, None);
992        // 4, 5, and 6 are legal array types.
993        try_byte(
994            &mut buffer,
995            (NUMBER, 8),
996            0x04,
997            Some("root ->\n> node ->\n> > number: IntArray([], Default)"),
998        );
999        try_byte(
1000            &mut buffer,
1001            (NUMBER, 8),
1002            0x05,
1003            Some("root ->\n> node ->\n> > number: UintArray([], Default)"),
1004        );
1005        try_byte(
1006            &mut buffer,
1007            (NUMBER, 8),
1008            0x06,
1009            Some("root ->\n> node ->\n> > number: DoubleArray([], Default)"),
1010        );
1011        // 0, 1, and 2 are legal formats.
1012        try_byte(
1013            &mut buffer,
1014            (NUMBER, 8),
1015            0x14,
1016            Some("root ->\n> node ->\n> > number: IntArray([], LinearHistogram)"),
1017        );
1018        try_byte(
1019            &mut buffer,
1020            (NUMBER, 8),
1021            0x24,
1022            Some("root ->\n> node ->\n> > number: IntArray([], ExponentialHistogram)"),
1023        );
1024        try_byte(&mut buffer, (NUMBER, 8), 0x34, None);
1025        // Let's make sure other Value block-type numbers are rejected.
1026        try_byte(&mut buffer, (NUMBER, 8), BlockType::ArrayValue.to_u8().unwrap(), None);
1027        buffer[NUMBER * 16 + 8] = 4; // Int, Default
1028        buffer[NUMBER * 16 + 9] = 2; // 2 entries
1029        try_byte(
1030            &mut buffer,
1031            (NUMBER, 16),
1032            42,
1033            Some("root ->\n> node ->\n> > number: IntArray([42, 0], Default)"),
1034        );
1035        try_byte(
1036            &mut buffer,
1037            (NUMBER, 24),
1038            42,
1039            Some("root ->\n> node ->\n> > number: IntArray([0, 42], Default)"),
1040        );
1041    }
1042
1043    #[fuchsia::test]
1044    async fn test_to_string_order() -> Result<(), Error> {
1045        // Make sure property payloads are distinguished by name, value, and type
1046        // but ignore id and parent, and that prefix is used.
1047        let int0 = Property {
1048            name: "int0".into(),
1049            id: 2.into(),
1050            parent: 1.into(),
1051            payload: Payload::Int(0),
1052        }
1053        .to_string("");
1054        let int1_struct = Property {
1055            name: "int1".into(),
1056            id: 2.into(),
1057            parent: 1.into(),
1058            payload: Payload::Int(1),
1059        };
1060        let int1 = int1_struct.to_string("");
1061        assert_ne!(int0, int1);
1062        let uint0 = Property {
1063            name: "uint0".into(),
1064            id: 2.into(),
1065            parent: 1.into(),
1066            payload: Payload::Uint(0),
1067        }
1068        .to_string("");
1069        assert_ne!(int0, uint0);
1070        let int0_different_name = Property {
1071            name: "int0_different_name".into(),
1072            id: 2.into(),
1073            parent: 1.into(),
1074            payload: Payload::Int(0),
1075        }
1076        .to_string("");
1077        assert_ne!(int0, int0_different_name);
1078        let uint0_different_ids = Property {
1079            name: "uint0".into(),
1080            id: 3.into(),
1081            parent: 4.into(),
1082            payload: Payload::Uint(0),
1083        }
1084        .to_string("");
1085        assert_eq!(uint0, uint0_different_ids);
1086        let int1_different_prefix = int1_struct.to_string("foo");
1087        assert_ne!(int1, int1_different_prefix);
1088        // Test that order doesn't matter. Use a real VMO rather than Data's
1089        // HashMaps which may not reflect order of addition.
1090        let mut puppet1 = puppet::tests::local_incomplete_puppet().await?;
1091        let mut child1_action = create_node!(parent:0, id:1, name:"child1");
1092        let mut child2_action = create_node!(parent:0, id:2, name:"child2");
1093        let mut property1_action =
1094            create_numeric_property!(parent:0, id:1, name:"prop1", value: Value::IntT(1));
1095        let mut property2_action =
1096            create_numeric_property!(parent:0, id:2, name:"prop2", value: Value::IntT(2));
1097        puppet1.apply(&mut child1_action).await?;
1098        puppet1.apply(&mut child2_action).await?;
1099        let mut puppet2 = puppet::tests::local_incomplete_puppet().await?;
1100        puppet2.apply(&mut child2_action).await?;
1101        puppet2.apply(&mut child1_action).await?;
1102        assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1103        puppet1.apply(&mut property1_action).await?;
1104        puppet1.apply(&mut property2_action).await?;
1105        puppet2.apply(&mut property2_action).await?;
1106        puppet2.apply(&mut property1_action).await?;
1107        assert_eq!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1108        // Make sure the tree distinguishes based on node position
1109        puppet1 = puppet::tests::local_incomplete_puppet().await?;
1110        puppet2 = puppet::tests::local_incomplete_puppet().await?;
1111        let mut subchild2_action = create_node!(parent:1, id:2, name:"child2");
1112        puppet1.apply(&mut child1_action).await?;
1113        puppet2.apply(&mut child1_action).await?;
1114        puppet1.apply(&mut child2_action).await?;
1115        puppet2.apply(&mut subchild2_action).await?;
1116        assert_ne!(puppet1.read_data().await?.to_string(), puppet2.read_data().await?.to_string());
1117        // ... and property position
1118        let mut subproperty2_action =
1119            create_numeric_property!(parent:1, id:2, name:"prop2", value: Value::IntT(1));
1120        puppet1.apply(&mut child1_action).await?;
1121        puppet2.apply(&mut child1_action).await?;
1122        puppet1.apply(&mut property2_action).await?;
1123        puppet2.apply(&mut subproperty2_action).await?;
1124        Ok(())
1125    }
1126
1127    #[fuchsia::test]
1128    fn test_bit_ops() -> Result<(), Error> {
1129        assert_eq!(low_bits(0xff, 3), 7);
1130        assert_eq!(low_bits(0x04, 3), 4);
1131        assert_eq!(low_bits(0xf8, 3), 0);
1132        assert_eq!(low_bits(0xab, 99), 0xab);
1133        assert_eq!(low_bits(0xff, 0), 0);
1134        assert_eq!(high_bits(0xff, 3), 0xe0);
1135        assert_eq!(high_bits(0x20, 3), 0x20);
1136        assert_eq!(high_bits(0x1f, 3), 0);
1137        assert_eq!(high_bits(0xab, 99), 0xab);
1138        assert_eq!(high_bits(0xff, 0), 0);
1139        Ok(())
1140    }
1141
1142    #[fuchsia::test]
1143    fn test_zero_bits() -> Result<(), Error> {
1144        let mut buffer = [0u8; 48];
1145        for byte in buffer.iter_mut().take(16) {
1146            *byte = 0xff;
1147        }
1148        for byte in buffer.iter_mut().skip(32) {
1149            *byte = 0xff;
1150        }
1151        {
1152            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1153            let block = backing_buffer.block_at(1.into());
1154            assert!(check_zero_bits(&buffer, &block, 1, 0).is_err());
1155            assert!(check_zero_bits(&buffer, &block, 0, 0).is_ok());
1156            assert!(check_zero_bits(&buffer, &block, 0, MAX_BLOCK_BITS).is_ok());
1157        }
1158        // Don't mess with buffer[0]; that defines block size and type.
1159        // The block I'm testing (index 1) is in between two all-ones blocks.
1160        // Its bytes are thus 16..23 in the buffer.
1161        buffer[1 + 16] = 1;
1162        // Now bit 8 of the block is 1. Checking any range that includes bit 8 should give an
1163        // error (even single-bit 8...8). Other ranges should succeed.
1164        {
1165            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1166            let block = backing_buffer.block_at(1.into());
1167            assert!(check_zero_bits(&buffer, &block, 8, 8).is_err());
1168            assert!(check_zero_bits(&buffer, &block, 8, MAX_BLOCK_BITS).is_err());
1169            assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_ok());
1170        }
1171        buffer[2 + 16] = 0x80;
1172        // Now bits 8 and 23 are 1. The range 9...MAX_BLOCK_BITS that succeeded before should fail.
1173        // 9...22 and 24...MAX_BLOCK_BITS should succeed. So should 24...63.
1174        {
1175            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1176            let block = backing_buffer.block_at(1.into());
1177            assert!(check_zero_bits(&buffer, &block, 9, MAX_BLOCK_BITS).is_err());
1178            assert!(check_zero_bits(&buffer, &block, 9, 22).is_ok());
1179            assert!(check_zero_bits(&buffer, &block, 24, MAX_BLOCK_BITS).is_ok());
1180            assert!(check_zero_bits(&buffer, &block, 24, 63).is_ok());
1181        }
1182        buffer[2 + 16] = 0x20;
1183        // Now bits 8 and 21 are 1. This tests bit-checks in the middle of the byte.
1184        {
1185            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1186            let block = backing_buffer.block_at(1.into());
1187            assert!(check_zero_bits(&buffer, &block, 16, 20).is_ok());
1188            assert!(check_zero_bits(&buffer, &block, 21, 21).is_err());
1189            assert!(check_zero_bits(&buffer, &block, 22, 63).is_ok());
1190        }
1191        buffer[7 + 16] = 0x80;
1192        // Now bits 8, 21, and 63 are 1. Checking 22...63 should fail; 22...62 should succeed.
1193        {
1194            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1195            let block = backing_buffer.block_at(1.into());
1196            assert!(check_zero_bits(&buffer, &block, 22, 63).is_err());
1197            assert!(check_zero_bits(&buffer, &block, 22, 62).is_ok());
1198        }
1199        buffer[3 + 16] = 0x10;
1200        // Here I'm testing whether 1 bits in the bytes between the ends of the range are also
1201        // detected (cause the check to fail) (to make sure my loop doesn't have an off by 1 error).
1202        {
1203            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1204            let block = backing_buffer.block_at(1.into());
1205            assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1206        }
1207        buffer[3 + 16] = 0;
1208        buffer[4 + 16] = 0x10;
1209        {
1210            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1211            let block = backing_buffer.block_at(1.into());
1212            assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1213        }
1214        buffer[4 + 16] = 0;
1215        buffer[5 + 16] = 0x10;
1216        {
1217            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1218            let block = backing_buffer.block_at(1.into());
1219            assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1220        }
1221        buffer[5 + 16] = 0;
1222        buffer[6 + 16] = 0x10;
1223        {
1224            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1225            let block = backing_buffer.block_at(1.into());
1226            assert!(check_zero_bits(&buffer, &block, 22, 62).is_err());
1227        }
1228        buffer[1 + 16] = 0x81;
1229        // Testing whether I can correctly ignore 1 bits within a single byte that are outside
1230        // the specified range, and detect 1 bits that are inside the range.
1231        {
1232            let backing_buffer = BackingBuffer::from(buffer.to_vec());
1233            let block = backing_buffer.block_at(1.into());
1234            assert!(check_zero_bits(&buffer, &block, 9, 14).is_ok());
1235            assert!(check_zero_bits(&buffer, &block, 8, 14).is_err());
1236            assert!(check_zero_bits(&buffer, &block, 9, 15).is_err());
1237        }
1238        Ok(())
1239    }
1240
1241    #[fuchsia::test]
1242    fn test_reserved_fields() {
1243        let mut buffer = [0u8; 4096];
1244        // VMO Header block (index 0)
1245        const HEADER: usize = 0;
1246        {
1247            let mut container = [0u8; 16];
1248            let mut header = container.block_at_mut(BlockIndex::EMPTY);
1249            HeaderFields::set_order(&mut header, 0);
1250            HeaderFields::set_block_type(&mut header, BlockType::Header.to_u8().unwrap());
1251            HeaderFields::set_header_magic(&mut header, constants::HEADER_MAGIC_NUMBER);
1252            HeaderFields::set_header_version(&mut header, constants::HEADER_VERSION_NUMBER);
1253            put_header(&header, &mut buffer, HEADER);
1254        }
1255        const VALUE: usize = 1;
1256        let mut container = [0u8; 16];
1257        let mut value_header = container.block_at_mut(BlockIndex::EMPTY);
1258        HeaderFields::set_order(&mut value_header, 0);
1259        HeaderFields::set_block_type(&mut value_header, BlockType::NodeValue.to_u8().unwrap());
1260        HeaderFields::set_value_name_index(&mut value_header, 2);
1261        HeaderFields::set_value_parent_index(&mut value_header, 0);
1262        put_header(&value_header, &mut buffer, VALUE);
1263        // Root's Name block
1264        const VALUE_NAME: usize = 2;
1265        {
1266            let mut buf = [0; 16];
1267            let mut header = buf.block_at_mut(0.into());
1268            HeaderFields::set_order(&mut header, 0);
1269            HeaderFields::set_block_type(&mut header, BlockType::Name.to_u8().unwrap());
1270            HeaderFields::set_name_length(&mut header, 5);
1271            put_header(&header, &mut buffer, VALUE_NAME);
1272        }
1273        copy_into(b"value", &mut buffer, VALUE_NAME * 16 + 8);
1274        // Extent block (not linked into tree)
1275        const EXTENT: usize = 3;
1276        {
1277            let mut container = [0u8; 16];
1278            let mut header = container.block_at_mut(BlockIndex::EMPTY);
1279            HeaderFields::set_order(&mut header, 0);
1280            HeaderFields::set_block_type(&mut header, BlockType::Extent.to_u8().unwrap());
1281            HeaderFields::set_extent_next_index(&mut header, 0);
1282            put_header(&header, &mut buffer, EXTENT);
1283        }
1284        // Let's make sure it scans.
1285        try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value ->"));
1286        // Put garbage in a random FREE block body - should fail.
1287        // TODO(https://fxbug.dev/42115894): Depending on the resolution of https://fxbug.dev/42115938, uncomment or delete this test.
1288        //try_byte(&mut buffer, (6, 9), 42, None);
1289        // Put garbage in a random FREE block header - should be fine.
1290        try_byte(&mut buffer, (6, 7), 42, Some("root ->\n> value ->"));
1291        // Put garbage in NAME header - should fail.
1292        try_byte(&mut buffer, (VALUE_NAME, 7), 42, None);
1293        // Put garbage in EXTENT header - should fail.
1294        try_byte(&mut buffer, (EXTENT, 6), 42, None);
1295        HeaderFields::set_block_type(&mut value_header, BlockType::ArrayValue.to_u8().unwrap());
1296        put_header(&value_header, &mut buffer, VALUE);
1297        {
1298            let mut container = [0u8; 16];
1299            let mut array_subheader = container.block_at_mut(BlockIndex::EMPTY);
1300            PayloadFields::set_array_entry_type(
1301                &mut array_subheader,
1302                BlockType::IntValue.to_u8().unwrap(),
1303            );
1304            PayloadFields::set_array_flags(
1305                &mut array_subheader,
1306                ArrayFormat::Default.to_u8().unwrap(),
1307            );
1308            put_payload(&array_subheader, &mut buffer, VALUE);
1309        }
1310        try_byte(&mut buffer, (16, 0), 0, Some("root ->\n> value: IntArray([], Default)"));
1311        // Put garbage in reserved part of Array spec, should fail.
1312        try_byte(&mut buffer, (VALUE, 12), 42, None);
1313        HeaderFields::set_block_type(&mut value_header, BlockType::IntValue.to_u8().unwrap());
1314        put_header(&value_header, &mut buffer, VALUE);
1315        // Now the array spec is just a (large) value; it should succeed.
1316        try_byte(&mut buffer, (VALUE, 12), 42, Some("root ->\n> value: Int(180388626436)"));
1317    }
1318}