include-interceptor
include-interceptor copied to clipboard
Windows flock support
Hello,
Background
You can skip this section
After #16 I've been having issues with infection(root project) on one of my projects on windows. Its setup is pretty specific, but basically, every mutant was killed no matter what. After some investigation, it turns out that running the created PHPUnit config files directly with PHPUnit results in the following:
fwrite(): Write of 4 bytes failed with errno=13 Permission denied
I went high and low trying to fix this to no avail; therefore, since then, I've been using Linux for this project of mine. I don't have this issue with some other projects on windows but for the life of me, I can't replicate the exact problem that causes this.
TLDR
test_it_works_with_locks() does not pass on windows. As it seems, a LOCK_SH is a reader_lock, and would prevent any writing from being done on the file at least on Windows. It probably doesn't throw an error on Linux since on Linux, flock() is advisory, but on windows, it's mandatory.
Could be due to this?
flock() uses mandatory locking instead of advisory locking on Windows. php.net ref
Versions
- PHPUnit 9.5.28
masterbranch ofinclude-interceptor
Simpler proof (without wrapper)
The following fails on windows:
<?php
$f = fopen('test.test', 'w+');
flock($f, LOCK_SH);
fwrite($f, 'hi'); // Notice: fwrite(): Write of 2 bytes failed with errno=13 Permission denied
This doesn't fail though:
<?php
$f = fopen('test.test', 'w+');
fwrite($f, 'hello world');
$f = fopen('test.test', 'r+');
flock($f, LOCK_SH);
echo fread($f, 100); //outputs: hello world
Hence my idea of LOCK_SH working only for reads, and failing on something like file_put_content().
Possible fix
Could we just make flock pass-thru with a return true;? I can't see why would the LOCK_SH would be useful.
Made a PR to make flock pass-thru.
The test ofc passes now on Windows too since flock is just a pass-thru.
Forgot to mention, infection works perfectly now with that change.
Hello, thanks for working on this and debugging.
Related to https://github.com/dg/bypass-finals/commit/101d0cc4b836d2a7745d745bc7b1fadcdcaf3b22
seems like solution on bypass-finals can resolve #16 and issue mentioned here about windows. Could you please try it? If it works, let's update your PR and I will be happy to merge.
That indeed fixes the default file_put_contents() flag param(0) but it does not fix the issue that:
1- StreamWrapper stream type not supporting LOCK_EX (2): IRC PHPUnit strictly specifies LOCK_EX(2) as the flag for their file_put_contents, hence #16
2- LOCK_SH on windows, not supporting write operations. (which is the strictly specified now since #16)
The Interceptor has to catch the LOCK_EX and just pass it through since it doesn't support it.
Gotta watch out for edge cases such as LOCK_EX|LOCK_NB too. Something like this:
$operation &= (~LOCK_EX);
return $operation
? flock($this->handle, $operation)
: true;
To support the 0 case, the LOCK_EX not supported case, and NB cases.