[rubygems/rubygems] Properly protect writing binstubs with a file lock
There's an issue when multiple processes try to write the same binstub.
The problem is that our file locking mechanism is incorrect because
files are truncated before they are locked. So it can happen that:
Process A truncates binstub FOO.
Process B truncates binstub FOO.
Process A writes binstub FOO for gem BAR from the beginning of file.
Process B writes binstub FOO for gem BAZ from the beginning of file.
If binstub FOO for gem BAR is bigger than binstub FOO for gem BAZ, then
some bytes will be left around at the end of the binstub, making it
corrupt.
This was not a problem in our specs until the spec testing binstubs with
the same name coming from different gems changed from using gems named
"fake" and "rack" to using gems named "fake" and "myrack". Because of
the difference in gem name length, the generated binstub for gem
"myrack" is now longer, causing the above problem if binstub for gem
myrack is written first.
The solution is to make sure when using flock to always use modes that
DON'T truncate the file when opening it. So, we use r+ if the file
exists previously (it requires the file to exist previously), otherwise
we use a+.
[rubygems/rubygems] Properly protect writing binstubs with a file lock
There's an issue when multiple processes try to write the same binstub.
The problem is that our file locking mechanism is incorrect because
files are truncated before they are locked. So it can happen that:
If binstub FOO for gem BAR is bigger than binstub FOO for gem BAZ, then
some bytes will be left around at the end of the binstub, making it
corrupt.
This was not a problem in our specs until the spec testing binstubs with
the same name coming from different gems changed from using gems named
"fake" and "rack" to using gems named "fake" and "myrack". Because of
the difference in gem name length, the generated binstub for gem
"myrack" is now longer, causing the above problem if binstub for gem
myrack is written first.
The solution is to make sure when using flock to always use modes that
DON'T truncate the file when opening it. So, we use
r+
if the fileexists previously (it requires the file to exist previously), otherwise
we use
a+
.https://github.com/rubygems/rubygems/commit/ce8bcba90f