diff --git a/src/main/java/com/amazon/ion/impl/IonReaderTextRawTokensX.java b/src/main/java/com/amazon/ion/impl/IonReaderTextRawTokensX.java index 9a7a445a6..18743648b 100644 --- a/src/main/java/com/amazon/ion/impl/IonReaderTextRawTokensX.java +++ b/src/main/java/com/amazon/ion/impl/IonReaderTextRawTokensX.java @@ -2582,6 +2582,13 @@ private final int read_escaped_char_content_helper(int c1, boolean is_clob) bad_escape_sequence(c2); } c2 = read_hex_escape_sequence_value(8); + // Eight hex digits can set the sign bit, wrapping the assembled + // value negative. A negative result is always out of the Unicode + // range and would otherwise slip past the downstream + // Character.MAX_CODE_POINT check, decoding to an unrelated char. + if (c2 < 0) { + error("invalid code point in \\U escape sequence"); + } break; case IonTokenConstsX.ESCAPE_HEX: c2 = read_hex_escape_sequence_value(2); diff --git a/src/test/java/com/amazon/ion/StringTest.java b/src/test/java/com/amazon/ion/StringTest.java index 79dff34f1..782f275ed 100644 --- a/src/test/java/com/amazon/ion/StringTest.java +++ b/src/test/java/com/amazon/ion/StringTest.java @@ -1,18 +1,5 @@ -/* - * Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 package com.amazon.ion; import org.junit.Test; @@ -215,6 +202,22 @@ public void testTrickyEscapes() checkString(expected, value); } + @Test + public void testBigUEscapeOutOfRange() + { + // Eight hex digits with the high bit set wrap the assembled value + // negative, which must still be rejected rather than decoded to a + // stray character (previously \\U80000000..\\UFFFFFFFF yielded U+FFFF). + badValue("\"\\U80000000\""); + badValue("\"\\UFFFFFFFF\""); + // Positive values beyond the Unicode range stay rejected. + badValue("\"\\U00110000\""); + // The maximum valid scalar is still accepted. + IonString value = (IonString) oneValue("\"\\U0010FFFF\""); + assertEquals(new StringBuilder().appendCodePoint(0x10FFFF).toString(), + value.stringValue()); + } + @Test public void testReadStringsFromSuite() throws Exception