Re: Invalid UTF-8

William Spitzak <[email protected]>
Newsgroups gmane.text.yaml.general
Message-ID <[email protected]>
Oren Ben-Kiki wrote:

> I have no special interest in "helping Unicode". All I want is the
> security of knowing that a YAML file is portable across systems,

My files contain the valid UTF-8 encodings of '\', 'X', and two hex 
digits. They are valid Unicode and are therefore "portable across systems".

> What encoding is used for file names?

UTF-8.

The fact that it is physically possible for the byte arrays naming the 
file to contain an invalid UTF-8 sequence does not change this, any more 
than the possibility of a misspelled word means that we cannot say a 
text file is in English.

> When you type "ls" in a shell inside an xterm window, and it
> displays the file names, somewhere along the chain there _must_ be an
> assumption about the encoding used for the file names.

The assumption is done inside the code in Xterm that decides how to 
*DISPLAY* the string on the screen (try "glob" instead of "ls" if you 
are confused by ls's attempt to do a *display* function of columnizing 
the filenames).

> The POSIX
> standard solves this by mandating that filenames must be encoded
> according to the LC_CTYPE locale setting (I don't recall chapter and
> verse off the top of my head; it has been a while).

Wrong. The current standard is "you must set locale to something using 
UTF-8 so that programs that still pay attention to it will not 
misinterpret the UTF-8 filenames." If you do not do this then UTF-16 
filesystems such as NTFS are unreadable and filenames will not match 
between platforms.

> What happens if the bytes in the filename are not valid according to the
> LC_CTYPE locale setting?

Nothing happens until there is a need to interpret the filename as 
Unicode code points, like when an attempt is made to render it on the 
screen. At that point the display routine should figure out a useful 
method of showing the erroneous bytes to the user. Lossy methods such as 
treating the bytes as CP1252 are harmless here (this is in fact the 
solution used by html browsers).

> For example, what would a Java
> program (that can only deal with UTF-16 characters) see when it fetches
> the name of such a file? I'm not really certain but I suspect it isn't
> pretty...

JAVA has a bug and cannot operate a UTF-8 filesystem. They either need a 
new byte-oriented api to the filesystem, or (more likely) a lossless 
method to encrypt UTF-8 into UTF-16 arrays (a popular one is to do 
UTF-16 "decoding" but turn invalid bytes into a 0xDCxx word and consider 
the UTF-8 encodings of U+DC80..U+DCFF to be invalid byte sequences).

A bug in JAVA is no excuse. If I wrote a decoder that threw an error on 
misspelled words, does that mean that YAML now must be defined to not 
allow misspelled words? Or would you correctly say that the problem is 
my decoder?

> At any rate, YAML doesn't attempt to act as a "transparent pipeline"
> allowing you to put anything-at-all on one side and get
> exactly-the-same-thing on the other. It definitely _does_ have
> restrictions about "what you can put in" (e.g., no duplicate keys in
> mappings, so PHP must therefore use sequence-of-single-pair-mappings for
> its weird data).

Being able to read raw invalid UTF-8 seemed to be a requirement from 
YAML's basic design principle of being "editable by users".

However I believe you are worried that programmers will use the ability 
as a "data compression" method for arbitrary binary data and I agree 
this is a problem. The \XNN sequence expands random binary data by 3 
times, so programmers will probably prefer the 4/3 expansion of base64. 
However that won't stop a determined programmer from coding their own 
writer that uses raw bytes as much as possible.

There may be a solution where libyaml could continue to reject invalid 
UTF-8 input: We could assume the editor sanitizes the invalid UTF-8 into 
the equivalent \XNN sequences. I'm sure Emacs could be told to do this 
in "yaml mode". I initially wanted to use \nnn octal escapes because 
there actually are examples of existing programs that produce this 
escape. I did not do this because of your use of \0 for nul (it would 
break if followed by a '0' through '7' byte). Using \xNN also has this 
nice property but is obviously incompatible.

> IMO, if the LC_CTYPE locale is UTF-8, the kernel would be
> within its rights to _reject_ any attempts to create files containing
> invalid UTF-8 bytes, or at minimum convert them into an "equivalent"
> valid UTF-8 string.

The filesystem (not the Kernel) is allowed to reject ANY byte array for 
any reason it wants. For instance the FAT driver rejects an awful lot of 
byte sequences such as ':' or a sequence where the ASCII letters if case 
is swapped name an existing unreadable file. All file systems I have 
seen reject strings with '/' in them where the part before the '/' is 
not an existing directory.

I fail to see how libyaml's rejection of a certain subset of byte arrays 
just because it MAY be a set a filesystem will reject is any kind of 
excuse however.

> AFAIK Apple's OS-X does exactly that, since it uses UTF-16 internally in
> HFS (even if it presents filenames as UTF-8 to the applications).

OS/X can handle NFS mounts and NFS can explicitly return arbitrary byte 
arrays including invalid UTF-8. Terminal App decodes strings as though 
they are UTF-8 and (suprise for me) displays invalid byte sequences as 
the hex code in a block.

HFS translates the Unicode into decomposed normalized form and therefore 
rejects and remaps quite a number of UTF-8 sequences. I fail to see how 
libyaml doing a tiny subset of it's manipulations helps me.

> Linux
> does not do this; I'm not certain about BSD and Solaris and AIX and QNX
> and all the other UNIXes out there.

Linux treats filenames as arrays of bytes, and explicitly supports some 
filesystems such as Ext3 where all possible arrays of bytes not 
containing 0x25 or 0x00 identify different files.

> Then there's Plan9 ("UNIX as it
> should have been") who _invented_ UTF-8 and I'm willing to bet that they
> definitely enforce valid UTF-8 filenames.

Plan9 accepted any array of bytes as a filename as long as it did not 
contain a 0x00 or 0x25 byte. Read the 9FS specification for details.

The 9.5 window system did interpret UTF-8 to draw glyphs on the screen. 
Assuming they used their torune() function to look up the glyphs, they 
drew each invalid UTF-8 byte as a '?', and they also did not detect 
overlong encodings as errors. Cut & paste handled the original UTF-8 as 
raw bytes (9.5 simply indicated the point in the string closest to the 
glyph the user clicked on) so even this unsafe and lossy practice was 
harmless in Plan9. This is an excellent example where interpretation was 
correctly deferred until display.

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.