mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat: Guard against runtime panics in lexer
Add guardrails for operations to ensure that they won't panic at runtime. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
+37
-4
@@ -98,7 +98,13 @@ impl SourceStr {
|
||||
}
|
||||
|
||||
pub fn text(&self) -> &str {
|
||||
&self.source.contents()[self.start as usize..self.end as usize]
|
||||
let start = self.start as usize;
|
||||
let end = self.end as usize;
|
||||
// Use safe slicing to avoid panics on malformed spans
|
||||
self.source
|
||||
.contents()
|
||||
.get(start..end)
|
||||
.unwrap_or("<invalid-span>")
|
||||
}
|
||||
|
||||
pub fn clone_empty(&self) -> SourceStr {
|
||||
@@ -241,7 +247,13 @@ pub struct Span {
|
||||
|
||||
impl Span {
|
||||
pub fn text(&self) -> &str {
|
||||
&self.source.contents()[self.start as usize..self.end as usize]
|
||||
let start = self.start as usize;
|
||||
let end = self.end as usize;
|
||||
// Use safe slicing to avoid panics on malformed spans
|
||||
self.source
|
||||
.contents()
|
||||
.get(start..end)
|
||||
.unwrap_or("<invalid-span>")
|
||||
}
|
||||
|
||||
pub fn source_str(&self) -> SourceStr {
|
||||
@@ -445,7 +457,13 @@ impl<'source> Lexer<'source> {
|
||||
}
|
||||
|
||||
// Ensure that the number is parsable in Rust.
|
||||
match serde_json::from_str::<Value>(&self.source.contents()[start..end]) {
|
||||
let num_slice = self
|
||||
.source
|
||||
.contents()
|
||||
.get(start..end)
|
||||
.ok_or_else(|| self.source.error(self.line, col, "invalid number span"))?;
|
||||
|
||||
match serde_json::from_str::<Value>(num_slice) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
let serde_msg = &e.to_string();
|
||||
@@ -506,6 +524,10 @@ impl<'source> Lexer<'source> {
|
||||
}
|
||||
}
|
||||
let end = self.peek().0;
|
||||
if end <= start {
|
||||
// Guard against invalid span that would underflow end - 1
|
||||
return Err(self.source.error(line, col, "invalid raw string span"));
|
||||
}
|
||||
Ok(Token(
|
||||
TokenKind::RawString,
|
||||
Span {
|
||||
@@ -574,8 +596,19 @@ impl<'source> Lexer<'source> {
|
||||
let end = self.peek().0;
|
||||
self.col += (end - start) as u32;
|
||||
|
||||
if start == 0 || end <= start {
|
||||
// Reject invalid spans before slicing/serde to avoid panic
|
||||
return Err(self.source.error(line, col, "invalid string span"));
|
||||
}
|
||||
|
||||
let str_slice = self
|
||||
.source
|
||||
.contents()
|
||||
.get(start - 1..end)
|
||||
.ok_or_else(|| self.source.error(line, col, "invalid string span"))?;
|
||||
|
||||
// Ensure that the string is parsable in Rust.
|
||||
match serde_json::from_str::<String>(&self.source.contents()[start - 1..end]) {
|
||||
match serde_json::from_str::<String>(str_slice) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
let serde_msg = &e.to_string();
|
||||
|
||||
@@ -224,6 +224,34 @@ fn invalid_line() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_span_text_fallbacks() -> Result<()> {
|
||||
let rego = "abc";
|
||||
let source = Source::from_contents("case.rego".to_string(), rego.to_string())?;
|
||||
|
||||
let ss = SourceStr::new(source.clone(), 100, 200);
|
||||
assert_eq!(
|
||||
ss.text(),
|
||||
"<invalid-span>",
|
||||
"SourceStr should return fallback for out-of-bounds span"
|
||||
);
|
||||
|
||||
let span = Span {
|
||||
source: source.clone(),
|
||||
line: 1,
|
||||
col: 1,
|
||||
start: 5,
|
||||
end: 2,
|
||||
};
|
||||
assert_eq!(
|
||||
span.text(),
|
||||
"<invalid-span>",
|
||||
"Span should return fallback for malformed span"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "std")]
|
||||
fn file_more_than_64_kb_size() -> Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user