Skip to content

JIT (tracing) return wrong float value after some times #18839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
marcimat opened this issue Jun 12, 2025 · 4 comments
Open

JIT (tracing) return wrong float value after some times #18839

marcimat opened this issue Jun 12, 2025 · 4 comments

Comments

@marcimat
Copy link

Description

In a (pretty old) PHP projet, is used a non-typed function moins (minus in french) with this simple following code:

<?php
function moins($a, $b) {
	return $a - $b;
}

We wanted to activate JIT (tracing) on PHP 8.4 (now with PHP 8.4.8), and after some unpredictable minutes or hours (depending of the website traffic ?) , the result of this function moins becomes wrong :

<?php
echo 'Moins:' . PHP_EOL;
echo moins(1, 1) . PHP_EOL;
echo moins(2, 1) . PHP_EOL;
echo moins(3, 1) . PHP_EOL;
echo PHP_EOL;

echo "with string:" . PHP_EOL;
echo moins('1', '1') . PHP_EOL;
echo moins('2', '1') . PHP_EOL;
echo moins('3', '1') . PHP_EOL;

Resulted in this output:

Moins:
0
4.9406564584125E-324
9.8813129168249E-324

with string:
0
4.9406564584125E-324
9.8813129168249E-324

But we expected this output instead:

Moins:
0
1
2

with string:
0
1
2

We didn’t test JIT before on previous PHP branches, so I don’t know if the result is the same on PHP 8.3 or before. This bug doesn’t appear without JIT enabled.

As you can see, some float with exponent is returned, and it seems related with floating point IEEE 754 64-bit binary format ; these numbers are the same as

<?php
(2 - 1)*2**-1074; // 4.9406564584125E-324
(3 - 1)*2**-1074; // 9.8813129168249E-324

And with all that, I was unable to reproduce that in CLI with JIT tracing on (we show that with FPM), nor in my local (DDEV) environment (and with different JIT configuration option).

The bug disapear (for some time) as soon as we reload that PHP version.

We show that at least on 2 different servers, with intel CPU

  • BIOS Model name: Intel(R) Xeon(R) E-2136 CPU @ 3.30GHz To Be Filled By O.E.M. CPU @ 3.3GHz
  • BIOS Model name: Intel(R) Xeon(R) E-2288G CPU @ 3.70GHz To Be Filled By O.E.M. CPU @ 3.7GHz

Opcache.jit* FPM configuration:

opcache.jit	tracing	tracing
opcache.jit_bisect_limit	0	0
opcache.jit_blacklist_root_trace	16	16
opcache.jit_blacklist_side_trace	8	8
opcache.jit_buffer_size	128M	128M
opcache.jit_debug	0	0
opcache.jit_hot_func	127	127
opcache.jit_hot_loop	64	64
opcache.jit_hot_return	8	8
opcache.jit_hot_side_exit	8	8
opcache.jit_max_exit_counters	8192	8192
opcache.jit_max_loop_unrolls	8	8
opcache.jit_max_polymorphic_calls	2	2
opcache.jit_max_recursive_calls	2	2
opcache.jit_max_recursive_returns	2	2
opcache.jit_max_root_traces	1024	1024
opcache.jit_max_side_traces	128	128
opcache.jit_max_trace_length	1024	1024
opcache.jit_prof_threshold	0.005

Is it something that talk to someone ?

Obviously, this moins function is used in a more complex context, in a web templating system notably, that function may also be call inside an eval() (I don’t know if that the cause of the problem) ; but for now I’m not able to reproduce a systematic small file code which trigger the bug, outside the full web project.

But from the moment the function bugs, it bugs in whatever script the function is called (that includes the file with the function declaration).

One example tried among other in CLI to reproduce vainly

php8.4 -d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.jit=tracing -d opcache.jit_buffer_size=1G -d opcache.jit_max_root_traces=1000000 -d opcache.jit_max_side_traces=1000000 -d opcache.jit_max_exit_counters=1000000 -d opcache.jit_hot_loop=0 -d opcache.jit_hot_func=0 -d opcache.jit_hot_return=0 -d opcache.jit_hot_side_exit=0 -d memory_limit=-1 test.php 
  • Is there some open or closed bugs with JIT that are similar to that ?

Note: I’m not so familiar with php-src, please apologize if I’m not write things the rigth way.

PHP Version

php-fpm8.4 -v
PHP 8.4.8 (fpm-fcgi) (built: Jun  9 2025 13:42:27) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.8, Copyright (c), by Zend Technologies

php8.4 -v
PHP 8.4.8 (cli) (built: Jun  9 2025 13:42:27) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.8, Copyright (c), by Zend Technologies

Operating System

Debian GNU/Linux 12 (bookworm)

@SakiTakamachi
Copy link
Member

This is most likely an issue caused by the combination of FPM and JIT.

Since the problem doesn’t occur when JIT is disabled, it’s likely that the JIT optimization process is conflicting across multiple processes, resulting in corrupted JIT-compiled code.

Would it be possible to try using JIT in function mode instead of tracing?
The tracing mode performs more complex optimizations, which makes it more prone to issues like code corruption compared to function mode.

@marcimat
Copy link
Author

Would it be possible to try using JIT in function mode instead of tracing?

Ok. The jit config is now in function mode. We will see.

@dstogov
Copy link
Member

dstogov commented Jun 16, 2025

I can't reproduce the problem.
I suppose the bug is triggered by usage of moins() in some specific context/trace, but I can't guess this.
Function JIT should work, but this won't fix the existing bug.

I would recommend to try the same script/app with PHP debug build (even better ASAN build) and with opcache.protect_memory=1. May be this will show some assertions.

@marcimat
Copy link
Author

Ok. The jit config is now in function mode. We will see.

Indeed, the problem seems not reappear with opcache.jit = function

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

No branches or pull requests

3 participants