|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76281 Opcache causes incorrect "undefined variable" errors
Submitted: 2018-04-27 19:27 UTC Modified: 2018-04-27 20:02 UTC
From: woody dot gilk at gmail dot com Assigned:
Status: Closed Package: opcache
PHP Version: 7.2.5 OS: Linux
Private report: No CVE-ID: None
 [2018-04-27 19:27 UTC] woody dot gilk at gmail dot com
% php --version
PHP (cli) (built: Apr  5 2018 08:53:57) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache, Copyright (c) 1999-2018, by Zend Technologies

PHP 7.2.5 is not yet available for my distro.

The bug does NOT appear on PHP 7.1.16.

When running the test script (part of a larger class) the following error always occurs:

E_NOTICE: Undefined variable: user_sub_resource on line 37

For obvious reasons, this is an impossible situation because the variable is defined and can only be a boolean.

When I disable opcache the problem disappears and everything works correctly.

Test script:
$user_sub_resource = in_array($action, array('get_securityquestions', 'get_status', 'get_groupstats'));

$user_id = null;
if ($user_sub_resource && isset($r['user_id'])) { // !! NO ERROR HERE !!
    $user_id = $r['user_id'];
else if (isset($r['id']))  {
    $user_id = $r['id'];

if ($user_sub_resource) { // !! ERROR HAPPENS HERE !!
    if ($action === 'get_securityquestions' && !$this->isRequestor($r['user_id'])) {
        $this->violation('can\'t get another user\'s security information');

    return $perms;


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2018-04-27 19:35 UTC] woody dot gilk at gmail dot com
One additional comment to add:

When I change the if() conditions to:

$user_sub_resource === true

for each reference to $user_sub_resource then the error goes away.

The problem also goes away if I change the line AFTER the problem to:

if ($action === 'get_securityquestions' && !$this->isRequestor($user_id))

Though I have absolutely no idea why that is the case.
 [2018-04-27 19:54 UTC]
-Status: Open +Status: Verified
 [2018-04-27 19:54 UTC]
I can reproduce with the following code:

<?php error_reporting(E_ALL);

function test($r, $action) {
    $user_sub_resource = in_array($action, array('get_securityquestions', 'get_status', 'get_groupstats'));

    $user_id = null;
    if ($user_sub_resource && isset($r['user_id'])) {
        $user_id = $r['user_id'];
    else if (isset($r['id']))  {
        $user_id = $r['id'];

    if ($user_sub_resource) {
        return 'foo';

    return 'bar';

var_dump(test(['user_id' => 1, 'id' => 2], 'foo'));
 [2018-04-27 20:02 UTC]
-Status: Verified +Status: Analyzed
 [2018-04-27 20:02 UTC]
In the DFA pass we end up going from

            #6.T4 [bool] = IN_ARRAY 0 #5.CV1($action) [any] array(...)
            ASSIGN #2.CV2($user_sub_resource) NOVAL [undef] -> #7.CV2($user_sub_resource) [bool] #6.T4 [bool]
            JMPZ #7.CV2($user_sub_resource) [bool] BB3


            #7.CV2($user_sub_resource) [bool] = IN_ARRAY 0 #5.CV1($action) [any] array(...)
            JMPZ #7.CV2($user_sub_resource) [bool] BB3

which drops the NOP necessary for smart branch inhibition.

The issue seems to be that the NOP elimination only checks for the pattern smart-branch-op NOP JMPZ/NZ, however in this case there will be two NOPs between the IN_ARRAY and the JMPZ, which is not detected as a smart branch.
 [2018-04-27 20:27 UTC]
Automatic comment on behalf of
Log: Fix bug #76281
 [2018-04-27 20:27 UTC]
-Status: Analyzed +Status: Closed
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon May 27 23:01:30 2024 UTC