It was never valid to cast an AnsiString
to a byte array. That code was always broken and you got lucky (or unlucky depending on your point of view).
Managed string types, just like dynamic arrays, have an extra payload of information, metadata, that is stored just before the data payload. This metadata includes reference count, length etc. But the metadata for strings is not the same as for dynamic arrays. Simply put, a string is not a dynamic arrays. Your reinterpret cast is completely invalid. It was invalid in the old versions of Delphi, and it's just as invalid in the modern versions.
What's really going on under the hood is that the size of the metadata has changed with the introduction of Unicode support. The metadata for AnsiString
has been expanded. It now contains, for instance, the code page of the string.
Now, when you call SetLength
, a block of memory large enough for both metadata and payload is allocated. Suppose that memory is allocated at address P. The address that your variable (string or dynamic array) holds is set to P + metadata size. When you come to deallocate the object, the system moves to P - metadata size and calls FreeMem
with that address. And here's the kicker. You use the size of a dynamic array metadata when you allocate, but the size of a string meta data when you deallocate. The result? BOOM! You just called FreeMem
on an invalid address, one that has not been allocated to you.
The correct way to handle this is to give the Indy function what it wants. Namely a byte array. If you need to transfer to a string variable, copy the byte array's content into a new string. For instance using TEncoding.Default.GetString()
.