Skip to content

JIT appears not to correctly account for property references in some cases #19831

Closed

Description

@dktapps

Description

I don't yet have an exact reproducing test case yet, but I believe I have a rough idea what the problem is.

Taking this class as an example:

Here, the layers field may be modified by-reference if a RuntimeDataReader was passed, turning the layers field into a reference.
https://github.com/pmmp/PocketMine-MP/blob/636b96a9a5c35292f076e2f2e9c5723611d28d7b/src/block/SnowLayer.php#L50

Here, the layers field is sometimes apparently larger than MAX_LAYERS (8), despite a var_dump clearly showing that the actual value is 1. I suspect in this case, the JIT isn't accounting for the possibility that layers may be IS_REFERENCE instead of IS_LONG, and is directly comparing the zend_reference* pointer to the int on the right. https://github.com/pmmp/PocketMine-MP/blob/636b96a9a5c35292f076e2f2e9c5723611d28d7b/src/block/SnowLayer.php#L64-L66

Here, the right side of the assign operator may be IS_REFERENCE. Again, JIT does not account for this, so the left side gets assigned some extremely large number. I'm pretty sure these very large numbers are pointers to IS_REFERENCE due to the misinterpretation of the field. E.g. one of the strange numbers I saw was 140367337677697, which is a multiple of 8 plus 1, which tracks with the expected pointer alignment on x86_64.
https://github.com/pmmp/PocketMine-MP/blob/636b96a9a5c35292f076e2f2e9c5723611d28d7b/src/block/SnowLayer.php#L89

It also appears that in some cases properties which are references are overwritten instead of updating the reference. I haven't been able to cleanly reproduce this.

As I said above, I don't currently have a reproducing test case for this. The bug has proven to be very elusive, and my efforts to recreate the issue in a local test case have thus far been unsuccessful. However, I believe I understand just enough of the PHP internals to make an educated guess what's going on.

JIT modes 1201 and 1202 did not reproduce the issue, but modes 1203, 1204 and 1205 do.

PHP Version

PHP 8.4.12 (cli) (built: Sep 13 2025 18:40:04) (ZTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.4.12, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.12, Copyright (c), by Zend Technologies

Operating System

Ubuntu 20.04 & Windows 11

Activity

  1. dktapps commented on Sep 13, 2025

    @dktapps
    ContributorAuthor

    Partial reproducing test case follows. Note that the Test class must be declared in a separate file, or this particular bug doesn't happen.

    main.php

    <?php
    
    final class RuntimeDataSizeCalculator{
    
    	private int $bits = 0;
    
    	protected function addBits(int $bits) : void{
    		$this->bits += $bits;
    	}
    
    	public function boundedIntAuto(int $min, int $max, int &$value) : void{
    		$this->addBits(((int) log($max - $min, 2)) + 1);
    	}
    }
    
    class Base{
    	public function __construct(){
    		$calculator = new RuntimeDataSizeCalculator();
    		$this->describeBlockOnlyState($calculator);
    	}
    
    	protected function describeBlockOnlyState(RuntimeDataSizeCalculator $w) : void{
    
    	}
    }
    
    require __DIR__ . '/test.php';
    
    $t = new Test();
    var_dump($t->getLayers());

    test.php

    <?php
    
    declare(strict_types=1);
    
    class Test extends Base{
    	public const MIN_LAYERS = 1;
    	public const MAX_LAYERS = 8;
    
    	protected int $layers = self::MIN_LAYERS;
    
    	protected function describeBlockOnlyState(RuntimeDataSizeCalculator $w) : void{
    		var_dump("wassup");
    		$w->boundedIntAuto(self::MIN_LAYERS, self::MAX_LAYERS, $this->layers);
    	}
    
    	public function getLayers() : int{
    		return $this->layers;
    	}
    }

    Outputs something like:

    string(6) "wassup"
    int(2363633267936)
    

    but should output

    string(6) "wassup"
    int(1)
    
  2. changed the title [-]JIT appears not to correctly account for possible references in math operations in some cases (no reproducing test case)[/-] [+]JIT appears not to correctly account for property references in some cases[/+] on Sep 13, 2025
  3. self-assigned this
    on Sep 15, 2025
  4. arnaud-lb commented on Sep 15, 2025

    @arnaud-lb
    Member

    Smaller reproducer:

    if (time() > 0) {
        class Base {
        }
    }
    
    class Test extends Base {
    	public int $layers = 1;
    
    	public function getLayers(): int {
    		return $this->layers;
    	}
    }
    
    $t = new Test();
    $a = &$t->layers;
    var_dump($t->getLayers());
  5. added a commit that references this issue on Sep 22, 2025
    32c919b
  6. arnaud-lb commented on Sep 22, 2025

    @arnaud-lb
    Member

    Thank you @dktapps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions