include-interceptor icon indicating copy to clipboard operation
include-interceptor copied to clipboard

Windows flock support

Open jacyimp opened this issue 2 years ago • 5 comments

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
  • master branch of include-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.

jacyimp avatar Jan 31 '23 18:01 jacyimp

Made a PR to make flock pass-thru.

The test ofc passes now on Windows too since flock is just a pass-thru.

jacyimp avatar Jan 31 '23 18:01 jacyimp

Forgot to mention, infection works perfectly now with that change.

jacyimp avatar Jan 31 '23 18:01 jacyimp

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.

maks-rafalko avatar Feb 02 '23 08:02 maks-rafalko

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)

jacyimp avatar Feb 05 '23 08:02 jacyimp

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.

jacyimp avatar Feb 05 '23 08:02 jacyimp