That's why the compiler passes a temporary ShortString variable and then assigns that to the shorter string. Yes, that might mean that data gets lost then, but that's how short strings work!
I'm sorry, it's working wrong in that case: the size of the destination is known, and even if data loss is expected there's absolutely no need to move more than that number of characters.
If it is a plain
ShortString parameter then the maximum size
is 255, because that's what a
ShortString's maximum length
is. However in the
bug reported by
ccrause FPK highlighted an aspect that neither of us had on the radar: Open Strings (and also Strict String Checking).
Open Strings is exactly what solves this problem in Delphi and which is also supported in FPC: if that switch is enabled (
$P+ or
{$OpenStrings On}) then if you have a
var parameter of type
ShortString then the compiler will provide an additional, hidden
High parameter which will contain the maximum length of the provided string variable. If that switch is not enabled then there will be no hidden
High parameter and
High(aArg) will
always return
255 for a
ShortString variable. The thing is that in Delphi (and presumably also TP) the Open Strings are enabled by default, while in FPC they aren't enabled by default (in any mode). Also the switch is a local one in Delphi, but a global one in FPC (that should be changed).
Also there is the Strict String Checking which is controlled by the
$V or
$VarStringChecks directive. This controls whether you can pass a
String[<N>] to a function declared with a
var parameter of type
String[<M>] where
<N> <> <M>. This is a
local switch and by default is is enabled in Delphi and it's also enabled by default in FPC in modes
TP and
Delphi.
So every passing of a by-reference
ShortString here works
by design. And yes, that includes potentially doing buffer overflows.
Side note: Delphi applies these switches only to
var parameters, but FPC also applies them to
out parameters.
But the fact that the result is truncated is not relevant here. What /is/ relevant is that the stack has to have the potential of being 256 bytes larger than expected, and that this requirement is multiplied if the overall program uses multiple threads or coroutines. And speaking as a sometime embedded system programmer, that is a grievous fault.
I'm not saying that the string concatenation shouldn't be improved (after all I did give
ccrause feedback to his changes). I'm only saying that everything here works
as designed (though one
can argue over the default settings of the switches).
This is fundamental, 1980s stuff. And if it breaks something more recent like RTTI, then it's the more recent stuff that has to be adjusted.
That was just some side note I got when testing this in Delphi. FPC correctly generates the RTTI for a method containing an OpenString parameter
