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