Skip to content

Commit

Permalink
fixes OutOfMemoryError/memory leak on e.<number> input #374 (#385)
Browse files Browse the repository at this point in the history
* fixes OutOfMemoryError/memory leak on e.<number> input #374
  • Loading branch information
uklimaschewski authored Jun 8, 2023
1 parent df8eeeb commit 7c39c54
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 24 deletions.
65 changes: 43 additions & 22 deletions src/main/java/com/ezylang/evalex/parser/Tokenizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -351,33 +351,54 @@ private boolean infixOperatorAllowed() {
}

private Token parseNumberLiteral() throws ParseException {
int tokenStartIndex = currentColumnIndex;
StringBuilder tokenValue = new StringBuilder();
int nextChar = peekNextChar();
if (currentChar == '0' && (nextChar == 'x' || nextChar == 'X')) {
// hexadecimal number, consume "0x"
return parseHexNumberLiteral();
} else {
return parseDecimalNumberLiteral();
}
}

private Token parseDecimalNumberLiteral() throws ParseException {
int tokenStartIndex = currentColumnIndex;
StringBuilder tokenValue = new StringBuilder();

int lastChar = -1;
boolean scientificNotation = false;
while (currentChar != -1 && isAtNumberChar()) {
if (currentChar == 'e' || currentChar == 'E') {
scientificNotation = true;
}
tokenValue.append((char) currentChar);
lastChar = currentChar;
consumeChar();
}
// illegal scientific format literal
if (scientificNotation
&& (lastChar == 'e'
|| lastChar == 'E'
|| lastChar == '+'
|| lastChar == '-'
|| lastChar == '.')) {
throw new ParseException(
new Token(tokenStartIndex, tokenValue.toString(), TokenType.NUMBER_LITERAL),
"Illegal scientific format");
}
return new Token(tokenStartIndex, tokenValue.toString(), TokenType.NUMBER_LITERAL);
}

private Token parseHexNumberLiteral() {
int tokenStartIndex = currentColumnIndex;
StringBuilder tokenValue = new StringBuilder();

// hexadecimal number, consume "0x"
tokenValue.append((char) currentChar);
consumeChar();
tokenValue.append((char) currentChar);
consumeChar();
while (currentChar != -1 && isAtHexChar()) {
tokenValue.append((char) currentChar);
consumeChar();
while (currentChar != -1 && isAtHexChar()) {
tokenValue.append((char) currentChar);
consumeChar();
}
} else {
// decimal number
int lastChar = -1;
while (currentChar != -1 && isAtNumberChar()) {
tokenValue.append((char) currentChar);
lastChar = currentChar;
consumeChar();
}
// illegal scientific format literal
if (lastChar == 'e' || lastChar == 'E' || lastChar == '+' || lastChar == '-') {
throw new ParseException(
new Token(tokenStartIndex, tokenValue.toString(), TokenType.NUMBER_LITERAL),
"Illegal scientific format");
}
}
return new Token(tokenStartIndex, tokenValue.toString(), TokenType.NUMBER_LITERAL);
}
Expand Down Expand Up @@ -485,7 +506,7 @@ private boolean isAtNumberStart() {
private boolean isAtNumberChar() {
int previousChar = peekPreviousChar();

if (previousChar == 'e' || previousChar == 'E') {
if ((previousChar == 'e' || previousChar == 'E') && currentChar != '.') {
return Character.isDigit(currentChar) || currentChar == '+' || currentChar == '-';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ void testFunctionTooManyParameters() {
"Hello 1 + 1",
"Hello World",
"Hello 1",
"1 2"
"1 2",
"e.1",
"E.1"
})
void testTooManyOperands(String expressionString) {
Expression expression = new Expression(expressionString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ void testSciOK() throws ParseException {
}

@ParameterizedTest
@ValueSource(strings = {"2e", "2E", "2e+", "2E+", "2e-", "2E-", "2e."})
@ValueSource(strings = {"2e", "2E", "2e+", "2E+", "2e-", "2E-", "2e.", "2E.", "2ex", "2Ex"})
void testScientificLiteralsParseException(String expression) {
assertThatThrownBy(() -> new Tokenizer(expression, configuration).parse())
.isInstanceOf(ParseException.class)
Expand Down

0 comments on commit 7c39c54

Please sign in to comment.