Skip to main content

luaur_analysis/methods/
lint_format_string_check_string_pack.rs

1use crate::records::lint_format_string::LintFormatString;
2use core::ffi::c_char;
3
4impl LintFormatString {
5    #[inline]
6    pub fn check_string_pack(
7        &self,
8        data: *const c_char,
9        size: usize,
10        fixed: bool,
11    ) -> *const c_char {
12        let options = b"<>!=bBhHlLjJTiIfdnczsxX ";
13        let unsized_opts = b"<>!zX ";
14
15        let mut i = 0;
16        while i < size {
17            let ch = unsafe { *data.add(i) };
18
19            if !options.contains(&(ch as u8)) {
20                return c"unexpected character; must be a pack specifier or space".as_ptr();
21            }
22
23            if ch == b'c' as i8 && (i + 1 == size || !self.is_digit(unsafe { *data.add(i + 1) })) {
24                return c"fixed-sized string format must specify the size".as_ptr();
25            }
26
27            if ch == b'X' as i8
28                && (i + 1 == size || unsized_opts.contains(&(unsafe { *data.add(i + 1) } as u8)))
29            {
30                return c"X must be followed by a size specifier".as_ptr();
31            }
32
33            if fixed && (ch == b'z' as i8 || ch == b's' as i8) {
34                return c"pack specifier must be fixed-size".as_ptr();
35            }
36
37            if (ch == b'!' as i8
38                || ch == b'i' as i8
39                || ch == b'I' as i8
40                || ch == b'c' as i8
41                || ch == b's' as i8)
42                && i + 1 < size
43                && self.is_digit(unsafe { *data.add(i + 1) })
44            {
45                let isc = ch == b'c' as i8;
46
47                let mut v: u32 = 0;
48                while i + 1 < size
49                    && self.is_digit(unsafe { *data.add(i + 1) })
50                    && v <= (i32::MAX as u32 - 9) / 10
51                {
52                    let digit_ch = unsafe { *data.add(i + 1) };
53                    v = v * 10 + (digit_ch as u8 - b'0') as u32;
54                    i += 1;
55                }
56
57                if i + 1 < size && self.is_digit(unsafe { *data.add(i + 1) }) {
58                    return c"size specifier is too large".as_ptr();
59                }
60
61                if !isc && (v == 0 || v > 16) {
62                    return c"integer size must be in range [1,16]".as_ptr();
63                }
64            }
65
66            i += 1;
67        }
68
69        core::ptr::null()
70    }
71}