Bug #81015 [Ana->Csd]: Opcache optimization assumes wrong part of ternary operator in if-condition

From: Date: Thu, 06 May 2021 08:48:00 +0000
Subject: Bug #81015 [Ana->Csd]: Opcache optimization assumes wrong part of ternary operator in if-condition
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-233715@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81015&edit=1 ID: 81015 Updated by: git@php.net Reported by: redwormik at gmail dot com Summary: Opcache optimization assumes wrong part of ternary operator in if-condition -Status: Analyzed +Status: Closed Type: Bug Package: opcache Operating System: Alpine 3.13 (Docker) PHP Version: 8.0.5 Block user comment: N Private report: N New Comment: Automatic comment on behalf of nikic Revision: https://github.com/php/php-src/commit/178bbe3478a3aa6aeb6eeae62950d8a5203d794b Log: Fixed bug #81015 Previous Comments: ------------------------------------------------------------------------ [2021-05-06 08:27:17] 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 04:17:55] 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 04:14:41] 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 ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=81015&edit=1

« previous php.bugs (#233715) next »