php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #59872 APC conditional function definitions in included files leads to invalid jumps
Submitted: 2011-07-26 10:02 UTC Modified: 2016-11-18 21:38 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: phpbugs at colin dot guthr dot ie Assigned:
Status: Wont fix Package: APC (PECL)
PHP Version: 5.3.6 OS: Linux (Mageia x86_64)
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2011-07-26 10:02 UTC] phpbugs at colin dot guthr dot ie
Description:
------------
Hi,

This is a self confessed weak bug report as although I can reproduce the problem reliably, I cannot come up with a reliable test condition that exhibits this problem, but from poking around at it a lot, I *think* I've got a rough explanation.

Now, I don't know the internals of APC very well, so the term "jump point" may not be valid and thus throws the whole of this report into doubt, but I'll try my best with the description and see if those cleverer than myself can clarify.

What seems to happen in this case relates to variable scope, a require() statement (no require_once) and a conditional function definition inside that required file (it's conditional to work around the fact that the file is require()'ed rather than require_once()'ed).

When this happens, it seems that the code being executed is not correct. It seems to that when the conditional function is called, the bit of code that is in that file after the function definition is also executed.




Reproduce code:
---------------
I'll demonstrate the layout here (although this code does not exhibit the problem on it's own):

File1 (index.php):

<?php

class apcParams
{
  function def($name, $value)
  {
    $this->$name = $value;
  }

  function get($name)
  {
    return $this->$name;
  }
}

class apcBug
{
  public static function myInclude($file)
  {
    $params = new apcParams();
    $params->def('Something', 'Wicked');
    $params->def('ThisWay', 'Comes');
    require($file);
  }

  public static function doCallback(&$params, $callback)
  {
    $callback($params);
  }
}

apcBug::myInclude(dirname(__FILE__).'/includee.php');

?>


File2 (includee.php):

<?php

if (!defined('apcFuncDefined'))
{

  function apcFunc(&$params)
  {
    echo "In callback: ".$params->get('Something')."<br>";
  }

  define('apcFuncDefined', true);
}

apcBug::doCallback($params, 'apcFunc');

?>

Expected result:
----------------
Here, the index.php file require()'s the includee.php file. When it calls require() a variable ($params) is in the scope. This variable is used inside includee.php.

It ultimately prints out "In callback: Wicked".


Actual result:
--------------
The problem I experience with a much more convoluted code base is that there are occasions when $params variable is simply not set inside the file. This initially made me believe that there was some kind of scoping problem inside APC relating to "require" calls or similar, but with further investigation I do not think this is actually the case.

The reason I do not think it is a scoping problem relates to the use of a work around I put in place. Rather than set a local variable, I instead set a GLOBAL (actually I used more of a registry model, but the principle is the same). When this happened, I ended up with infinite recursion (900 calls at least on the stack!).

As there was definitely no recursion actually written in the code, this seemed to indicate that the line in includee.php that calls apcBug::doCallback() was simply being called whenever the callback function was being called.... this in turn led to the recursion.  Obviously, this should not be the case and the fact that that code was being run was an error. I think it is this that is the fundamental problem here. I think that there must be some kind of error in the "entry point" into that required file due to the conditional definition and rather than calling the callback, it is just landing and executing the static code.


If I replace the conditional function definition with a require_once and put the function in a separate file, it appears to work around the problem (can't say for certain but I have not been able to reproduce it yet) which gives further credence to the above hypothesis.

I am on x86_64 but have had seen the same symptoms on i586 boxes too.

It is an intermittent issue even when it does occur but with our codebase I can generally reproduce it in a few clicks.

I appreciate that without a good reproduction case, this may be a very tricky bug to nail down, but I live in hope that this description will be sufficient to maybe spark a few thoughts.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-08-06 22:00 UTC] gopalv@php.net
It looks like a case of inclusion checks failing - does your scenario look like 

http://notmysock.org/blog/php/inclusion-checks.html

?
 [2011-08-07 06:27 UTC] phpbugs at colin dot guthr dot ie
@gopalv It looks very similar from reading that article yes.

We actually deployed the latest APC (3.1.9) to a live environment and it *really* didn't like it. We promptly downgraded to 3.0.19 which behaves much better.

I can't be 100% certain that this issue was the primary problem but a known breakage in Joomla (1.5.x) was patched by me in our deployment and that site worked fine again. Sadly some Drupal sites also on that server were totally borked, hence the downgrade.

Hopefully this fundamental problem can be fixed in APC as I don't think I can realistically carry on using it when such serious problems with real world apps :(

If there is anything I can do to help, please do let me know. Sadly my test environment doesn't exhibit the major Drupal problems.... gotta love inconsistent failings :(
 [2016-11-18 21:38 UTC] kalle@php.net
-Status: Open +Status: Wont fix
 [2016-11-18 21:38 UTC] kalle@php.net
APC is no longer supported in favor of opcache that comes bundled with PHP, if you wish to use the user cache, then look at PECL/APCu.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 09:01:28 2024 UTC