Skip to content

Commit 0912903

Browse files
authored
Fix panic with invalid last char in PEP 508 name (#13105)
Fixes #13102
1 parent ae5c77c commit 0912903

File tree

2 files changed

+34
-20
lines changed

2 files changed

+34
-20
lines changed

crates/uv-pep508/src/lib.rs

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -443,27 +443,22 @@ fn parse_name<T: Pep508Url>(cursor: &mut Cursor) -> Result<PackageName, Pep508Er
443443
});
444444
}
445445

446-
loop {
447-
if let Some((index, char @ ('A'..='Z' | 'a'..='z' | '0'..='9' | '.' | '-' | '_'))) =
448-
cursor.peek()
449-
{
450-
cursor.next();
451-
// [.-_] can't be the final character
452-
if cursor.peek().is_none() && matches!(char, '.' | '-' | '_') {
453-
return Err(Pep508Error {
454-
message: Pep508ErrorSource::String(format!(
455-
"Package name must end with an alphanumeric character, not `{char}`"
456-
)),
457-
start: index,
458-
len: char.len_utf8(),
459-
input: cursor.to_string(),
460-
});
461-
}
462-
} else {
463-
let len = cursor.pos() - start;
464-
return Ok(PackageName::from_str(cursor.slice(start, len)).unwrap());
465-
}
446+
cursor.take_while(|char| matches!(char, 'A'..='Z' | 'a'..='z' | '0'..='9' | '.' | '-' | '_'));
447+
let len = cursor.pos() - start;
448+
// Unwrap-safety: The block above ensures that there is at least one char in the buffer.
449+
let last = cursor.slice(start, len).chars().last().unwrap();
450+
// [.-_] can't be the final character
451+
if !matches!(last, 'A'..='Z' | 'a'..='z' | '0'..='9') {
452+
return Err(Pep508Error {
453+
message: Pep508ErrorSource::String(format!(
454+
"Package name must end with an alphanumeric character, not `{last}`"
455+
)),
456+
start: cursor.pos() - last.len_utf8(),
457+
len: last.len_utf8(),
458+
input: cursor.to_string(),
459+
});
466460
}
461+
Ok(PackageName::from_str(cursor.slice(start, len)).unwrap())
467462
}
468463

469464
/// Parse a potential URL from the [`Cursor`], advancing the [`Cursor`] to the end of the URL.
@@ -1531,6 +1526,24 @@ mod tests {
15311526
);
15321527
}
15331528

1529+
#[test]
1530+
fn parse_name_with_star() {
1531+
assert_snapshot!(
1532+
parse_pep508_err("wheel-*.whl"),
1533+
@r"
1534+
Package name must end with an alphanumeric character, not `-`
1535+
wheel-*.whl
1536+
^
1537+
");
1538+
assert_snapshot!(
1539+
parse_pep508_err("wheelѦ"),
1540+
@r"
1541+
Expected one of `@`, `(`, `<`, `=`, `>`, `~`, `!`, `;`, found `Ѧ`
1542+
wheelѦ
1543+
^
1544+
");
1545+
}
1546+
15341547
#[test]
15351548
fn test_error_invalid_marker_key() {
15361549
assert_snapshot!(

crates/uv-pep508/src/verbatim_url.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use regex::Regex;
1111
use thiserror::Error;
1212
use url::{ParseError, Url};
1313

14+
#[cfg_attr(not(feature = "non-pep508-extensions"), allow(unused_imports))]
1415
use uv_fs::{normalize_absolute_path, normalize_url_path};
1516

1617
use crate::Pep508Url;

0 commit comments

Comments
 (0)