Skip to content

[HttpFoundation] Use locking for file_put_contents in MockFileSessionStorage #39167

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

Closed
wants to merge 2 commits into from

Conversation

mpdude
Copy link
Contributor

@mpdude mpdude commented Nov 24, 2020

Q A
Branch? 4.4
Bug fix? yes
New feature? no
Deprecations? no
Tickets
License MIT
Doc PR

I am running tests with a headless browser, where there is quite some concurrency in hitting Symfony (several concurrent requests to API endpoints performed by the browser almost at the same time).

From time to time, these tests fail with

request.CRITICAL: Uncaught PHP Exception ErrorException: "Notice: unserialize(): Error at offset 134 of 8192 bytes" at /var/www/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php line 144

Though I cannot really prove this and have no idea how to write a test case for it, my hypothesis is that several processes may try to write to the file concurrently and corrupt it.

Of course, it might also be that the problem is a read operation while another process is writing. I don't know how to tell.

The bigger solution would be to use a more involved scheme of creating the file and moving it in place, as it happens in other places in Symfony?

@mpdude
Copy link
Contributor Author

mpdude commented Nov 25, 2020

I am afraid the LOCK_EX alone would not be enough, since it is using advisory locking only, and the file_get_contents() function does not provide a way to honor that.

So, would you (maybe @jderusse can tell) endorse using Filesystem::dumpFile() from the Filesystem component?

@mpdude
Copy link
Contributor Author

mpdude commented Nov 25, 2020

Further failed test runs on our CI also indicate that there may be a race condition related to the unlink() call: It may fail if another process concurrently removed the session file, and the error will not be contained.

@carsonbot carsonbot changed the title Use locking for file_put_contents in MockFileSessionStorage [HttpFoundation] Use locking for file_put_contents in MockFileSessionStorage Nov 26, 2020
@derrabus
Copy link
Member

So, would you […] endorse using Filesystem::dumpFile() from the Filesystem component?

I don't think that we should introduce such a dependency in a bugfix release, but you could certainly borrow the logic from there.

@jderusse
Copy link
Member

Filesystem::dumpFile is tempnam + file_put_content + rename I think we can safely copy these methods here

@mpdude
Copy link
Contributor Author

mpdude commented Nov 29, 2020

That would give us atomic writes, but what about race conditions and/or concurrent session access?

Last time I checked, PHP’s built in session functions used locking: When one process read the session data on session_start, other requests for the same session ID will block until the session has been closed again and data written. All requests using the same session will be processed sequentially.

Might be too much hassle for something with Mock in the name...

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Dec 8, 2020

I am afraid the LOCK_EX alone would not be enough, since it is using advisory locking only, and the file_get_contents() function does not provide a way to honor that.

then we should replace the call to file_get_contents() by a proper fopen+flock

Further failed test runs on our CI also indicate that there may be a race condition related to the unlink() call

Yes, and in theory also you can get valid yet different-than-expected content when a concurrent process writes new content.

Maybe you should use separate folders to store the session in your case?

PHP’s built in session functions used locking

yes, but that's too much work, and many real drivers don't have locking either.
Better keep as is in this regard.
If we want to add locking to the mock, it should be opt-in and would be a new feature.

@fabpot
Copy link
Member

fabpot commented Jan 5, 2021

@mpdude Are you still interested in moving this PR forward?

@mpdude
Copy link
Contributor Author

mpdude commented Jan 5, 2021

@fabpot Yes, only somewhat limited in spare time atm.

@solverat
Copy link

I'm facing the same thing in my functional tests (worst debugging time of my life). I just tried the Filesystem::dumpFile approach, and it works 👍 ! Implementing the dumpFile source into the MockFileSessionStorage class is a +1 from my side!

@nicolas-grekas
Copy link
Member

Please check #39167 and confirm it fixes your issue if you can.

@jderusse
Copy link
Member

Please check #39167 and confirm it fixes your issue if you can.

you mean #39816?

nicolas-grekas added a commit that referenced this pull request Jan 14, 2021
…ge (nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[HttpFoundation] use atomic writes in MockFileSessionStorage

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #39167
| License       | MIT
| Doc PR        | -

Instead of #39808

Commits
-------

5290e97 [HttpFoundation] use atomic writes in MockFileSessionStorage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants