Skip to main content

dxil_reader/
bitstream.rs

1//! A bounded reader of LLVM's bitstream container: blocks, abbreviations (literal, fixed, VBR, array, char6,
2//! blob) and the BLOCKINFO block. It knows nothing of IR; it returns a tree of blocks and records. Every length is
3//! checked against the bits that remain before anything is allocated, and nesting, abbreviations and the total
4//! number of operands are capped, so a crafted file errors instead of exhausting memory.
5use crate::{Result, error};
6use primase_foundations::bytes::View;
7
8/// Limits on what one bitstream may contain.
9const MAX_DEPTH: usize = 32;
10const MAX_ABBREVS_PER_BLOCK: usize = 4096;
11const MAX_ABBREV_OPS: usize = 256;
12const MAX_TOTAL_OPERANDS: usize = 1 << 26;
13
14/// A record: its code, operands and, for blob abbreviations, the blob.
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct Record {
17    /// The record code, whose meaning the block's id gives.
18    pub code: u64,
19    /// The operands, in order (an abbreviated array's elements are flattened into them).
20    pub operands: Vec<u64>,
21    /// The blob of a record whose abbreviation ends in one.
22    pub blob: Option<Vec<u8>>,
23    /// Bit offset of the record in the stream (bit 0 is the first bit of the `BC` magic), for error locations.
24    pub at: usize,
25    /// Bit offset just past the record: where the next element (record, abbreviation definition, block or END_BLOCK)
26    /// starts, so the record's bits are `at..end`.
27    pub end: usize,
28}
29/// What a block holds, in order.
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub enum Element {
32    /// A nested block.
33    Block(Block),
34    /// A record.
35    Record(Record),
36}
37/// A block: its id and what it holds.
38#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct Block {
40    /// The block id (LLVM's `MODULE_BLOCK_ID` and so on).
41    pub id: u64,
42    /// The block's records and nested blocks, in order.
43    pub elements: Vec<Element>,
44    /// Bit offset of the block's header (its ENTER_SUBBLOCK).
45    pub at: usize,
46    /// Bit offset just past the block: after its END_BLOCK and the 32-bit alignment that follows, so the block's bits
47    /// are `at..end`.
48    pub end: usize,
49}
50impl Block {
51    /// The nested blocks.
52    pub fn blocks(&self) -> impl Iterator<Item = &Block> {
53        self.elements.iter().filter_map(|e| match e {
54            Element::Block(b) => Some(b),
55            Element::Record(_) => None,
56        })
57    }
58    /// The records.
59    pub fn records(&self) -> impl Iterator<Item = &Record> {
60        self.elements.iter().filter_map(|e| match e {
61            Element::Record(r) => Some(r),
62            Element::Block(_) => None,
63        })
64    }
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68enum Op {
69    Literal(u64),
70    Fixed(u32),
71    Vbr(u32),
72    Array,
73    Char6,
74    Blob,
75}
76type Abbrev = Vec<Op>;
77
78/// The characters of the `char6` encoding, by code.
79const CHAR6: &[u8; 64] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._";
80
81struct Bits<'a> {
82    data: &'a [u8],
83    /// Next bit to read.
84    pos: usize,
85}
86impl Bits<'_> {
87    fn remaining(&self) -> usize {
88        self.data.len().saturating_mul(8).saturating_sub(self.pos)
89    }
90    fn read(&mut self, width: u32) -> Result<u64> {
91        if width > 64 {
92            return Err(error(self.pos, "field wider than 64 bits"));
93        }
94        let n = width as usize;
95        if n > self.remaining() {
96            return Err(error(self.pos, "bitstream ends inside a field"));
97        }
98        let mut value = 0u64;
99        for i in 0..width {
100            let bit = self.pos.saturating_add(i as usize);
101            let byte = self.data.get(bit / 8).copied().unwrap_or(0);
102            let shift = u32::try_from(bit % 8).unwrap_or(0);
103            if byte.checked_shr(shift).unwrap_or(0) & 1 == 1 {
104                value |= 1u64.checked_shl(i).unwrap_or(0);
105            }
106        }
107        self.pos = self.pos.saturating_add(n);
108        Ok(value)
109    }
110    fn vbr(&mut self, width: u32) -> Result<u64> {
111        if !(2..=32).contains(&width) {
112            return Err(error(self.pos, "VBR width outside 2..32"));
113        }
114        let at = self.pos;
115        let high = 1u64.checked_shl(width.saturating_sub(1)).unwrap_or(0);
116        let mut value = 0u64;
117        let mut shift = 0u32;
118        loop {
119            let chunk = self.read(width)?;
120            let payload = chunk & high.saturating_sub(1);
121            if payload != 0 {
122                // The payload's bits must all land below bit 64.
123                if shift >= 64 || payload.leading_zeros() < shift {
124                    return Err(error(at, "VBR value exceeds 64 bits"));
125                }
126                value |= payload.checked_shl(shift).unwrap_or(0);
127            }
128            if chunk & high == 0 {
129                return Ok(value);
130            }
131            shift = shift.saturating_add(width.saturating_sub(1));
132            if shift > 64 + 32 {
133                return Err(error(at, "VBR value exceeds 64 bits"));
134            }
135        }
136    }
137    fn align32(&mut self) -> Result<()> {
138        let aligned = self
139            .pos
140            .div_ceil(32)
141            .checked_mul(32)
142            .filter(|&aligned| aligned <= self.data.len().saturating_mul(8))
143            .ok_or_else(|| error(self.pos, "bitstream ends before 32-bit alignment"))?;
144        self.pos = aligned;
145        Ok(())
146    }
147    /// A VBR-encoded count or length, as a `usize`.
148    fn vbr_usize(&mut self, width: u32) -> Result<usize> {
149        let at = self.pos;
150        let value = self.vbr(width)?;
151        usize::try_from(value).map_err(|_| error(at, format!("{value} does not fit the address space")))
152    }
153    /// A VBR-encoded field that must fit 32 bits.
154    fn vbr_u32(&mut self, width: u32) -> Result<u32> {
155        let at = self.pos;
156        let value = self.vbr(width)?;
157        u32::try_from(value).map_err(|_| error(at, format!("{value} does not fit 32 bits")))
158    }
159}
160
161struct Reader<'a> {
162    bits: Bits<'a>,
163    /// Abbreviations BLOCKINFO defines, by block id.
164    info: Vec<(u64, Vec<Abbrev>)>,
165    operands: usize,
166}
167
168fn char6(v: u64) -> u64 {
169    let [index, ..] = v.to_le_bytes();
170    u64::from(CHAR6.get(usize::from(index)).copied().unwrap_or(b'_'))
171}
172
173impl Reader<'_> {
174    fn count(&mut self, n: usize) -> Result<()> {
175        self.operands = self
176            .operands
177            .checked_add(n)
178            .filter(|&t| t <= MAX_TOTAL_OPERANDS)
179            .ok_or_else(|| error(self.bits.pos, "too many record operands"))?;
180        Ok(())
181    }
182    fn scalar(&mut self, op: Op) -> Result<u64> {
183        match op {
184            Op::Literal(v) => Ok(v),
185            Op::Fixed(w) => self.bits.read(w),
186            Op::Vbr(w) => self.bits.vbr(w),
187            Op::Char6 => Ok(char6(self.bits.read(6)?)),
188            Op::Array | Op::Blob => Err(error(self.bits.pos, "array or blob as an element")),
189        }
190    }
191    fn define_abbrev(&mut self) -> Result<Abbrev> {
192        let at = self.bits.pos;
193        let n = self.bits.vbr_usize(5)?;
194        if n == 0 || n > MAX_ABBREV_OPS {
195            return Err(error(at, "abbreviation operand count"));
196        }
197        let mut ops = Vec::with_capacity(n);
198        while ops.len() < n {
199            if self.bits.read(1)? == 1 {
200                ops.push(Op::Literal(self.bits.vbr(8)?));
201                continue;
202            }
203            ops.push(match self.bits.read(3)? {
204                1 => {
205                    let w = self.bits.vbr(5)?;
206                    if w > 64 {
207                        return Err(error(at, "fixed width above 64"));
208                    }
209                    Op::Fixed(u32::try_from(w).map_err(|_| error(at, "fixed width above 64"))?)
210                }
211                2 => {
212                    let w = self.bits.vbr(5)?;
213                    if !(2..=32).contains(&w) {
214                        return Err(error(at, "VBR width outside 2..32"));
215                    }
216                    Op::Vbr(u32::try_from(w).map_err(|_| error(at, "VBR width outside 2..32"))?)
217                }
218                3 => Op::Array,
219                4 => Op::Char6,
220                5 => Op::Blob,
221                other => return Err(error(at, format!("abbreviation encoding {other}"))),
222            });
223        }
224        // An array takes the one operand after it as its element; a blob or array ends the abbreviation.
225        let mut rest = ops.as_slice();
226        while let Some((op, tail)) = rest.split_first() {
227            match (op, tail) {
228                (Op::Array, [Op::Array | Op::Blob, ..]) => {
229                    return Err(error(at, "array not followed by one element encoding"));
230                }
231                (Op::Array, [_]) => {}
232                (Op::Array, _) => {
233                    return Err(error(at, "array not followed by one element encoding"));
234                }
235                (Op::Blob, [_, ..]) => return Err(error(at, "blob not last")),
236                _ => {}
237            }
238            rest = tail;
239        }
240        Ok(ops)
241    }
242    fn abbreviated(&mut self, abbrev: &Abbrev, at: usize) -> Result<Record> {
243        let mut values: Vec<u64> = Vec::new();
244        let mut blob = None;
245        let mut rest = abbrev.as_slice();
246        while let Some((&op, tail)) = rest.split_first() {
247            rest = tail;
248            match op {
249                Op::Array => {
250                    let Some((&element, after)) = tail.split_first() else {
251                        return Err(error(at, "array without its element encoding"));
252                    };
253                    rest = after;
254                    let len = self.bits.vbr_usize(6)?;
255                    // An element stored takes its width in bits; a literal or zero-width one takes none, so it is
256                    // counted as one bit: the length of an array must not exceed the bits that remain, whatever its
257                    // elements are.
258                    let min_bits = match element {
259                        Op::Literal(_) | Op::Fixed(0) => 1,
260                        Op::Fixed(w) | Op::Vbr(w) => w as usize,
261                        Op::Char6 => 6,
262                        _ => 1,
263                    };
264                    if self
265                        .bits
266                        .remaining()
267                        .checked_div(min_bits)
268                        .is_none_or(|most| len > most)
269                    {
270                        return Err(error(at, "array longer than the bits that remain"));
271                    }
272                    self.count(len)?;
273                    values.reserve(len);
274                    for _ in 0..len {
275                        values.push(self.scalar(element)?);
276                    }
277                }
278                Op::Blob => {
279                    let len = self.bits.vbr_usize(6)?;
280                    self.bits.align32()?;
281                    if len > self.bits.remaining() / 8 {
282                        return Err(error(at, "blob longer than the bits that remain"));
283                    }
284                    let start = self.bits.pos / 8;
285                    let bytes = View::new(self.bits.data)
286                        .slice(start, len)
287                        .map_err(|e| error(at, e.to_string()))?;
288                    blob = Some(bytes.to_vec());
289                    self.bits.pos = self.bits.pos.saturating_add(len.saturating_mul(8));
290                    self.bits.align32()?;
291                }
292                op => {
293                    self.count(1)?;
294                    values.push(self.scalar(op)?);
295                }
296            }
297        }
298        if values.is_empty() {
299            return Err(error(at, "abbreviated record without a code"));
300        }
301        let code = values.remove(0);
302        Ok(Record {
303            code,
304            operands: values,
305            blob,
306            at,
307            end: self.bits.pos,
308        })
309    }
310    /// Read a block's body after its header, up to and including END_BLOCK.
311    fn block(&mut self, id: u64, width: u32, end: usize, depth: usize, at: usize) -> Result<Block> {
312        if depth > MAX_DEPTH {
313            return Err(error(at, "blocks nested too deeply"));
314        }
315        let mut abbrevs: Vec<Abbrev> = self
316            .info
317            .iter()
318            .find(|(b, _)| *b == id)
319            .map(|(_, a)| a.clone())
320            .unwrap_or_default();
321        let mut elements = Vec::new();
322        // In BLOCKINFO, the block id that following abbreviations apply to.
323        let mut info_target: Option<u64> = None;
324        loop {
325            if self.bits.pos >= end {
326                return Err(error(at, "block ends without END_BLOCK"));
327            }
328            let here = self.bits.pos;
329            match self.bits.read(width)? {
330                0 => {
331                    self.bits.align32()?;
332                    if self.bits.pos != end {
333                        return Err(error(here, "END_BLOCK before the declared block length"));
334                    }
335                    return Ok(Block {
336                        id,
337                        elements,
338                        at,
339                        end,
340                    });
341                }
342                1 => {
343                    let child = self.bits.vbr(8)?;
344                    let child_width = self.bits.vbr_u32(4)?;
345                    if !(1..=32).contains(&child_width) {
346                        return Err(error(here, "abbreviation width outside 1..32"));
347                    }
348                    self.bits.align32()?;
349                    let words = usize::try_from(self.bits.read(32)?)
350                        .map_err(|_| error(here, "block longer than its parent"))?;
351                    let child_end = words
352                        .checked_mul(32)
353                        .and_then(|b| b.checked_add(self.bits.pos))
354                        .filter(|&e| e <= end)
355                        .ok_or_else(|| error(here, "block longer than its parent"))?;
356                    let b = self.block(child, child_width, child_end, depth.saturating_add(1), here)?;
357                    elements.push(Element::Block(b));
358                }
359                2 => {
360                    let abbrev = self.define_abbrev()?;
361                    if id == 0 {
362                        let target =
363                            info_target.ok_or_else(|| error(here, "BLOCKINFO abbreviation before SETBID"))?;
364                        let slot = match self.info.iter().position(|(b, _)| *b == target) {
365                            Some(i) => i,
366                            None => {
367                                self.info.push((target, Vec::new()));
368                                self.info.len().saturating_sub(1)
369                            }
370                        };
371                        let Some((_, entry)) = self.info.get_mut(slot) else {
372                            return Err(error(here, "BLOCKINFO abbreviation table"));
373                        };
374                        if entry.len() >= MAX_ABBREVS_PER_BLOCK {
375                            return Err(error(here, "too many abbreviations"));
376                        }
377                        entry.push(abbrev);
378                    } else {
379                        if abbrevs.len() >= MAX_ABBREVS_PER_BLOCK {
380                            return Err(error(here, "too many abbreviations"));
381                        }
382                        abbrevs.push(abbrev);
383                    }
384                }
385                3 => {
386                    let code = self.bits.vbr(6)?;
387                    let n = self.bits.vbr_usize(6)?;
388                    if n > self.bits.remaining() / 2 {
389                        return Err(error(here, "record longer than the bits that remain"));
390                    }
391                    self.count(n)?;
392                    let mut operands = Vec::with_capacity(n);
393                    for _ in 0..n {
394                        operands.push(self.bits.vbr(6)?);
395                    }
396                    if id == 0 && code == 1 {
397                        info_target = Some(
398                            *operands
399                                .first()
400                                .ok_or_else(|| error(here, "SETBID without a block id"))?,
401                        );
402                    }
403                    elements.push(Element::Record(Record {
404                        code,
405                        operands,
406                        blob: None,
407                        at: here,
408                        end: self.bits.pos,
409                    }));
410                }
411                n => {
412                    let abbrev = usize::try_from(n.saturating_sub(4))
413                        .ok()
414                        .and_then(|i| abbrevs.get(i))
415                        .cloned()
416                        .ok_or_else(|| error(here, format!("undefined abbreviation {n}")))?;
417                    let record = self.abbreviated(&abbrev, here)?;
418                    if id == 0 && record.code == 1 {
419                        info_target = record.operands.first().copied();
420                    }
421                    elements.push(Element::Record(record));
422                }
423            }
424        }
425    }
426}
427
428/// Read a bitstream whose 32-bit magic has been checked: the top-level blocks (abbreviation width 2).
429pub fn read(data: &[u8], magic: [u8; 4]) -> Result<Vec<Block>> {
430    if data.get(..4) != Some(&magic[..]) || !data.len().is_multiple_of(4) {
431        return Err(error(0, "bitstream magic or length"));
432    }
433    let mut r = Reader {
434        bits: Bits { data, pos: 32 },
435        info: Vec::new(),
436        operands: 0,
437    };
438    let end = data.len().saturating_mul(8);
439    let mut blocks = Vec::new();
440    while r.bits.pos < end {
441        let here = r.bits.pos;
442        // Trailing zero padding after the last block is allowed.
443        if data
444            .get(here / 8..)
445            .is_none_or(|tail| tail.iter().all(|&b| b == 0))
446        {
447            break;
448        }
449        if r.bits.read(2)? != 1 {
450            return Err(error(here, "top level holds only blocks"));
451        }
452        let id = r.bits.vbr(8)?;
453        let width = r.bits.vbr_u32(4)?;
454        if !(1..=32).contains(&width) {
455            return Err(error(here, "abbreviation width outside 1..32"));
456        }
457        r.bits.align32()?;
458        let words =
459            usize::try_from(r.bits.read(32)?).map_err(|_| error(here, "block longer than the stream"))?;
460        let block_end = words
461            .checked_mul(32)
462            .and_then(|b| b.checked_add(r.bits.pos))
463            .filter(|&e| e <= end)
464            .ok_or_else(|| error(here, "block longer than the stream"))?;
465        blocks.push(r.block(id, width, block_end, 1, here)?);
466    }
467    Ok(blocks)
468}