Skip to content

Commit

Permalink
Fixed macro panics
Browse files Browse the repository at this point in the history
  • Loading branch information
QnnOkabayashi committed Nov 2, 2021
1 parent 85c3dd7 commit 3fc629f
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 69 deletions.
12 changes: 10 additions & 2 deletions macros/src/lib.rs
Expand Up @@ -36,11 +36,19 @@ pub fn parse_lit(input: TokenStream) -> TokenStream {
let ts = TokenStream2::from(input);
let span = match e {
Error::UuidParse(error::Error(
error::ErrorKind::InvalidCharacter { index, .. },
error::ErrorKind::InvalidCharacter { found, index, .. },
)) => {
// Hack to find the byte width of the char
// so we can set the span accordingly.
let mut bytes = found as u32;
let mut width = 0;
while bytes != 0 {
bytes >>= 4;
width += 1;
}
let mut s = proc_macro2::Literal::string("");
s.set_span(ts.span());
s.subspan(index + 1..=index + 1).unwrap()
s.subspan(index + 1..index + width).unwrap()
}
Error::UuidParse(error::Error(
error::ErrorKind::InvalidGroupLength { found, index, .. },
Expand Down
33 changes: 33 additions & 0 deletions shared/error.rs
Expand Up @@ -81,6 +81,39 @@ impl fmt::Display for ExpectedLength {
}
}

impl Error {
pub(crate) fn character(found: char, index: usize, offset: usize) -> Self {
Error(ErrorKind::InvalidCharacter {
expected: "0123456789abcdefABCDEF-",
found,
index: index + offset,
urn: UrnPrefix::Optional,
})
}

pub(crate) fn group_count(expected: ExpectedLength, found: usize) -> Self {
Error(ErrorKind::InvalidGroupCount { expected, found })
}

pub(crate) fn group_length(
expected: ExpectedLength,
found: usize,
group: usize,
offset: usize,
) -> Self {
Error(ErrorKind::InvalidGroupLength {
expected,
found,
group,
index: [1, 10, 15, 20, 25][group] + offset,
})
}

pub(crate) fn length(expected: ExpectedLength, found: usize) -> Self {
Error(ErrorKind::InvalidLength { expected, found })
}
}

impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Error(kind)
Expand Down
101 changes: 41 additions & 60 deletions shared/parser.rs
Expand Up @@ -36,22 +36,24 @@ pub fn parse_str(mut input: &str) -> Result<[u8; 16], Error> {

let mut start = 0;
// Check for a URN prefixed UUID
if len == 45 && input.starts_with(URN_PREFIX) {
input = &input[URN_PREFIX.len()..];
start += URN_PREFIX.len();
if len == 45 {
if let Some(stripped) = input.strip_prefix(URN_PREFIX) {
input = stripped;
start = URN_PREFIX.len();
}
}
// Check for a Microsoft GUID wrapped in {}
else if len == 38 && input.starts_with("{") && input.ends_with("}") {
input = &input[1..input.len() - 1];
start += 1;
else if len == 38 {
if let Some(stripped) =
input.strip_prefix('{').and_then(|s| s.strip_suffix('}'))
{
input = stripped;
start = 1;
}
}
// In other cases, check for a simple or hyphenated UUID
else if !len_matches_any(len, &[36, 32]) {
return Err(ErrorKind::InvalidLength {
expected: ExpectedLength::Any(&[36, 32]),
found: len,
}
.into());
return Err(Error::length(ExpectedLength::Any(&[36, 32]), len));
}

// `digit` counts only hexadecimal digits, `i_char` counts all chars.
Expand All @@ -60,21 +62,17 @@ pub fn parse_str(mut input: &str) -> Result<[u8; 16], Error> {
let mut acc = 0;
let mut buffer = [0u8; 16];

for (i_char, chr) in input.bytes().enumerate() {
for (i_char, character) in input.char_indices() {
let chr = character as u8;
if digit as usize >= 32 && group != 4 {
if group == 0 {
return Err(ErrorKind::InvalidLength {
expected: ExpectedLength::Any(&[36, 32]),
found: len,
}
.into());
return Err(Error::length(ExpectedLength::Any(&[36, 32]), len));
}

return Err(ErrorKind::InvalidGroupCount {
expected: ExpectedLength::Any(&[1, 5]),
found: group + 1,
}
.into());
return Err(Error::group_count(
ExpectedLength::Any(&[1, 5]),
group + 1,
));
}

if digit % 2 == 0 {
Expand All @@ -90,34 +88,25 @@ pub fn parse_str(mut input: &str) -> Result<[u8; 16], Error> {
// Calculate how many digits this group consists of
// in the input.
let found = if group > 0 {
digit - ACC_GROUP_LENS[group - 1] as u8
digit as usize - ACC_GROUP_LENS[group - 1]
} else {
digit
digit as usize
};

let index =
ACC_GROUP_LENS[group - 1] + group + 1 + start;
return Err(ErrorKind::InvalidGroupLength {
expected: ExpectedLength::Exact(GROUP_LENS[group]),
found: found as usize,
return Err(Error::group_length(
ExpectedLength::Exact(GROUP_LENS[group]),
found,
group,
index,
}
.into());
start,
));
}
// Next group, decrement digit, it is incremented again
// at the bottom.
group += 1;
digit -= 1;
}
_ => {
return Err(ErrorKind::InvalidCharacter {
expected: "0123456789abcdefABCDEF-",
found: input[i_char..].chars().next().unwrap(),
index: i_char + start,
urn: UrnPrefix::Optional,
}
.into());
return Err(Error::character(character, i_char, start));
}
}
} else {
Expand All @@ -135,23 +124,17 @@ pub fn parse_str(mut input: &str) -> Result<[u8; 16], Error> {
digit
};

let index = ACC_GROUP_LENS[group - 1] + group + 1 + start;
return Err(ErrorKind::InvalidGroupLength {
expected: ExpectedLength::Exact(GROUP_LENS[group]),
found: found as usize,
return Err(Error::group_length(
ExpectedLength::Exact(GROUP_LENS[group]),
found as usize,
group,
index,
}
.into());
start,
));
}
_ => {
return Err(ErrorKind::InvalidCharacter {
expected: "0123456789abcdefABCDEF-",
found: input[i_char..].chars().next().unwrap(),
index: i_char + start,
urn: UrnPrefix::Optional,
}
.into());
// let found = input[i_char..].chars().next().unwrap();
// let found = char::from(chr);
return Err(Error::character(character, i_char, start));
}
}
buffer[(digit / 2) as usize] = acc;
Expand All @@ -161,14 +144,12 @@ pub fn parse_str(mut input: &str) -> Result<[u8; 16], Error> {

// Now check the last group.
if ACC_GROUP_LENS[4] as u8 != digit {
let index = ACC_GROUP_LENS[group - 1] + group + 1 + start;
return Err(ErrorKind::InvalidGroupLength {
expected: ExpectedLength::Exact(GROUP_LENS[4]),
found: (digit as usize - ACC_GROUP_LENS[3]),
return Err(Error::group_length(
ExpectedLength::Exact(GROUP_LENS[4]),
digit as usize - ACC_GROUP_LENS[3],
group,
index,
}
.into());
start,
));
}

Ok(buffer)
Expand Down
12 changes: 11 additions & 1 deletion src/parser.rs
Expand Up @@ -209,9 +209,19 @@ mod tests {

assert_eq!(
Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41"),
Err(Error(ErrorKind::InvalidCharacter {
expected: EXPECTED_CHARS,
found: '{',
index: 0,
urn: UrnPrefix::Optional,
}))
);

assert_eq!(
Uuid::parse_str("{F9168C5E-CEB2-4faa9B6BFF329BF39FA1E41}"),
Err(Error(ErrorKind::InvalidLength {
expected: ExpectedLength::Any(&[36, 32]),
found: 38
found: 39
}))
);

Expand Down
8 changes: 8 additions & 0 deletions tests/ui/compile_fail/invalid_parse.rs
Expand Up @@ -31,4 +31,12 @@ const _: Uuid = uuid!("{F9168C5E-CEB2-4faa-B0a75-32BF39FA1E4}");

const _: Uuid = uuid!("{F9168C5E-CEB2-4faa-B6BF-329Bz39FA1E4}");

// group 0 has invalid length
const _: Uuid = uuid!("67e550-4105b1426f9247bb680e5fe0c");

const _: Uuid = uuid!("504410岡林aab1426f9247bb680e5fe0c8");
const _: Uuid = uuid!("504410😎👍aab1426f9247bb680e5fe0c8");

const _: Uuid = uuid!("{F9168C5E-CEB2-4faa-👍5-32BF39FA1E4}");

fn main() {}
33 changes: 27 additions & 6 deletions tests/ui/compile_fail/invalid_parse.stderr
Expand Up @@ -82,14 +82,11 @@ error: invalid character: expected an optional prefix of `urn:uuid:` followed by
19 | const _: Uuid = uuid!("67e550X410b1426f9247bb680e5fe0cd");
| ^

error: proc macro panicked
--> tests/ui/compile_fail/invalid_parse.rs:20:17
error: invalid group length: expected 8, found 6 in group 0
--> tests/ui/compile_fail/invalid_parse.rs:20:24
|
20 | const _: Uuid = uuid!("67e550-4105b1426f9247bb680e5fe0c");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: message: attempt to subtract with overflow
= note: this error originates in the macro `uuid` (in Nightly builds, run with -Z macro-backtrace for more info)
| ^^^^^^

error: invalid group length: expected 4, found 5 in group 3
--> tests/ui/compile_fail/invalid_parse.rs:21:43
Expand Down Expand Up @@ -144,3 +141,27 @@ error: invalid character: expected an optional prefix of `urn:uuid:` followed by
|
32 | const _: Uuid = uuid!("{F9168C5E-CEB2-4faa-B6BF-329Bz39FA1E4}");
| ^

error: invalid group length: expected 8, found 6 in group 0
--> tests/ui/compile_fail/invalid_parse.rs:35:24
|
35 | const _: Uuid = uuid!("67e550-4105b1426f9247bb680e5fe0c");
| ^^^^^^

error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found 岡 at 6
--> tests/ui/compile_fail/invalid_parse.rs:37:30
|
37 | const _: Uuid = uuid!("504410岡林aab1426f9247bb680e5fe0c8");
| ^^

error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found 😎 at 6
--> tests/ui/compile_fail/invalid_parse.rs:38:30
|
38 | const _: Uuid = uuid!("504410😎👍aab1426f9247bb680e5fe0c8");
| ^^

error: invalid character: expected an optional prefix of `urn:uuid:` followed by 0123456789abcdefABCDEF-, found 👍 at 20
--> tests/ui/compile_fail/invalid_parse.rs:40:44
|
40 | const _: Uuid = uuid!("{F9168C5E-CEB2-4faa-👍5-32BF39FA1E4}");
| ^^

0 comments on commit 3fc629f

Please sign in to comment.