Skip to content

Commit

Permalink
Fix wrong error message when parsing string wuth invalid escaping (#1288
Browse files Browse the repository at this point in the history
)
  • Loading branch information
plokhotnyuk authored Feb 5, 2025
1 parent ef5155d commit ebfcf1d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 45 deletions.
67 changes: 22 additions & 45 deletions zio-json/shared/src/main/scala/zio/json/internal/lexer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,8 @@ object Lexer {
c = in.readChar()
c != '"'
}) {
if (c == '\\') {
(in.readChar(): @switch) match {
case '"' => c = '"'
case '\\' => c = '\\'
case '/' => c = '/'
case 'b' => c = '\b'
case 'f' => c = '\f'
case 'n' => c = '\n'
case 'r' => c = '\r'
case 't' => c = '\t'
case 'u' => c = nextHex4(trace, in)
case _ => error(c, trace)
}
} else if (c < ' ') error("invalid control in string", trace)
if (c == '\\') c = nextEscaped(trace, in)
else if (c < ' ') error("invalid control in string", trace)
bs = matrix.update(bs, i, c)
i += 1
}
Expand Down Expand Up @@ -181,7 +169,7 @@ object Lexer {
case 'r' => '\r'
case 't' => '\t'
case 'u' => Lexer.nextHex4(trace, in)
case _ => Lexer.error(c, trace)
case c => Lexer.error(c, trace)
}).toInt
} else if (c == '\\') {
escaped = true
Expand Down Expand Up @@ -209,20 +197,8 @@ object Lexer {
c = in.readChar()
c != '"'
}) {
if (c == '\\') {
(in.readChar(): @switch) match {
case '"' => c = '"'
case '\\' => c = '\\'
case '/' => c = '/'
case 'b' => c = '\b'
case 'f' => c = '\f'
case 'n' => c = '\n'
case 'r' => c = '\r'
case 't' => c = '\t'
case 'u' => c = nextHex4(trace, in)
case _ => error(c, trace)
}
} else if (c < ' ') error("invalid control in string", trace)
if (c == '\\') c = nextEscaped(trace, in)
else if (c < ' ') error("invalid control in string", trace)
if (i == cs.length) cs = java.util.Arrays.copyOf(cs, i << 1)
cs(i) = c
i += 1
Expand All @@ -236,28 +212,29 @@ object Lexer {
c = in.readChar()
if (
c == '"' || {
if (c == '\\') {
(in.readChar(): @switch) match {
case '"' => c = '"'
case '\\' => c = '\\'
case '/' => c = '/'
case 'b' => c = '\b'
case 'f' => c = '\f'
case 'n' => c = '\n'
case 'r' => c = '\r'
case 't' => c = '\t'
case 'u' => c = nextHex4(trace, in)
case _ => error(c, trace)
}
} else if (c < ' ') error("invalid control in string", trace)
if (c == '\\') c = nextEscaped(trace, in)
else if (c < ' ') error("invalid control in string", trace)
in.readChar() != '"'
}
) error("expected single character string", trace)
c
}

// consumes 4 hex characters after current
@noinline def nextHex4(trace: List[JsonError], in: OneCharReader): Char = {
@noinline private[this] def nextEscaped(trace: List[JsonError], in: OneCharReader): Char =
(in.readChar(): @switch) match {
case '"' => '"'
case '\\' => '\\'
case '/' => '/'
case 'b' => '\b'
case 'f' => '\f'
case 'n' => '\n'
case 'r' => '\r'
case 't' => '\t'
case 'u' => nextHex4(trace, in)
case c => error(c, trace)
}

def nextHex4(trace: List[JsonError], in: OneCharReader): Char = {
var i, accum = 0
while (i < 4) {
val c = in.readChar()
Expand Down
19 changes: 19 additions & 0 deletions zio-json/shared/src/test/scala/zio/json/DecoderSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,25 @@ object DecoderSpec extends ZIOSpecDefault {
val spec: Spec[Environment, Any] =
suite("Decoder")(
suite("fromJson")(
test("string") {
assert(""""abc"""".fromJson[String])(isRight(equalTo("abc"))) &&
assert(""""abc\n"""".fromJson[String])(isRight(equalTo("abc\n"))) &&
assert("\"abc\\u0182\"".fromJson[String])(isRight(equalTo("abcƂ"))) &&
assert("\"abc\\u1Ee1\"".fromJson[String])(isRight(equalTo("abcỡ"))) &&
assert(""""abc\x"""".fromJson[String])(isLeft(equalTo("""(invalid '\x' in string)"""))) &&
assert("\"\u0000\"".fromJson[String])(isLeft(equalTo("""(invalid control in string)"""))) &&
assert("\"\\u0000\"".replace('0', 'g').fromJson[String])(isLeft(equalTo("""(invalid charcode in string)""")))
},
test("char") {
assert(""""a"""".fromJson[Char])(isRight(equalTo('a'))) &&
assert(""""\n"""".fromJson[Char])(isRight(equalTo('\n'))) &&
assert("\"\\u0182\"".fromJson[Char])(isRight(equalTo('Ƃ'))) &&
assert("\"\\u1Ee1\"".fromJson[Char])(isRight(equalTo('ỡ'))) &&
assert(""""aa"""".fromJson[Char])(isLeft(equalTo("""(expected single character string)"""))) &&
assert(""""\x"""".fromJson[Char])(isLeft(equalTo("""(invalid '\x' in string)"""))) &&
assert("\"\u0000\"".fromJson[Char])(isLeft(equalTo("""(invalid control in string)"""))) &&
assert("\"\\u0000\"".replace('0', 'g').fromJson[Char])(isLeft(equalTo("""(invalid charcode in string)""")))
},
test("byte") {
assert("-123".fromJson[Byte])(isRight(equalTo(-123: Byte))) &&
assert("123".fromJson[Byte])(isRight(equalTo(123: Byte))) &&
Expand Down

0 comments on commit ebfcf1d

Please sign in to comment.