Prior to this change, if the new size of the string/bytes after
appending the other one onto it was going to be exactly a
power of two, and if we were also copying an additional null
terminator byte from the other one, then this method was
violating memory safety.
Specifically, it would reserve space only for the new size,
without reserving an extra byte for the null terminator it
was going to copy. Thus when it came time to copy in the
null terminator byte, it was possibly getting written into
the first byte of another object!
In practice this was resulting in a change to the type
descriptor pointer for that other object, causing it to
behave like a different type for type match purposes
and for virtual calls, which led to further corruption
of memory and a cascade of strange behavior in the program.
Prior to this change, if the new size of the string/bytes after appending the other one onto it was going to be exactly a power of two, and if we were also copying an additional null terminator byte from the other one, then this method was violating memory safety.
Specifically, it would reserve space only for the new size, without reserving an extra byte for the null terminator it was going to copy. Thus when it came time to copy in the null terminator byte, it was possibly getting written into the first byte of another object!
In practice this was resulting in a change to the type descriptor pointer for that other object, causing it to behave like a different type for type match purposes and for virtual calls, which led to further corruption of memory and a cascade of strange behavior in the program.