php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #56776 Mixing early and late binding
Submitted: 2006-01-16 22:43 UTC Modified: 2009-03-18 14:06 UTC
From: t dot starling at physics dot unimelb dot edu dot au Assigned:
Status: Closed Package: APC (PECL)
PHP Version: 5.1.1 OS: Fedora Core 3
Private report: No CVE-ID: None
 [2006-01-16 22:43 UTC] t dot starling at physics dot unimelb dot edu dot au
Description:
------------
I don't usually report bugs unless I've narrowed it down to a simple test case, but unfortunately we've been unable to do so with this one. The problem is cache corruption on *.wikipedia.org. Symptoms are:

* Missing parent classes

PHP Fatal error:  Call to undefined method LanguageCs::initEncoding() in /usr/local/apache/common-local/php-1.5/includes/Setup.php on line 185

where initEncoding is a member of the parent class. This happened whether the parent class was defined early or late. get_parent_class() returned false or "" (not sure which) and get_class_methods() returned the methods of the derived class only, missing the inherited methods.

* Corrupted function invocation

PHP Fatal error:  Call to undefined function ^A() in /usr/local/apache/common-local/live-1.5/thumb.php on line 3

So far we've observed this consistently in servers under load, but I've been unable to reproduce it in a controlled environment. If an APC developer would like to take a closer look at our cluster in order to track down this bug further, please contact me.

-- Tim Starling

Reproduce code:
---------------
http://cvs.sourceforge.net/viewcvs.py/wikipedia/phase3/


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-01-17 09:36 UTC] florian at lorifan dot homeip dot net
Hi, 

your problem seems to be a general problem of apc when classes extends other classes and taughter classes include_once other files. A lot of boards on the net descripe this problem. Some days ago I've also searched for this sympthoms and a possible solution. I have found a hint to include the missing file a second time. 
Here http://pecl.php.net/bugs/bug.php?id=5401 is a concrete scenario. 

Let's hope this problem will be solved :-)
 [2006-01-17 12:08 UTC] t dot starling at physics dot unimelb dot edu dot au
Thanks for the link, I'll try upgrading to CVS HEAD.
 [2006-01-17 12:17 UTC] rasmus@php.net
If it is the early-binding vs. late-binding problem you are hitting, CVS HEAD won't fix it.  The fix for this is extremely complicated.  We are working on it, but even when we fix it you are better off fixing your code to not switch back and forth between early and late binding on the same files.
 [2006-01-17 19:43 UTC] brion at pobox dot com
The problem seems to be triggered with our dynamically-loaded 
modules that can inherit from other modules (mainly 
localization and layout skins). This seems to fit with the 
early/late binding thing if I understand it correctly.

I've added in a stub to preload the extra dependencies for 
those classes that need it; hopefully that'll clear this up.

http://mail.wikipedia.org/pipermail/wikitech-l/2006-January/
033660.html
 [2006-01-18 01:55 UTC] t dot starling at physics dot unimelb dot edu dot au
Brion's change seems to have stopped the missing parent class errors, so I'll change the report title if I can, to reflect this diagnosis. The corrupted function invocations seemed to stop after we upgraded to the CVS version of APC, so we'll call that part of the report a duplicate of 5401.
 [2006-01-18 02:16 UTC] rasmus@php.net
Be careful here though.  If it is early vs. late binding issues, then the first request after a server restart sets the tone for the remaining requests until you either restart or change one of the files in question.

The reason being that if the first request which triggers the cache insert of a particular file is a conditional include which pushes the class definition into the executor, then the cached opcodes will include the FETCH_CLASS call and you will always be doing late binding.  This is slow, but will always work.  If, on the other hand, the first request is a non-conditional top-level include then the early binding optimization kicks in and the cached opcode array won't include the FETCH_CLASS which means that a later conditional include on that same file will then exhibit the problem.

That's what I mean about cleaning up your code to either always do early or late binding, but don't mix them on the same file.  The easiest way to do this is to always put your includes at the very top level and never use include_once/require_once.  Not only do the _once calls lead to this confusion, they are also tremendously slow under an opcode cache because of the way they are implemented with a non-opcode-cached environment in mind.
 [2006-01-18 06:34 UTC] t dot starling at physics dot unimelb dot edu dot au
Thanks for the advice. I had noticed the slowness of require_once/include_once (see http://wikitech.leuksman.com/view/Slow_require_once ), in fact I spent some time studying the APC and PHP source to see if there was an obvious way to fix it. I saw that the REQUIRE opcode called compile_filename() instead of zend_compile_file() and mistakenly assumed it didn't pass through APC at all. Obviously it does, and it does so without opening the file, what's more. So that seems like a good way to proceed.

Would it be possible to convert an early bound class declaration to a late binding one at the time when the class is restored? Presumably the NOP is still there, could you just change it back to a FETCH_CLASS if the parent does not exist? I know it's a hack but that seems to be the name of the game. Alternatively you could change the bytecode specification to give some reasonably version-independent and stable way to switch between early and late binding.
 [2006-01-18 11:03 UTC] rasmus@php.net
Actually, the way I tried to fix it was to have APC maintain an inheritance tree meaning that as it loads the op_arrays it detects child classes and if the parent is missing it adds a parent->child element to an array.  Then for each new class it sees it checks to see if it is in the array as a parent and if so does the parent->child inheritance which essentially means copying methods down into the child.  Where this gets nasty is when you have multi-level inheritance where you have A->B->C and you load C, then B but since A hasn't been seen yet you can't do the b->c inheritance yet.  Might first patch for this just did a 1-level thing and actually fixed most of these, but having it half-baked like this is obviously not the way to go.  My multi-level fix still has some problems I haven't been able to figure out yet.  You can see the code for this on the branch called "INH_FIX" in CVS.  I haven't had much time lately to devote to this.
 [2006-07-27 11:23 UTC] gopalv82 at yahoo dot com
Fixed in CVS HEAD for php 5.1.x.

The classes which mix dynamic and static binding are detected and the opcodes from those files are not cached. 

Introduced apc.report_autofilter to report the auto-filtering  of such errant classes. Also the reports can be used to pinpoint classes which are runtime binding and probably can be modified to be compile-time binding for optimal performance.
 [2006-07-27 11:24 UTC] gopalv82 at yahoo dot com
Just noticed the other corruption errors. Please re-test current CVS head and confirm whether the recent race condition fixes have done anything for it.
 [2009-03-18 14:06 UTC] shire@php.net
Sounds like this one is fixed, closing....
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Sep 18 13:01:52 2019 UTC