Skip to content

Commit 0ba64a6

Browse files
authored
Fix TOML parse failure when number token hits buffer edge (#356)
When a number token is exactly at the end of the lexer text buffer, the parser would advance the lexer, triggering a buffer refill, before the number is parsed from the buffer. This patch moves the advance operation to come after parsing, which resolves the issue. Kudos to @wbprime for finding this and reporting it as micronaut-projects/micronaut-toml#93 . Not even the fuzzer managed to hit this – maybe because it does not fail fast, and just returns the wrong output (NumberInput does no input checking)?
1 parent 3ecd76c commit 0ba64a6

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

toml/src/main/java/com/fasterxml/jackson/dataformat/toml/Parser.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.fasterxml.jackson.databind.node.ArrayNode;
88
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
99
import com.fasterxml.jackson.databind.node.ObjectNode;
10+
import com.fasterxml.jackson.databind.node.ValueNode;
1011

1112
import java.io.IOException;
1213
import java.io.Reader;
@@ -242,7 +243,12 @@ private JsonNode parseInt(int nextState) throws IOException {
242243
}
243244
}
244245

246+
ValueNode node = parseIntFromBuffer(buffer, start, length);
245247
pollExpected(TomlToken.INTEGER, nextState);
248+
return node;
249+
}
250+
251+
private ValueNode parseIntFromBuffer(char[] buffer, int start, int length) throws TomlStreamReadException {
246252
if (length > 2) {
247253
char baseChar = buffer[start + 1];
248254

toml/src/test/java/com/fasterxml/jackson/dataformat/toml/FuzzTomlReadTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public void testBigIntegerDecoding50033() throws Exception
2929
JsonNode n = TOML_MAPPER.readTree(INPUT);
3030
Assert.fail("Should not pass, got: "+n);
3131
} catch (StreamReadException e) {
32-
verifyException(e, "Invalid number");
32+
verifyException(e, "Premature end of file");
3333
// NOTE: decoding of token for error message seems wrong, cannot
3434
// quite verify it for the last line
3535
}
@@ -73,8 +73,7 @@ public void testNumberParsingFail50395() throws Exception
7373
TOML_MAPPER.readTree(INPUT);
7474
Assert.fail("Should not pass");
7575
} catch (StreamReadException e) {
76-
verifyException(e, "Invalid number representation");
77-
verifyException(e, "Illegal leading minus sign");
76+
verifyException(e, "Premature end of file");
7877
}
7978
}
8079

toml/src/test/java/com/fasterxml/jackson/dataformat/toml/ParserTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.fasterxml.jackson.core.io.ContentReference;
55
import com.fasterxml.jackson.core.io.IOContext;
66
import com.fasterxml.jackson.core.json.JsonReadFeature;
7+
import com.fasterxml.jackson.core.util.BufferRecycler;
78
import com.fasterxml.jackson.core.util.BufferRecyclers;
89
import com.fasterxml.jackson.databind.DeserializationFeature;
910
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -23,6 +24,7 @@
2324
import java.time.LocalDateTime;
2425
import java.time.LocalTime;
2526
import java.time.OffsetDateTime;
27+
import java.util.Arrays;
2628

2729
@SuppressWarnings("OctalInteger")
2830
public class ParserTest {
@@ -1027,4 +1029,23 @@ public void unknownEscape() throws IOException {
10271029
expectedException.expectMessage("Unknown escape sequence");
10281030
toml("foo = \"\\k\"");
10291031
}
1032+
1033+
@Test
1034+
public void chunkEdge() throws IOException {
1035+
BufferRecycler br = BufferRecyclers.getBufferRecycler();
1036+
char[] chars = br.allocCharBuffer(0);
1037+
br.releaseCharBuffer(0, chars);
1038+
int bufferLength = chars.length;
1039+
1040+
ObjectNode node = toml("foo = \"" + repeat('a', bufferLength - 19) + "\"\n" +
1041+
"bar = 123\n" +
1042+
"baz = \"" + repeat('a', bufferLength) + "\"");
1043+
Assert.assertEquals(123, node.get("bar").intValue());
1044+
}
1045+
1046+
private static String repeat(char c, int n) {
1047+
char[] chars = new char[n];
1048+
Arrays.fill(chars, c);
1049+
return new String(chars);
1050+
}
10301051
}

0 commit comments

Comments
 (0)