php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80404 Incorrect range inference result when division results in float
Submitted: 2020-11-23 10:06 UTC Modified: 2020-11-24 09:25 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: contact at shivammathur dot com Assigned:
Status: Closed Package: opcache
PHP Version: 8.0Git-2020-11-23 (Git) OS: Tested on Ubuntu 18.04
Private report: No CVE-ID: None
 [2020-11-23 10:06 UTC] contact at shivammathur dot com
Description:
------------
PHP 8.0.0-dev (cli) (built: Nov 23 2020 00:27:07) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.0-dev, Copyright (c), by Zend Technologies

Build Configuration: https://github.com/shivammathur/php-builder/blob/master/.github/scripts/8.0

Script: https://3v4l.org/kkRIE
  curl -o test.php -H Accept:text/plain -sL https://3v4l.org/kkRIE
  for ((i=1;i<=5;i++)); 
  do 
     echo $i
     php test.php
     sleep 1
  done

Above snippet will run the script "https://3v4l.org/kkRIE" multiple times and when opcache kicks in "(int) (63/ 120 * 100)" starts evaluating to 0.

This works fine with opcache disabled on PHP 8.0 and with or without opcache on PHP 7.4

Test workflow - https://github.com/shivammathur/test-setup-php/runs/1441325553?check_suite_focus=true#step:6:33



Test script:
---------------
<?php

$firstRowColumns  = 63;

var_dump([
    $firstRowColumns,
    ($firstRowColumns / 120),
    ($firstRowColumns / 120 * 100),
    (int) ($firstRowColumns / 120 * 100),
]);

Expected result:
----------------
(int) (63/ 120 * 100) should evaluate to 52 with opcache enabled on PHP 8.0

Actual result:
--------------
(int) (63/ 120 * 100) evaluates to 0 with opcache enabled on PHP 8.0

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-11-23 11:53 UTC] cmb@php.net
-Package: Math related +Package: JIT
 [2020-11-23 11:53 UTC] cmb@php.net
This looks like a JIT issue.
 [2020-11-23 11:59 UTC] contact at shivammathur dot com
@cmb

Can be reproduced with opcache.jit=off, so I'm not sure if this is JIT related.
Jit Status - https://github.com/shivammathur/test-setup-php/runs/1441867898?check_suite_focus=true#step:5:67
Test - https://github.com/shivammathur/test-setup-php/runs/1441867898?check_suite_focus=true#step:6:33
 [2020-11-23 14:12 UTC] cmb@php.net
-Package: JIT +Package: opcache
 [2020-11-23 14:12 UTC] cmb@php.net
Ah, thanks!
 [2020-11-24 09:20 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2020-11-24 09:20 UTC] nikic@php.net
0000 ASSIGN #0.CV0($firstRowColumns) [undef, ref, any] -> #1.CV0($firstRowColumns) [ref, any] RANGE[63..63] int(63)
0001 INIT_FCALL 1 96 string("var_dump")
0002 #2.T1 [false, long, double, object] RANGE[0..0] = DIV #1.CV0($firstRowColumns) [ref, any] RANGE[63..63] int(120)
0003 #3.T2 [false, long, double, object] RANGE[0..0] = MUL #2.T1 [false, long, double, object] RANGE[0..0] int(100)
0004 #4.T1 [long] RANGE[0..0] = CAST (long) #3.T2 [false, long, double, object] RANGE[0..0]
0005 SEND_VAL #4.T1 [long] RANGE[0..0] 1
0006 DO_ICALL
0007 RETURN int(1)

Interesting issue. We determine that ($firstRowColumns / 120) has value range 0..0 and thus that ($firstRowColumns / 120) * 100 stays zero.

We probably shouldn't be rounding down the division. While that's the behavior of integer divisions, it does not accurately model PHP's fallback to float division.
 [2020-11-24 09:25 UTC] nikic@php.net
-Summary: opcache breaks expression evaluation order when cast as int +Summary: Incorrect range inference result when division results in float
 [2020-11-24 10:38 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=03f8bccaf545817237ee5b92a0cad6aefbe4e603
Log: Fixed bug #80404
 [2020-11-24 10:38 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Wed Jan 20 14:01:23 2021 UTC