mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-03 15:55:31 +00:00
parser: understand nested block comments in macro calls
Fixes <https://issues.oss-fuzz.com/issues/427825995>.
This commit is contained in:
parent
7610b374db
commit
c71aead21b
@ -7,7 +7,7 @@ use winnow::combinator::{
|
|||||||
alt, cut_err, empty, fail, not, opt, peek, preceded, repeat, separated, terminated,
|
alt, cut_err, empty, fail, not, opt, peek, preceded, repeat, separated, terminated,
|
||||||
};
|
};
|
||||||
use winnow::error::{ErrMode, ParserError as _};
|
use winnow::error::{ErrMode, ParserError as _};
|
||||||
use winnow::token::take_until;
|
use winnow::token::{one_of, take_until};
|
||||||
|
|
||||||
use crate::node::CondTest;
|
use crate::node::CondTest;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -839,21 +839,31 @@ impl<'a> Suffix<'a> {
|
|||||||
fn block_comment<'a>(i: &mut &'a str) -> ParseResult<'a, ()> {
|
fn block_comment<'a>(i: &mut &'a str) -> ParseResult<'a, ()> {
|
||||||
let start = "/*".parse_next(i)?;
|
let start = "/*".parse_next(i)?;
|
||||||
let is_doc_comment = alt((
|
let is_doc_comment = alt((
|
||||||
('*', not(peek('*'))).value(true),
|
('*', not(peek(one_of(['*', '/'])))).value(true),
|
||||||
'!'.value(true),
|
'!'.value(true),
|
||||||
empty.value(false),
|
empty.value(false),
|
||||||
))
|
))
|
||||||
.parse_next(i)?;
|
.parse_next(i)?;
|
||||||
if opt(take_until(.., "*/")).parse_next(i)?.is_none() {
|
|
||||||
return cut_error!(
|
let mut depth = 0usize;
|
||||||
format!(
|
loop {
|
||||||
"missing `*/` to close block {}comment",
|
if opt(take_until(.., ("/*", "*/"))).parse_next(i)?.is_none() {
|
||||||
if is_doc_comment { "doc " } else { "" }
|
return cut_error!(
|
||||||
),
|
format!(
|
||||||
start,
|
"missing `*/` to close block {}comment",
|
||||||
);
|
if is_doc_comment { "doc " } else { "" }
|
||||||
|
),
|
||||||
|
start,
|
||||||
|
);
|
||||||
|
} else if alt(("/*".value(true), "*/".value(false))).parse_next(i)? {
|
||||||
|
// cannot overflow: `i` cannot be longer than `isize::MAX`, cf. [std::alloc::Layout]
|
||||||
|
depth += 1;
|
||||||
|
} else if let Some(new_depth) = depth.checked_sub(1) {
|
||||||
|
depth = new_depth;
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identifier_or_prefixed_string<'a>(i: &mut &'a str) -> ParseResult<'a, ()> {
|
fn identifier_or_prefixed_string<'a>(i: &mut &'a str) -> ParseResult<'a, ()> {
|
||||||
|
@ -1561,3 +1561,34 @@ fn test_raw() {
|
|||||||
}))],
|
}))],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_macro_call_nested_comments() {
|
||||||
|
// Regression test for <https://issues.oss-fuzz.com/issues/427825995>.
|
||||||
|
let syntax = Syntax::default();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ast::from_str("{{ x!(/*/*/*)*/*/*/) }}", None, &syntax)
|
||||||
|
.unwrap()
|
||||||
|
.nodes,
|
||||||
|
vec![Node::Expr(
|
||||||
|
Ws(None, None),
|
||||||
|
WithSpan::no_span(Expr::RustMacro(vec!["x"], "/*/*/*)*/*/*/")),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
|
let msg = Ast::from_str("{{ x!(/*/*/) }}", None, &syntax)
|
||||||
|
.unwrap_err()
|
||||||
|
.to_string();
|
||||||
|
assert!(msg.contains("missing `*/` to close block comment"));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Ast::from_str("{{ x!(/**/) }}", None, &syntax)
|
||||||
|
.unwrap()
|
||||||
|
.nodes,
|
||||||
|
vec![Node::Expr(
|
||||||
|
Ws(None, None),
|
||||||
|
WithSpan::no_span(Expr::RustMacro(vec!["x"], "/**/")),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<EFBFBD><EFBFBD><EFBFBD>{{K!(/*/*/)}}<7D><><EFBFBD><EFBFBD>u<EFBFBD><75>
|
Loading…
x
Reference in New Issue
Block a user