Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Race Condition in Zend\Cache\Storage\Adapter\Filesystem::prepareDirectoryStructure #6435

Closed
dasann opened this issue Jul 2, 2014 · 2 comments
Assignees
Milestone

Comments

@dasann
Copy link

dasann commented Jul 2, 2014

In case there are lot of parallel requests writing caches in the same directory, you may have problems at creating the cachedir.
If a parallel request creates the directory between

if (file_exists($pathname)) {
            return;
}

and

if (!$res) {
                $oct = ($perm === false) ? '777' : decoct($perm);
                $err = ErrorHandler::stop();
                throw new Exception\RuntimeException(
                    "mkdir('{$pathname}', 0{$oct}, true) failed", 0, $err
                );
}

the application will throw an exception.

The solution could be just to add another file_exist($pathname) to the second condition, like this:

 if (!$res && !file_exists($pathname)

I also wrote a little quick and dirty test to verify the problem and the solution:

public function testRaceConditionInPrepareDirectoryStructure()
    {
        $cachedirPath = 'cachetest';

        \vfsStreamWrapper::register();
        $root = \vfsStream::newDirectory($cachedirPath);
        \vfsStreamWrapper::setRoot($root);

        $builtInWrapperMock = LouisMockery::mock('Zend\Cache\Storage\Adapter\BuiltInWrapper');
        $builtInWrapperMock->shouldReceive('fileExists')->andReturn(false);

        $storageAdapter = new \Zend\Cache\Storage\Adapter\Filesystem();

        $storage = new \ReflectionClass('Zend\Cache\Storage\Adapter\Filesystem');
        $storage->getMethod('prepareDirectoryStructure')->setAccessible(true);

        $storage->getMethod('setBuiltInWrapper')->invoke($storageAdapter, $builtInWrapperMock);
        $method = $storage->getMethod('prepareDirectoryStructure');
        $method->setAccessible(true);
        $method->invoke($storageAdapter, \vfsStream::url($cachedirPath));
    } 

Because it's difficult to mock built-in-functions, I wrapped the file_exist() in a special class called BuiltInWrapper.

@marc-mabe
Copy link
Member

@david-sann You are right. In this case the exception is wrong.
For the mocked filesystem part of testing it needs more work but this is another example why it could be a good idea.

@Ocramius
Copy link
Member

Handled in #6573

gianarb pushed a commit to zendframework/zend-cache that referenced this issue May 15, 2015
gianarb pushed a commit to zendframework/zend-cache that referenced this issue May 15, 2015
gianarb pushed a commit to zendframework/zend-cache that referenced this issue May 15, 2015
gianarb pushed a commit to zendframework/zend-cache that referenced this issue May 15, 2015
boesing pushed a commit to laminas/laminas-cache-storage-adapter-apc that referenced this issue May 24, 2020
boesing pushed a commit to laminas/laminas-cache-storage-adapter-apc that referenced this issue May 24, 2020
boesing pushed a commit to laminas/laminas-cache-storage-adapter-filesystem that referenced this issue Jul 4, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants