Skip to content

Commit

Permalink
uint[1.111111E1111111111111] causes compiler to go into infinite loop
Browse files Browse the repository at this point in the history
The lexer tries to calculate 10^1111111111111 which will be a very large
number. This will take a long time.

The lexer should not try to calculate numbers from strings, as this
might fail and we do not want the lexer to give up, as no parsing and
semantic analysis will be done.

Signed-off-by: Sean Young <sean@mess.org>
  • Loading branch information
seanyoung committed May 12, 2022
1 parent 68fa55d commit f2e3a09
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 223 deletions.
3 changes: 0 additions & 3 deletions solang-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ lalrpop = "0.19"

[dependencies]
lalrpop-util = "0.19"
num-bigint = "0.4"
num-traits = "0.2"
num-rational = "0.4"
phf = { version = "0.10", features = ["macros"] }
unicode-xid = "0.2.0"
itertools = "0.10"
24 changes: 12 additions & 12 deletions solang-parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,13 @@ impl<'input> fmt::Display for Token<'input> {
Token::StringLiteral(s) => write!(f, "\"{}\"", s),
Token::HexLiteral(hex) => write!(f, "{}", hex),
Token::AddressLiteral(address) => write!(f, "{}", address),
Token::Number(base, exp) if exp.is_empty() => write!(f, "{}", base),
Token::Number(base, exp) => write!(f, "{}e{}", base, exp),
Token::RationalNumber(significand, mantissa, exp) if exp.is_empty() => {
write!(f, "{}.{}", significand, mantissa)
Token::Number(integer, exp) if exp.is_empty() => write!(f, "{}", integer),
Token::Number(integer, exp) => write!(f, "{}e{}", integer, exp),
Token::RationalNumber(integer, fraction, exp) if exp.is_empty() => {
write!(f, "{}.{}", integer, fraction)
}
Token::RationalNumber(significand, mantissa, exp) => {
write!(f, "{}.{}e{}", significand, mantissa, exp)
Token::RationalNumber(integer, fraction, exp) => {
write!(f, "{}.{}e{}", integer, fraction, exp)
}
Token::HexNumber(n) => write!(f, "{}", n),
Token::Uint(w) => write!(f, "uint{}", w),
Expand Down Expand Up @@ -678,21 +678,21 @@ impl<'input> Lexer<'input> {
}

if is_rational {
let significand = &self.input[start..=end_before_rational];
let mantissa = &self.input[rational_start..=rational_end];

let integer = &self.input[start..=end_before_rational];
let fraction = &self.input[rational_start..=rational_end];
let exp = &self.input[exp_start..=end];

return Ok((
start,
Token::RationalNumber(significand, mantissa, exp),
Token::RationalNumber(integer, fraction, exp),
end + 1,
));
}

let base = &self.input[start..=old_end];
let integer = &self.input[start..=old_end];
let exp = &self.input[exp_start..=end];

Ok((start, Token::Number(base, exp), end + 1))
Ok((start, Token::Number(integer, exp), end + 1))
}

fn string(
Expand Down
13 changes: 5 additions & 8 deletions solang-parser/src/pt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use std::fmt::{self, Display};

use num_bigint::BigInt;
use num_rational::BigRational;

#[derive(Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Clone, Copy)]
/// file no, start offset, end offset (in bytes)
pub enum Loc {
Expand Down Expand Up @@ -407,8 +404,8 @@ pub enum Expression {
AssignDivide(Loc, Box<Expression>, Box<Expression>),
AssignModulo(Loc, Box<Expression>, Box<Expression>),
BoolLiteral(Loc, bool),
NumberLiteral(Loc, BigInt),
RationalNumberLiteral(Loc, BigRational),
NumberLiteral(Loc, String, String),
RationalNumberLiteral(Loc, String, String, String),
HexNumberLiteral(Loc, String),
StringLiteral(Vec<StringLiteral>),
Type(Loc, Type),
Expand Down Expand Up @@ -472,8 +469,8 @@ impl CodeLocation for Expression {
| Expression::AssignDivide(loc, ..)
| Expression::AssignModulo(loc, ..)
| Expression::BoolLiteral(loc, _)
| Expression::NumberLiteral(loc, _)
| Expression::RationalNumberLiteral(loc, _)
| Expression::NumberLiteral(loc, ..)
| Expression::RationalNumberLiteral(loc, ..)
| Expression::HexNumberLiteral(loc, _)
| Expression::ArrayLiteral(loc, _)
| Expression::List(loc, _)
Expand Down Expand Up @@ -696,7 +693,7 @@ pub struct YulBlock {
#[derive(Debug, PartialEq, Clone)]
pub enum YulExpression {
BoolLiteral(Loc, bool, Option<Identifier>),
NumberLiteral(Loc, BigInt, Option<Identifier>),
NumberLiteral(Loc, String, String, Option<Identifier>),
HexNumberLiteral(Loc, String, Option<Identifier>),
HexStringLiteral(HexLiteral, Option<Identifier>),
StringLiteral(StringLiteral, Option<Identifier>),
Expand Down
100 changes: 8 additions & 92 deletions solang-parser/src/solidity.lalrpop
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
use std::str::FromStr;
use num_bigint::{BigUint, BigInt};
use num_traits::{Pow, Zero};
use num_rational::BigRational;
use std::ops::Mul;
use lalrpop_util::ParseError;
use super::pt::*;
use super::box_option;
Expand Down Expand Up @@ -430,87 +425,17 @@ NoFunctionTyPrecedence0: Expression = {
<SolNoErrorIdentifier> => Expression::Variable(<>),
<l:@L> <e:Precedence0> <u:Unit> <r:@R> => Expression::Unit(Loc::File(file_no, l, r), Box::new(e), u),
<l:@L> <n:number> <r:@R> => {
let base: String = n.0.chars().filter(|v| *v != '_').collect();
let integer: String = n.0.chars().filter(|v| *v != '_').collect();
let exp: String = n.1.chars().filter(|v| *v != '_').collect();

let base = BigInt::from_str(&base).unwrap();

let n = if exp.is_empty() {
base
} else {
let b10 = BigInt::from_str("10").unwrap();

if exp.starts_with('-') {
let exp = b10.pow(BigUint::from_str(&exp[1..]).unwrap());
let res = BigRational::new(base, exp);

if res.is_integer() {
res.to_integer()
} else {
return Expression::RationalNumberLiteral(Loc::File(file_no, l, r), res);
}
} else {
let exp = b10.pow(BigUint::from_str(&exp).unwrap());

base.mul(exp)
}
};

Expression::NumberLiteral(Loc::File(file_no, l, r), n)
Expression::NumberLiteral(Loc::File(file_no, l, r), integer, exp)
},
<l:@L> <n:rational> <r:@R> => {
let mut significand: String = n.0.to_string();
let mantissa: String = n.1.to_string();
let exp: String = n.2.to_string();
let len = if mantissa.is_empty() {
0
} else {
mantissa.len()
};
let mut test = false;
if exp.starts_with("-") {
test = true;
}

let denominator = BigInt::from_str("10").unwrap().pow(BigUint::from(len as u64));
let zero_index = mantissa.chars().position(|c| c != '0').unwrap_or(usize::MAX);
let n = if exp.is_empty() {
if significand.is_empty() || significand == "0" {
if zero_index < usize::MAX {
BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap(), denominator)
} else {
BigRational::from(BigInt::zero())
}
} else {
significand.push_str(&mantissa);
BigRational::new(BigInt::from_str(&significand).unwrap(), denominator)
}
} else {
if significand.is_empty() || significand == "0" {
if zero_index < usize::MAX {
if test {
let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp[1..]).unwrap());
BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap(), denominator.mul(exp_result))
} else {
let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());
BigRational::new(BigInt::from_str(&mantissa[zero_index..]).unwrap().mul(exp_result), denominator)
}
} else {
BigRational::from(BigInt::zero())
}
} else {
significand.push_str(&mantissa);
if test {
let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp[1..]).unwrap());
BigRational::new(BigInt::from_str(&significand).unwrap(), denominator.mul(exp_result))
} else {
let exp_result = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());
BigRational::new(BigInt::from_str(&significand).unwrap().mul(exp_result), denominator)
}
}
};
let integer: String = n.0.chars().filter(|v| *v != '_').collect();
let fraction: String = n.1.chars().filter(|v| *v != '_').collect();
let exp: String = n.2.chars().filter(|v| *v != '_').collect();

Expression::RationalNumberLiteral(Loc::File(file_no, l, r), n)
Expression::RationalNumberLiteral(Loc::File(file_no, l, r), integer, fraction, exp)
},
<l:@L> <n:hexnumber> <r:@R> => {
Expression::HexNumberLiteral(Loc::File(file_no, l, r), n.to_owned())
Expand Down Expand Up @@ -869,19 +794,10 @@ YulLiteral: YulExpression = {
<a:@L> "true" <t_type:(":" <YulIdentifier>)?> <b:@R> => YulExpression::BoolLiteral(Loc::File(file_no, a, b), true, t_type),
<a:@L> "false" <t_type:(":" <YulIdentifier>)?> <b:@R> => YulExpression::BoolLiteral(Loc::File(file_no, a, b), false, t_type),
<l:@L> <n:number> <t_type:(":" <YulIdentifier>)?> <r:@R> => {
let base: String = n.0.chars().filter(|v| *v != '_').collect();
let integer: String = n.0.chars().filter(|v| *v != '_').collect();
let exp: String = n.1.chars().filter(|v| *v != '_').collect();

let n = if exp.is_empty() {
BigInt::from_str(&base).unwrap()
} else {
let base = BigInt::from_str(&base).unwrap();
let exp = BigInt::from_str("10").unwrap().pow(BigUint::from_str(&exp).unwrap());

base.mul(exp)
};

YulExpression::NumberLiteral(Loc::File(file_no, l, r), n, t_type)
YulExpression::NumberLiteral(Loc::File(file_no, l, r), integer, exp, t_type)
},
<l:@L> <n:hexnumber> <t_type:(":" <YulIdentifier>)?> <r:@R> => {
YulExpression::HexNumberLiteral(Loc::File(file_no, l, r), n.to_owned(), t_type)
Expand Down
21 changes: 10 additions & 11 deletions solang-parser/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::lexer::Lexer;
use crate::pt::*;
use crate::solidity;
use num_bigint::BigInt;

#[test]
fn parse_test() {
Expand Down Expand Up @@ -154,8 +153,8 @@ fn parse_test() {
name: "sum".to_string(),
})),
vec![
Expression::NumberLiteral(Loc::File(0, 765, 766), 1.into()),
Expression::NumberLiteral(Loc::File(0, 768, 769), 1.into()),
Expression::NumberLiteral(Loc::File(0, 765, 766), "1".to_string(), "".to_string()),
Expression::NumberLiteral(Loc::File(0, 768, 769), "1".to_string(), "".to_string()),
],
),
Some((
Expand Down Expand Up @@ -190,7 +189,7 @@ fn parse_test() {
})),
Box::new(Expression::NumberLiteral(
Loc::File(0, 830, 831),
2.into(),
"2".to_string(), "".to_string(),
)),
)],
),
Expand Down Expand Up @@ -478,7 +477,7 @@ fn test_assembly_parser() {
}],
Some(YulExpression::NumberLiteral(
Loc::File(0, 107, 108),
BigInt::from(0),
"0".to_string(), "".to_string(),
None,
)),
),
Expand All @@ -498,7 +497,7 @@ fn test_assembly_parser() {
}],
Some(YulExpression::NumberLiteral(
Loc::File(0, 148, 149),
BigInt::from(0),
"0".to_string(), "".to_string(),
None,
)),
)],
Expand Down Expand Up @@ -678,7 +677,7 @@ fn test_assembly_parser() {
Loc::File(0, 510, 620),
YulExpression::NumberLiteral(
Loc::File(0, 515, 516),
BigInt::from(0),
"0".to_string(), "".to_string(),
None,
),
YulBlock {
Expand All @@ -693,12 +692,12 @@ fn test_assembly_parser() {
arguments: vec![
YulExpression::NumberLiteral(
Loc::File(0, 554, 555),
BigInt::from(0),
"0".to_string(), "".to_string(),
None,
),
YulExpression::NumberLiteral(
Loc::File(0, 557, 558),
BigInt::from(0),
"0".to_string(), "".to_string(),
None,
),
],
Expand Down Expand Up @@ -802,15 +801,15 @@ fn test_assembly_parser() {
arguments: vec![
YulExpression::NumberLiteral(
Loc::File(0, 924, 930),
BigInt::from(3),
"3".to_string(), "".to_string(),
Some(Identifier {
loc: Loc::File(0, 926, 930),
name: "u256".to_string(),
}),
),
YulExpression::NumberLiteral(
Loc::File(0, 932, 938),
BigInt::from(2),
"2".to_string(), "".to_string(),
Some(Identifier {
loc: Loc::File(0, 934, 938),
name: "u256".to_string(),
Expand Down
Loading

0 comments on commit f2e3a09

Please sign in to comment.