Browse Source

Deny Unicode Escapes in boolean and null expressions (#2931)

* Deny Unicode Escapes in boolean and null expressions

* Add tests
pull/2981/head
Veera 1 year ago committed by GitHub
parent
commit
4a68fb5120
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      boa_parser/src/lexer/identifier.rs
  2. 4
      boa_parser/src/lexer/tests.rs
  3. 12
      boa_parser/src/lexer/token.rs
  4. 2
      boa_parser/src/parser/expression/assignment/yield.rs
  5. 8
      boa_parser/src/parser/expression/left_hand_side/call.rs
  6. 14
      boa_parser/src/parser/expression/left_hand_side/member.rs
  7. 18
      boa_parser/src/parser/expression/left_hand_side/optional/mod.rs
  8. 13
      boa_parser/src/parser/expression/primary/mod.rs
  9. 4
      boa_parser/src/parser/expression/primary/object_initializer/mod.rs
  10. 8
      boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs
  11. 15
      boa_parser/src/parser/tests/mod.rs

12
boa_parser/src/lexer/identifier.rs

@ -94,9 +94,15 @@ impl<R> Tokenizer<R> for Identifier {
Self::take_identifier_name(cursor, start_pos, self.init)?;
let token_kind = match identifier_name.parse() {
Ok(Keyword::True) => TokenKind::BooleanLiteral(true),
Ok(Keyword::False) => TokenKind::BooleanLiteral(false),
Ok(Keyword::Null) => TokenKind::NullLiteral,
Ok(Keyword::True) => {
TokenKind::BooleanLiteral((true, ContainsEscapeSequence(contains_escaped_chars)))
}
Ok(Keyword::False) => {
TokenKind::BooleanLiteral((false, ContainsEscapeSequence(contains_escaped_chars)))
}
Ok(Keyword::Null) => {
TokenKind::NullLiteral(ContainsEscapeSequence(contains_escaped_chars))
}
Ok(keyword) => TokenKind::Keyword((keyword, contains_escaped_chars)),
_ => TokenKind::IdentifierName((
interner.get_or_intern(identifier_name.as_str()),

4
boa_parser/src/lexer/tests.rs

@ -38,7 +38,7 @@ fn check_single_line_comment() {
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true),
TokenKind::BooleanLiteral((true, ContainsEscapeSequence(false))),
];
expect_tokens(&mut lexer, &expected, interner);
@ -54,7 +54,7 @@ fn check_single_line_comment_with_crlf_ending() {
TokenKind::Keyword((Keyword::Var, false)),
TokenKind::LineTerminator,
TokenKind::LineTerminator,
TokenKind::BooleanLiteral(true),
TokenKind::BooleanLiteral((true, ContainsEscapeSequence(false))),
];
expect_tokens(&mut lexer, &expected, interner);

12
boa_parser/src/lexer/token.rs

@ -95,7 +95,7 @@ impl From<BigInt> for Numeric {
#[derive(Clone, PartialEq, Debug)]
pub enum TokenKind {
/// A boolean literal, which is either `true` or `false`.
BooleanLiteral(bool),
BooleanLiteral((bool, ContainsEscapeSequence)),
/// The end of the file.
EOF,
@ -118,7 +118,7 @@ pub enum TokenKind {
/// The [`null` literal][spec].
///
/// [spec]: https://tc39.es/ecma262/#prod-NullLiteral
NullLiteral,
NullLiteral(ContainsEscapeSequence),
/// A numeric literal.
NumericLiteral(Numeric),
@ -152,7 +152,7 @@ pub enum TokenKind {
impl From<bool> for TokenKind {
#[inline]
fn from(oth: bool) -> Self {
Self::BooleanLiteral(oth)
Self::BooleanLiteral((oth, ContainsEscapeSequence(false)))
}
}
@ -182,7 +182,7 @@ impl TokenKind {
#[inline]
#[must_use]
pub const fn boolean_literal(lit: bool) -> Self {
Self::BooleanLiteral(lit)
Self::BooleanLiteral((lit, ContainsEscapeSequence(false)))
}
/// Creates an `EOF` token kind.
@ -261,12 +261,12 @@ impl TokenKind {
#[must_use]
pub fn to_string(&self, interner: &Interner) -> String {
match *self {
Self::BooleanLiteral(val) => val.to_string(),
Self::BooleanLiteral((val, _)) => val.to_string(),
Self::EOF => "end of file".to_owned(),
Self::IdentifierName((ident, _)) => interner.resolve_expect(ident).to_string(),
Self::PrivateIdentifier(ident) => format!("#{}", interner.resolve_expect(ident)),
Self::Keyword((word, _)) => word.to_string(),
Self::NullLiteral => "null".to_owned(),
Self::NullLiteral(_) => "null".to_owned(),
Self::NumericLiteral(Numeric::Rational(num)) => num.to_string(),
Self::NumericLiteral(Numeric::Integer(num)) => num.to_string(),
Self::NumericLiteral(Numeric::BigInt(ref num)) => format!("{num}n"),

2
boa_parser/src/parser/expression/assignment/yield.rs

@ -103,7 +103,7 @@ where
_,
))
| TokenKind::BooleanLiteral(_)
| TokenKind::NullLiteral
| TokenKind::NullLiteral(_)
| TokenKind::StringLiteral(_)
| TokenKind::TemplateNoSubstitution(_)
| TokenKind::NumericLiteral(_)

8
boa_parser/src/parser/expression/left_hand_side/call.rs

@ -140,13 +140,15 @@ where
TokenKind::Keyword((kw, _)) => {
SimplePropertyAccess::new(lhs, kw.to_sym()).into()
}
TokenKind::BooleanLiteral(true) => {
TokenKind::BooleanLiteral((true, _)) => {
SimplePropertyAccess::new(lhs, Sym::TRUE).into()
}
TokenKind::BooleanLiteral(false) => {
TokenKind::BooleanLiteral((false, _)) => {
SimplePropertyAccess::new(lhs, Sym::FALSE).into()
}
TokenKind::NullLiteral => SimplePropertyAccess::new(lhs, Sym::NULL).into(),
TokenKind::NullLiteral(_) => {
SimplePropertyAccess::new(lhs, Sym::NULL).into()
}
TokenKind::PrivateIdentifier(name) => {
PrivatePropertyAccess::new(lhs, PrivateName::new(*name)).into()
}

14
boa_parser/src/parser/expression/left_hand_side/member.rs

@ -171,13 +171,13 @@ where
TokenKind::Keyword((kw, _)) => {
SuperPropertyAccess::new(kw.to_sym().into())
}
TokenKind::BooleanLiteral(true) => {
TokenKind::BooleanLiteral((true, _)) => {
SuperPropertyAccess::new(Sym::TRUE.into())
}
TokenKind::BooleanLiteral(false) => {
TokenKind::BooleanLiteral((false, _)) => {
SuperPropertyAccess::new(Sym::FALSE.into())
}
TokenKind::NullLiteral => SuperPropertyAccess::new(Sym::NULL.into()),
TokenKind::NullLiteral(_) => SuperPropertyAccess::new(Sym::NULL.into()),
TokenKind::PrivateIdentifier(_) => {
return Err(Error::general(
"unexpected private identifier",
@ -233,13 +233,15 @@ where
TokenKind::Keyword((kw, _)) => {
SimplePropertyAccess::new(lhs, kw.to_sym()).into()
}
TokenKind::BooleanLiteral(true) => {
TokenKind::BooleanLiteral((true, _)) => {
SimplePropertyAccess::new(lhs, Sym::TRUE).into()
}
TokenKind::BooleanLiteral(false) => {
TokenKind::BooleanLiteral((false, _)) => {
SimplePropertyAccess::new(lhs, Sym::FALSE).into()
}
TokenKind::NullLiteral => SimplePropertyAccess::new(lhs, Sym::NULL).into(),
TokenKind::NullLiteral(_) => {
SimplePropertyAccess::new(lhs, Sym::NULL).into()
}
TokenKind::PrivateIdentifier(name) => {
PrivatePropertyAccess::new(lhs, PrivateName::new(*name)).into()
}

18
boa_parser/src/parser/expression/left_hand_side/optional/mod.rs

@ -73,13 +73,17 @@ where
TokenKind::Keyword((kw, _)) => OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(kw.to_sym()),
},
TokenKind::BooleanLiteral(true) => OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(Sym::TRUE),
},
TokenKind::BooleanLiteral(false) => OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(Sym::FALSE),
},
TokenKind::NullLiteral => OptionalOperationKind::SimplePropertyAccess {
TokenKind::BooleanLiteral((true, _)) => {
OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(Sym::TRUE),
}
}
TokenKind::BooleanLiteral((false, _)) => {
OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(Sym::FALSE),
}
}
TokenKind::NullLiteral(_) => OptionalOperationKind::SimplePropertyAccess {
field: PropertyAccessField::Const(Sym::NULL),
},
TokenKind::PrivateIdentifier(name) => {

13
boa_parser/src/parser/expression/primary/mod.rs

@ -27,7 +27,10 @@ use self::{
object_initializer::ObjectLiteral,
};
use crate::{
lexer::{token::Numeric, InputElement, Token, TokenKind},
lexer::{
token::{ContainsEscapeSequence, Numeric},
InputElement, Token, TokenKind,
},
parser::{
expression::{
identifiers::IdentifierReference, primary::template::TemplateLiteral,
@ -103,7 +106,9 @@ where
let tok_position = tok.span().start();
match tok.kind() {
TokenKind::Keyword((Keyword::This, true)) => Err(Error::general(
TokenKind::Keyword((Keyword::This, true))
| TokenKind::BooleanLiteral((_, ContainsEscapeSequence(true)))
| TokenKind::NullLiteral(ContainsEscapeSequence(true)) => Err(Error::general(
"Keyword must not contain escaped characters",
tok_position,
)),
@ -187,12 +192,12 @@ where
.parse(cursor, interner)
.map(Into::into)
}
TokenKind::BooleanLiteral(boolean) => {
TokenKind::BooleanLiteral((boolean, _)) => {
let node = Literal::from(*boolean).into();
cursor.advance(interner);
Ok(node)
}
TokenKind::NullLiteral => {
TokenKind::NullLiteral(_) => {
cursor.advance(interner);
Ok(Literal::Null.into())
}

4
boa_parser/src/parser/expression/primary/object_initializer/mod.rs

@ -600,8 +600,8 @@ where
let (utf8, utf16) = word.as_str();
interner.get_or_intern_static(utf8, utf16).into()
}
TokenKind::NullLiteral => (Sym::NULL).into(),
TokenKind::BooleanLiteral(bool) => match bool {
TokenKind::NullLiteral(_) => (Sym::NULL).into(),
TokenKind::BooleanLiteral((bool, _)) => match bool {
true => Sym::TRUE.into(),
false => Sym::FALSE.into(),
},

8
boa_parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs

@ -589,7 +589,7 @@ where
| TokenKind::StringLiteral(_)
| TokenKind::NumericLiteral(_)
| TokenKind::Keyword(_)
| TokenKind::NullLiteral
| TokenKind::NullLiteral(_)
| TokenKind::PrivateIdentifier(_)
| TokenKind::Punctuator(
Punctuator::OpenBracket | Punctuator::Mul | Punctuator::OpenBlock,
@ -931,7 +931,7 @@ where
| TokenKind::StringLiteral(_)
| TokenKind::NumericLiteral(_)
| TokenKind::Keyword(_)
| TokenKind::NullLiteral
| TokenKind::NullLiteral(_)
| TokenKind::Punctuator(Punctuator::OpenBracket) => {
let name_position = token.span().start();
let name = PropertyName::new(self.allow_yield, self.allow_await)
@ -1062,7 +1062,7 @@ where
| TokenKind::StringLiteral(_)
| TokenKind::NumericLiteral(_)
| TokenKind::Keyword(_)
| TokenKind::NullLiteral
| TokenKind::NullLiteral(_)
| TokenKind::Punctuator(Punctuator::OpenBracket) => {
let name_position = token.span().start();
let name = PropertyName::new(self.allow_yield, self.allow_await)
@ -1223,7 +1223,7 @@ where
| TokenKind::StringLiteral(_)
| TokenKind::NumericLiteral(_)
| TokenKind::Keyword(_)
| TokenKind::NullLiteral
| TokenKind::NullLiteral(_)
| TokenKind::Punctuator(Punctuator::OpenBracket) => {
let name_position = token.span().start();
let name = PropertyName::new(self.allow_yield, self.allow_await)

15
boa_parser/src/parser/tests/mod.rs

@ -604,3 +604,18 @@ fn hashbang_use_strict_with_with_statement() {
fn hashbang_comment() {
check_script_parser(r"#!Comment Here", vec![], &mut Interner::default());
}
#[test]
fn deny_unicode_escape_in_false_expression() {
check_invalid_script(r"let x = f\u{61}lse;");
}
#[test]
fn deny_unicode_escape_in_true_expression() {
check_invalid_script(r"let x = tru\u{65};");
}
#[test]
fn deny_unicode_escape_in_null_expression() {
check_invalid_script(r"let x = n\u{75}ll;");
}

Loading…
Cancel
Save