I have the following code (RAD Studio XE2, Windows 7 x64):
program letters;
{$APPTYPE CONSOLE}
{$DEFINE BOO}
const
ENGLISH_ALPHABET = 'abcdefghijklmnopqrstuvwxyz';
begin
{$IFDEF BOO}
writeln;
{$ENDIF}
write(ENGLISH_ALPHABET[1]:3);
readln;
end.
When {$DEFINE BOO}
directive is turned off, I have the following (expected) output (spaces are replaced with dots for readability):
..a
When the directive is turned on, I have the following (unexpected) output:
// empty line here
?..a
instead of expected
// empty line here
..a
When I change const ENGLISH_ALPHABET
to const ENGLISH_ALPHABET: AnsiString
, the expected output is printed without question character. When :3
formatting is removed or changed to :1
, there is no question mark. When the output is redirected to file (either by AssignFile(Output, 'boo.log')
or from command line), there is no question mark again.
What is the correct explanation for this behavior?
This is a rather odd bug in the RTL. The call to
write
resolves to a call to_WriteWChar
. This function is implemented like this:The
?
that you see is emitted by the code above.So, why does this happen. The simplest SSCCE that I can construct is this:
So, your first call
writeln
and that resolves to this:Here you push a single character,
cLF
, ASCII character 10, linefeed, onto the output text record. This results int.MBCSBuffer
being fed thecLF
character. That character is left in the buffer which is fine becauseSystem._Write0Char.WriteUnicodeFromMBCSBuffer
does this:But when
_WriteWChar
executes, it indiscriminately looks int.UTF16Buffer
. Which is declared inTTextRec
like this:So,
MBCSBuffer
andUTF16Buffer
share the same storage.The bug is that
_WriteWChar
should not look at the content oft.UTF16Buffer
without first checking the length of the buffer. Something that is not immediately obvious how to achieve becauseTTextRec
has notUTF16Length
. Instead, ift.UTF16Buffer
contains meaningful content, the convention is that its length is given by-t.MBCSLength
!So
_WriteWChar
should perhaps be:Here is a rather vile hack that fixes
_WriteWChar
. Note that I have not been able to get the address ofSystem._WriteSpaces
to be able to call it. That's something that could be done if you were desperate to fix this.I submitted QC#123157.