Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows flock support #20

Open
jacyimp opened this issue Jan 31, 2023 · 5 comments
Open

Windows flock support #20

jacyimp opened this issue Jan 31, 2023 · 5 comments

Comments

@jacyimp
Copy link

jacyimp commented Jan 31, 2023

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
Copy link
Author

jacyimp commented Jan 31, 2023

Made a PR to make flock pass-thru.

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

@jacyimp
Copy link
Author

jacyimp commented Jan 31, 2023

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

@maks-rafalko
Copy link
Member

maks-rafalko commented Feb 2, 2023

Hello, thanks for working on this and debugging.

Related to dg/bypass-finals@101d0cc

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.

@jacyimp
Copy link
Author

jacyimp commented Feb 5, 2023

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
Copy link
Author

jacyimp commented Feb 5, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants