luaur_analysis/methods/
lint_format_string_check_string_pack.rs1use 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}