Repository navigation
Conversation
The high byte of the low surrogate was computed with the mask 0xFF instead of 0x03, so it also picked up bits that belong to the high surrogate. For example U+1F310 was written as D83C CF10 instead of D83C DF10. This code was unreachable so far, because the emitter always escapes characters above U+FFFF as "\UXXXXXXXX".
IS_PRINTABLE covered only the 1-3 byte ranges of c-printable. Even with yaml_emitter_set_unicode(emitter, 1), characters outside the BMP (e.g. emoji) were escaped as "\U0001F310", which also forced the scalar into double quoted style. c-printable includes [#x10000-#x10FFFF] in YAML 1.1 and 1.2. Add the 4 byte range to the macro. The upper bound is checked exactly, because yaml_check_utf8() does not reject sequences above U+10FFFF. Add tests/test-emitter.c to check the escaping and the UTF-16 output of such characters. Fixes yaml#279
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #279. Downstream reports: ruby/psych#371, ruby/psych#508, glebm/i18n-tasks#291.
Problem
With
yaml_emitter_set_unicode(emitter, 1), 3-byte UTF-8 characters are written as is, but 4-byte characters (U+10000–U+10FFFF, e.g. emoji) are still escaped. A single such character also forces the whole scalar into double quoted style:Output with
unicode = 0(the default) is unchanged.Cause
IS_PRINTABLE_ATimplementsc-printableonly up to#xFFFD. The production includes[#x10000-#x10FFFF]in YAML 1.1 as well as 1.2:PyYAML's
analyze_scalarhas had this range since 2017 (yaml/pyyaml@cf1c86c).Changes
src/writer.c). The high byte of the low surrogate was masked with0xFFinstead of0x03; U+1F310 came out asD83C CF10instead ofD83C DF10. This was unreachable until now, because characters above U+FFFF were always escaped. This commit comes first, because with only the macro change PyYAML's test suite fails in 6 tests withUnicodeDecodeError: illegal UTF-16 surrogate.IS_PRINTABLE_AT(src/yaml_private.h), in the same style as the existing clauses. The upper bound is exact (F4 90 ..and above stay escaped), becauseyaml_check_utf8()does not reject sequences above U+10FFFF.tests/test-emitter.c, registered for both CMake and autotools. It compares the emitted bytes for the range boundaries, both code paths (analyze_scalarandwrite_double_quoted_scalar),unicode = 0, and UTF-16LE/BE. The yaml-test-suite cannot cover this, sincerun-emitter-test-suiteruns withunicode = 0.No dependency is added and no character property tables are needed, because
c-printableis defined by ranges. This is an alternative to #150, which solves the same problem using ICU.Testing
make test-alland the CMake tests pass with gcc and clang on Linux and macOS: https://github.com/Hee-San/libyaml/actions/runs/35680870522{"globe" => "🌐"}.to_yamlnow givesglobe: "🌐"