php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77310 Variable values incorrect when Opcache enabled
Submitted: 2018-12-17 15:05 UTC Modified: 2019-05-09 08:59 UTC
Votes:81
Avg. Score:4.7 ± 0.6
Reproduced:55 of 64 (85.9%)
Same Version:55 (100.0%)
Same OS:42 (76.4%)
From: taylor at laravel dot com Assigned: nikic (profile)
Status: Closed Package: opcache
PHP Version: 7.3.0 OS: Multiple
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: taylor at laravel dot com
New email:
PHP Version: OS:

 

 [2018-12-17 15:05 UTC] taylor at laravel dot com
Description:
------------
We received multiple bug reports to the Laravel framework Git issue tracker and I was able to confirm the following bug on my own machine as well. GitHub thread is here: https://github.com/laravel/framework/issues/26819

Laravel's dependency injection container uses Closures to resolve objects. We are encountering a bug in the following section of code: https://gist.github.com/taylorotwell/2a0934fcd5bb59e74640c9e451e69ec4

A $mailer instance is created on line 6... However, we when we interact with the mailer on line 11, PHP throws an error that the `setQueue` method does not exist on the Container object (which is the `$app` variable). It appears PHP thinks the `$mailer` variable is the `$app` variable.

I am able to resolve the error by disabling Opcache entirely. With Opcache enabled, I will get the error fairly frequently, although it does seem to sometimes resolve itself. It will always reappear if I restart PHP-FPM and Opcache is enabled.

I'm not sure of the best way to create a small, re-producable example of the bug. However, it seems to be affecting many users and be entirely Opcache related.

Expected result:
----------------
PHP should call the `setQueue` method on the `$mailer` variable which is an instance of Mailer.

Actual result:
--------------
PHP calls the `setQueue` method on the value of the `$app` variable.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-12-17 15:08 UTC] taylor at laravel dot com
Wanted to add this has been seen on Ubuntu and Mac.
 [2018-12-17 16:50 UTC] taylor at laravel dot com
We have temporarily worked around this by referencing `$this->app` within the Closure which is set to the same value that `$app` was previously.

So, Laravel >= 5.7.18 should not be affected by this; however, I am worried the bug could affect other areas of code we haven't discovered yet.
 [2018-12-17 16:59 UTC] nikic@php.net
Off-topic comment by spam2 at rhsoft dot net deleted.
 [2018-12-20 11:57 UTC] taylor at laravel dot com
Might be duplicate / similar issue as: https://bugs.php.net/bug.php?id=77275
 [2018-12-20 15:13 UTC] cmb@php.net
Can you please check with the fix for that bug[1] applied? Instead
of applying the fix yourself, you can also test with PHP
7.3.1RC1[2] (announcement including hashes and signatures will
follow shortly).

Anyhow, this issue might also be related to bug #76937.

[1] <http://git.php.net/?p=php-src.git;a=commit;h=93aabf1533bd3af673bb59cf283e6599ced3ab9a>
[2] <http://downloads.php.net/~cmb/>
 [2019-01-07 02:44 UTC] syntax53 at gmail dot com
I believe a problem I just ran across is related / same as this.  This is with PHP 7.3 nts x64 (I tried 7.3.1RC1 and same problem) on Windows 2016.

---[begin]
<?php
$data[0][0] = 'zero';
$data[0][1] = 0;
$data[1][0] = 'one';
$data[1][1] = 1;
$data[2][0] = 'two';
$data[2][1] = 2;

function breakit($op,$table,$data_arr,$qual="") {
	switch ($op) {
		case "go":
			$foo[0] = "";
			$foo[1] = "";
			$bar[0] = "";
			$bar[1] = "";
			for($i = 0; $i < count($data_arr); $i++)
			{
				if ($foo[0] != "") { $foo[0]=$foo[0].","; $foo[1]=$foo[1].","; }
				if ($bar[0] != "") { $bar[0]=$bar[0].","; $bar[1]=$bar[1].","; }
				
				$field = "`".$data_arr[$i][0]."`";
				$val = "'".$data_arr[$i][1]."'";

				$foo[0] .= $field;
				$foo[1] .= $val;
				$bar[0] = $bar[0].$field;
				$bar[1] = $bar[1].$val;
			}
			echo "foo[0]: ".$foo[0]."<br>";
			echo "foo[1]: ".$foo[1]."<br>";
			echo "bar[0]: ".$bar[0]."<br>";
			echo "bar[1]: ".$bar[1]."<br>";
			
			break;
	}
}

breakit('go','table',$data);
?>
---[end]

output--

foo[0]:
foo[1]:
bar[0]: `zero`,`one`,`two`
bar[1]: '0','1','2' (edited) 

... with opcache enabled the string concatenation of "var .= value" produces an empty string.  But using "var = var . value" works fine.  Disable opcache and output of foo and bar is identical.
 [2019-01-07 03:03 UTC] titansoftime at gmail dot com
I to have experienced this bug. Happens every time after first page load. Totally broke my games stat system. 

Code works ok on first attempt after ftp upload, get 0's every time afterwards.

OpCache for php 7.2.13 has no issue, only php 7.3 has the issue. Disabling opcache solves the problem. Using Ubuntu 18.

Test code:

class itest{
	
	function make_user_stats():array{
		
		$stats = array(
			'strength'  => 0,
			'stamina'   => 0,
			'intellect' => 0,
			'spirit'    => 0,
			'agility'   => 0,
			'armor'     => 0,
			'resist'    => 0
		);	
		
		$item_stats = array(
			'stam_x'     => 0,
			'str_x'      => 0,
			'int_x'      => 0,
			'agi_x'      => 0,
			'spirit_x'   => 0,
			'armor_inc'  => 0,
			'resist_inc' => 0
		);	
		
		$count = count($rows = array(
			array(
				'intellect' => 100,
				'stamina' => 200,
				'strength' => 30,
				'spirit' => 300,
				'agility' => 500,
				'resist' => 5,
				'armor' => 5,
			),
			array(
				'intellect' => 200,
				'stamina' => 300,
				'strength' => 330,
				'spirit' => 40,
				'agility' => 100,
				'resist' => 10,
				'armor' => 5,
			),
			array(
				'intellect' => 250,
				'stamina' => 120,
				'strength' => 330,
				'spirit' => 30,
				'agility' => 5,
				'resist' => 10,
				'armor' => 10,
			),				
		));
		
		foreach( $rows as $row ){
			
			$item_stats['stam_x']      += $row['stamina'];
			$item_stats['str_x']      += $row['strength'];
			$item_stats['int_x']      += $row['intellect'];
			$item_stats['agi_x']      += $row['agility'];
			$item_stats['spirit_x']   += $row['spirit'];
			$item_stats['armor_inc']  += $row['armor'];
			$item_stats['resist_inc'] += $row['resist'];
			
			//var_dump($item_stats);
			
		}
		
		$stats['stamina']   += ceil( ($stats['stamina']   * ($item_stats['stam_x']/100)) )   + $item_stats['stam_x'];
		$stats['intellect'] += ceil( ($stats['intellect'] * ($item_stats['int_x']/100)) )    + $item_stats['int_x'];
		$stats['strength']  += ceil( ($stats['strength']  * ($item_stats['str_x']/100)) )    + $item_stats['str_x'];
		$stats['agility']   += ceil( ($stats['agility']   * ($item_stats['agi_x']/100)) )    + $item_stats['agi_x'];
		$stats['spirit']    += ceil( ($stats['spirit']    * ($item_stats['spirit_x']/100)) ) + $item_stats['spirit_x'];	
		
		$stats['armor']    += $item_stats['armor_inc'];	
		$stats['resist']    += $item_stats['resist_inc'];		
		
		return $stats;
		
	}
	
}

$itest = new itest;

$stats = $itest->make_user_stats();

var_dump($stats);
 [2019-01-07 08:21 UTC] nikic@php.net
@syntax53: That looks like bug #77257 to me, based on the involvement of switch. I can't reproduce this issue on current 7.3 tip.

@titansoftime: Can't reproduce that on on current 7.3 tip either, though not sure which bug would have fixed that one.
 [2019-01-07 08:27 UTC] nikic@php.net
@syntax53 @titansoftime Ooops, nevermind what I just said, I tested the wrong PHP build. Both of your test cases still reproduce on current 7.3. I will take a look.
 [2019-01-07 09:08 UTC] nikic@php.net
@titansoftime And yours as well :) Turned out to be the same problem.
 [2019-01-07 15:04 UTC] syntax53 at gmail dot com
@nikic -- thanks!  How can we track to see when this has been included in an Release/Candidate?
 [2019-01-07 23:10 UTC] cmb@php.net
> How can we track to see when this has been included in an
> Release/Candidate?

Ideally, you'd had filed a separate ticket – if it had been the
same root cause, that would have been closed as duplicate.
Otherwise it would have gotten its own NEWS/Changelog entry.

Anyhow, the fix should be in 7.3.2RC1, scheduled for Jan. 24th.
 [2019-01-08 12:17 UTC] syntax53 at gmail dot com
@cmb -- Sorry, as I was going to submit the ticket I saw all the warnings against submitting duplicates and this one had seemed very plausible that it could have been the same root cause.
 [2019-05-09 08:59 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2019-05-09 08:59 UTC] nikic@php.net
I believe this has been fixed by one of the opcache fixes in an early 7.3 release, though I don't remember which one exactly it was. Please correct me if I'm wrong :)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 20:01:29 2024 UTC