diff --git a/klaxon/src/main/kotlin/com/beust/klaxon/KlaxonParser.kt b/klaxon/src/main/kotlin/com/beust/klaxon/KlaxonParser.kt index 01a7c02..9b6ac27 100644 --- a/klaxon/src/main/kotlin/com/beust/klaxon/KlaxonParser.kt +++ b/klaxon/src/main/kotlin/com/beust/klaxon/KlaxonParser.kt @@ -136,7 +136,10 @@ internal class KlaxonParser( VALUE_TYPE.tokenType, { world: World, token: Token -> with(world) { popStatus() - val key = popValue() as String + val key = popValue() + if (key !is String) { + throw KlaxonException("Object keys must be strings, got: $key") + } parent = getFirstObject() parent[key] = (token as Value<*>).value status = peekStatus() @@ -148,7 +151,10 @@ internal class KlaxonParser( LEFT_BRACKET.tokenType, { world: World, _: Token -> with(world) { popStatus() - val key = popValue() as String + val key = popValue() + if (key !is String) { + throw KlaxonException("Object keys must be strings, got: $key") + } parent = getFirstObject() val newArray = JsonArray() parent[key] = newArray @@ -160,7 +166,10 @@ internal class KlaxonParser( LEFT_BRACE.tokenType, { world: World, _: Token -> with(world) { popStatus() - val key = popValue() as String + val key = popValue() + if (key !is String) { + throw KlaxonException("Object keys must be strings, got: $key") + } parent = getFirstObject() val newObject = JsonObject() parent[key] = newObject diff --git a/klaxon/src/main/kotlin/com/beust/klaxon/Lexer.kt b/klaxon/src/main/kotlin/com/beust/klaxon/Lexer.kt index 2cb160b..05182e0 100644 --- a/klaxon/src/main/kotlin/com/beust/klaxon/Lexer.kt +++ b/klaxon/src/main/kotlin/com/beust/klaxon/Lexer.kt @@ -116,12 +116,21 @@ class Lexer(passedReader: Reader, val lenient: Boolean = false): Iterator 't' -> currentValue.append("\t") 'u' -> { val unicodeChar = StringBuilder(4) - .append(nextChar()) - .append(nextChar()) - .append(nextChar()) - .append(nextChar()) - - val intValue = java.lang.Integer.parseInt(unicodeChar.toString(), 16) + try { + unicodeChar + .append(nextChar()) + .append(nextChar()) + .append(nextChar()) + .append(nextChar()) + } catch(_: IllegalStateException) { + throw KlaxonException("EOF reached in unicode char after: u$unicodeChar") + } + + val intValue = try { + java.lang.Integer.parseInt(unicodeChar.toString(), 16) + } catch(e: NumberFormatException) { + throw KlaxonException("Failed to parse unicode char: u$unicodeChar") + } currentValue.append(intValue.toChar()) } else -> currentValue.append(c) @@ -165,7 +174,7 @@ class Lexer(passedReader: Reader, val lenient: Boolean = false): Iterator } else if (!isDone) { while (isValueLetter(c)) { currentValue.append(c) - if (! isValueLetter(peekChar())) { + if (isDone || !isValueLetter(peekChar())) { break } else { c = nextChar() diff --git a/klaxon/src/test/kotlin/com/beust/klaxon/JazzerTest.kt b/klaxon/src/test/kotlin/com/beust/klaxon/JazzerTest.kt new file mode 100644 index 0000000..2ce9d29 --- /dev/null +++ b/klaxon/src/test/kotlin/com/beust/klaxon/JazzerTest.kt @@ -0,0 +1,41 @@ +package com.beust.klaxon + +import org.testng.annotations.Test + +class JazzerTest { + @Test(expectedExceptions = [KlaxonException::class]) + fun characterInNumericLiteral() { + val json = "0r" + Parser.default().parse(StringBuilder(json)) + } + + @Test(expectedExceptions = [KlaxonException::class]) + fun numericKeyAndObject() { + val json = "{1{" + Parser.default().parse(StringBuilder(json)) + } + + @Test(expectedExceptions = [KlaxonException::class]) + fun numericKeyAndArray() { + val json = "{3[" + Parser.default().parse(StringBuilder(json)) + } + + @Test(expectedExceptions = [KlaxonException::class]) + fun numericKeyAndString() { + val json = "{0\"\"" + Parser.default().parse(StringBuilder(json)) + } + + @Test(expectedExceptions = [KlaxonException::class]) + fun incompleteUnicodeEscape() { + val json = "\"\\u" + Parser.default().parse(StringBuilder(json)) + } + + @Test(expectedExceptions = [KlaxonException::class]) + fun nonNumericUnicodeEscape() { + val json = "\"\\u\\\\{[" + Parser.default().parse(StringBuilder(json)) + } +}