Partner and Community Forums
Windows Cache Extension for PHP
Wincache Opcache breaks Drupal 8 install
Last post May 29, 2015 06:28 PM by DropPhone
May 16, 2015 11:03 PM|davidgarcia|LINK
I was about to pull my hair on this while porting the Drupal SQL Server driver to Drupal 8, but after investigation I can only conclude that the Wincache Opcode Cache is breaking Drupal 8 install process.
Why am I using still this Opcode cache instead of Zend's? Because Zend Opcache is broken on Windows, there's at least 10 bugs on the PHP issue queue related to Zend Opcache randomly failing on windows.
Steps to reproduce:
1. Get the latest dev version of Drupal 8 with GIT:
git clone --branch 8.0.x http://git.drupal.org/project/drupal.git
2. Download clean PHP binaries from PHP (5.6.9 Non Thread Safe)
3. Add Wincache 22.214.171.124 to the extension DIR and enable the opcode cache and enable the MySQL pdo:
wincache.ocachesize = 100
4. Configure an IIS site with D8 and the PHP and navigate to the installation URL, introduce the MySQL database details and strat the installation process.
Then this errors shows up:
An AJAX HTTP error occurred.
HTTP Result Code: 200
Debugging information follows.
Fatal error: Class name must be a valid object or a string in D:\DRUPAL OFICIAL\d8\core\lib\Drupal\Core\Entity\Annotation\EntityType.php on line 63
So I investigated and debugged the error with XDebug a few times to find out that this is probably
some sort of encoding issue.
The error originates because this line:
$class = $values['entity_type_class'];
is returning NULL ($class = null).
But.... the $values array DOES contain a KEY named 'entity_type_class'. The only possible explanation for this is that the key inside the array and the 'entity_type_class' literal have different encodings or are not binary equal.
But I tried all imaginable ways to determine if both strings (key and literal) had different encodings, and they look to be exactly the same, PHP's mb_detect_encoding reports they are both ASCII encoded, and using PHP's == and === operator on the literal
and the key return TRUE.
May 18, 2015 02:09 PM|DropPhone|LINK
If you've disabled the opcache, then the opcache can't be the culprit.
Did you mean wincache.ocenabled=1 ?
May 18, 2015 02:43 PM|davidgarcia|LINK
Ups.. I'll have to make double sure that wincache is responsible for this. Can't imagine how the ocenabled=0 got in there.
I'll post back after double checking.
May 22, 2015 09:25 PM|davidgarcia|LINK
Confirmed! I spent time on this because today I found a similar issue on D7, the problem manifests itself in such a strange way in the debugger you clearly see that the array item exists, but accessing the array item fails returning null. (the tests were
run with the debugger extension completely disabled to discard this as a source of the issue).
There have been changes in D8 since my last tests, and the error location has changed but it still of the same nature.
I tried this on a clean PHP 5.6.9 freshly downloaded from the PHP site + a fresh wincache (126.96.36.199) binary from codeplex. All settings in PHP.ini were verified to be efectively setup before running the installation process by calling phpinfo(), and IIS reset
between every test.
1. Download PHP 5.6.9 and copy to desired location and enable the pdo_mysql extension in php.ini.
2. Download Wincache 188.8.131.52 and copy to the extension folder.
3. Clone a D8 copy to a local folder with GIT and in sites/all/default rename default.settings.php to settings.php
4. Configure a site in IIS with PHP Manager that uses the previsouly setup PHP and D8.
5. Browse your site and run the installer - all OK. You can provide MySQL database names on the fly and they will get created.
6. Delete sites/all/default/files/* and settings.php to be able to start the installation again.
7. Enable the wincache extension and set wincache.ocenabled=1
8. Browse your site and run the installer - fails inmediately.
9. Disable wincache, and enable zend opcache.
10. Delete sites/all/default/files/* and settings.php to be able to install the installation again.
11. Browse your site and run the installer - OK.
I also tried to disable file_rerouting (with wincache opcache turned on) with no success.
The issue is that accesing a specific item in an associative array returns null (when the item does exist) and this null gets carried on until an exception is thrown somewhere else in the code due to that null propagating.
I have a remote feeling that this might be related to the PhpBackend storage backend. In D8 they were quite smart and knew that on cheap hosting and for hobbyists setting upc APC or Wincache was too much, so they created a storage backend that uses Opcache
to store data.
The implementation is in core\lib\Drupal\Core\Cache\PHpBackend.php and core\lib\Drupal\Componente\PhpStorage\FileStorage.php
This cache backend writes php files to the disk with serialized data, and then retrieves the data with include_once().
There is nothing else I can think of that could lead to such a bizarre situation and related to Opcode caching (that has proven stable for so long in D7).
D8 is soooo complex that they even found serveral bugs in PHP itself. HHVM included Drupal (and other CMS's) into their test suite.
May 26, 2015 06:21 PM|DropPhone|LINK
Well, it sounds like disabling WinCache's opcode cache and using the Zend Opcode cache is the right answer.
We've marked the WinCache opcode cache as deprecated as of 184.108.40.206, and it's disabled by default for PHP 5.5 and above. The reason being is that Zend Opcache was added to the core product in PHP 5.5. Wherever possible, folks should be using the Zend Opcache,
and getting away from WinCache's opcode cache.
May 27, 2015 10:19 AM|davidgarcia|LINK
For anyone having problems with Zend Opcache on Windows, this is what it is all about:
I just wonder if there is any workaround for the ASLR issue on production environments that does work as the proposed ones in these issues simply reduce the probablity of the issue happening, but do not really prevent it.
May 28, 2015 03:48 PM|DropPhone|LINK
I just wonder if there is any workaround for the ASLR issue
Hm. WinCache definitely has the problem when subsequent processes aren't able to map the opcode cache segment at the same address as the php-cgi.exe instance that created the segment. In that case, WinCache detects the problem, and falls back to a "local"
opcode cache, scoped to the process instance. Sure, you wind up paying the re-compilation price, but at least it gets cached.
In recent builds I worked on improving the algorithm used to select the memory segment's base address. Before, it just used whatever address the first instance used, and was subject to the ASLR problem. Now, it goes to the top end of the virtual address
space and walks backwards until it finds a "big enough" spot for the segment. This strategy seemed to improve the rate at which we avoided falling back to a "local" opcode cache. I wasn't able to measure the improvement, however.
FYI, I sent the code I used to select a better base address to one of the PHP folks a few months ago. I don't know if they incorporated it into Zend Opcache or not.
May 28, 2015 08:46 PM|davidgarcia|LINK
This is not at all my field but... can both PHP and its extensions be compiled with ASLR disabled? Is it worth trying?
Previously you had to opt in to allowing the linker to use ASLR. Now, you have to opt out:
(Visual Studio 2012: Configuration Properties -> Linker -> Advanced -> "Randomized Base Address")
It looks like you can also disable ASLR system wide, not sure if that is a good idea at all...
May 29, 2015 06:28 PM|DropPhone|LINK
PHP links with system DLLs, which will still use ASLR. So, recompiling PHP without ASLR isn't really going to help you that much. You still run the risk of having some random allocation get dropped in a place that will prevent you from mapping a large
swath of memory.