php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81015 Opcache optimization assumes wrong part of ternary operator in if-condition
Submitted: 2021-05-06 04:14 UTC Modified: 2021-05-06 08:27 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: redwormik at gmail dot com Assigned:
Status: Closed Package: opcache
PHP Version: 8.0.5 OS: Alpine 3.13 (Docker)
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: redwormik at gmail dot com
New email:
PHP Version: OS:

 

 [2021-05-06 04:14 UTC] redwormik at gmail dot com
Description:
------------
I have opcache enabled and opcache.optimization_level at least 0x000000b0 (bits 4, 5 and 8 all set, other irrelevant).

When I compare a variable to NULL in a "false" part of a ternary operator in an if-condition, the variable changes to NULL in the respective branch of the if-condition (i.e. if comparison is === NULL, the variable changes to NULL in the if-branch; if comparison is !== NULL, the variable changes to NULL in the else-branch), even though the ternary operator condition is true.

Returning the value, changing the condition so it does not use ternary operator, moving the NULL-equality out of the condition to a local variable or comparing to anything else other than NULL all work as expected.

Test script:
---------------
<?php
declare(strict_types=1);

function ternary(bool $enabled, ?string $value): void
{
	// the "true" part is not as trivial in the real case
	if ($enabled ? true : $value === null) {
		echo ($value ?? 'NULL') . "\n";
	} else {
		echo "INVALID\n";
	}
}

ternary(true, 'value');
ternary(true, null);
ternary(false, 'value');
ternary(false, null);


Expected result:
----------------
value
NULL
INVALID value
NULL


Actual result:
--------------
NULL
NULL
INVALID value
NULL

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-05-06 04:17 UTC] redwormik at gmail dot com
Sorry, changed the output at last minute, but did not change the script. The condition should be (the else-branch output changed):

	if ($enabled ? true : $value === null) {
		echo ($value ?? 'NULL') . "\n";
	} else {
		echo "INVALID " . ($value ?? 'NULL') . "\n";
	}
 [2021-05-06 08:03 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2021-05-06 08:27 UTC] nikic@php.net
-Status: Verified +Status: Analyzed
 [2021-05-06 08:27 UTC] nikic@php.net
This happens due to an incorrect pi-node placement:

0000 #2.CV0($enabled) [bool] RANGE[0..1] = RECV 1
0001 #3.CV1($value) [null, string] = RECV 2
0002 JMPZ #2.CV0($enabled) [bool] RANGE[0..1] BB2

BB1:
     ; follow lines=[3-4]
     ; from=(BB0)
     ; to=(BB3)
     ; idom=BB0
     ; level=1
0003 #4.T2 [true] RANGE[1..1] = QM_ASSIGN bool(true)
0004 JMP BB3

BB2:
     ; target lines=[5-5]
     ; from=(BB0)
     ; to=(BB3)
     ; idom=BB0
     ; level=1
0005 #5.T2 [bool] = TYPE_CHECK (null) #3.CV1($value) [null, string]

BB3:
     ; follow target lines=[6-6]
     ; from=(BB1, BB2)
     ; to=(BB7, BB4)
     ; idom=BB0
     ; level=1
     ; children=(BB4, BB7)
     #6.X2 [bool] = Phi(#4.X2 [true] RANGE[1..1], #5.X2 [bool])
0006 JMPZ #6.T2 [bool] BB7

BB4:
     ; follow lines=[7-7]
     ; from=(BB3)
     ; to=(BB6, BB5)
     ; idom=BB3
     ; level=2
     ; children=(BB5, BB6)
     #7.CV1($value) [null] = Pi<BB3>(#3.CV1($value) [null, string] & TYPE [undef, ref, null])
0007 #8.T4 [] = COALESCE #7.CV1($value) [null] BB6

A pi node was placed in BB4 based on the JMPZ of TYPE_CHECK, but what that didn't account for is that this TYPE_CHECK is only one of the possible values of T2 at that point.
 [2021-05-06 08:48 UTC] git@php.net
Automatic comment on behalf of nikic
Revision: https://github.com/php/php-src/commit/178bbe3478a3aa6aeb6eeae62950d8a5203d794b
Log: Fixed bug #81015
 [2021-05-06 08:48 UTC] git@php.net
-Status: Analyzed +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 14:01:29 2024 UTC