php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81226 Integer overflow behavior is different with JIT enabled
Submitted: 2021-07-06 00:39 UTC Modified: 2021-07-21 12:20 UTC
From: smokey101stair at gmail dot com Assigned: dmitry (profile)
Status: Closed Package: JIT
PHP Version: 8.0.8 OS: Ubuntu 20.04
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 this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: smokey101stair at gmail dot com
New email:
PHP Version: OS:

 

 [2021-07-06 00:39 UTC] smokey101stair at gmail dot com
Description:
------------
When $characterReferenceCode overflows in the test script with the JIT enabled, sometimes it evaluates to 65 and other times it evaluates to 1.844674407371E+19. The expected value is 1.844674407371E+19.

With opcache.jit_debug=1 I get the following:

TRACE-1$/home/trevor/jit_test2.php$9: ; (unknown)
        mov $EG(jit_trace_num), %rax
        mov $0x1, (%rax)
        mov $EG(vm_stack_end), %rax
        mov (%rax), %rcx
        mov $EG(vm_stack_top), %rax
        sub (%rax), %rcx
        cmp $0x60, %rcx
        jb jit$$trace_exit_0
.L1:
        cmp $0x4, 0x88(%r14)
        jnz jit$$trace_exit_1
        cmp $0x4, 0x98(%r14)
        jnz jit$$trace_exit_1
        mov 0x80(%r14), %rax
        cmp 0x90(%r14), %rax
        jge jit$$trace_exit_2
        cmp $0x4, 0x78(%r14)
        jnz jit$$trace_exit_3
        mov 0x70(%r14), %rax
        shl $0x4, %rax
        jo .L6
        mov %rax, 0x70(%r14)
.L2:
        mov $EG(vm_stack_top), %r15
        mov (%r15), %r15
        mov $EG(vm_stack_top), %rdx
        add $0x60, (%rdx)
        mov $0x0, 0x28(%r15)
        mov $0x5572643c6590, %rcx
        mov %rcx, 0x18(%r15)
        mov $0x0, 0x20(%r15)
        mov $0x1, 0x2c(%r15)
        cmp $0x6, 0x58(%r14)
        jnz jit$$trace_exit_4
        cmp $0x4, 0x88(%r14)
        jnz jit$$trace_exit_4
        mov $0x409da8e0, (%r14)
        mov 0x50(%r14), %rdi
        mov 0x80(%r14), %rsi
        mov $zend_jit_fetch_dim_str_offset_r_helper, %rax
        call *%rax
        mov %rax, 0xa0(%r14)
        mov $0x6, 0xa8(%r14)
        mov $EG(exception), %rax
        cmp $0x0, (%rax)
        jnz JIT$$exception_handler
        cmp $0x6, 0xa8(%r14)
        jnz jit$$trace_exit_6
        mov 0xa0(%r14), %rdx
        mov %rdx, 0x50(%r15)
        mov 0xa8(%r14), %eax
        mov %eax, 0x58(%r15)
        mov $0x409da920, (%r14)
        mov %r14, 0x30(%r15)
        lea 0xb0(%r14), %rsi
        mov $0x1, 0x8(%rsi)
        mov $EG(current_execute_data), %rcx
        mov %r15, (%rcx)
        mov %r15, %rdi
        mov $0x557262a8e270, %rax
        call *%rax
        mov $EG(current_execute_data), %rax
        mov %r14, (%rax)
        test $0x1, 0x59(%r15)
        jnz .L7
.L3:
        mov $EG(vm_stack_top), %rax
        mov %r15, (%rax)
        mov $EG(exception), %rax
        cmp $0x0, (%rax)
        jnz JIT$$icall_throw
        mov $EG(vm_interrupt), %rax
        cmp $0x0, (%rax)
        jnz jit$$trace_exit_7
        mov 0xb0(%r14), %rax
        sub $0x30, %rax
        jo jit$$trace_exit_8
        mov %rax, 0xa0(%r14)
        mov $0x4, 0xa8(%r14)
        cmp $0x4, 0x78(%r14)
        jnz jit$$trace_exit_9
        mov 0x70(%r14), %rax
        add 0xa0(%r14), %rax
        jo .L8
        mov %rax, 0x70(%r14)
.L4:
        cmp $0x4, 0x88(%r14)
        jnz jit$$trace_exit_10
        add $0x1, 0x80(%r14)
        jo .L9
.L5:
        mov $EG(vm_interrupt), %rax
        cmp $0x0, (%rax)
        jz .L1
        jmp jit$$trace_exit_11
.L6:
        vxorps %xmm0, %xmm0, %xmm0
        vcvtsi2sd 0x70(%r14), %xmm0, %xmm0
        mov $0x10, %rax
        vxorps %xmm1, %xmm1, %xmm1
        vcvtsi2sd %rax, %xmm1, %xmm1
        vmulsd %xmm1, %xmm0, %xmm0
        vmovsd %xmm0, 0x70(%r14)
        mov $0x5, 0x78(%r14)
        jmp .L2
.L7:
        mov 0x50(%r15), %rdi
        sub $0x1, (%rdi)
        jnz .L3
        mov $0x409da920, (%r14)
        mov $rc_dtor_func, %rax
        call *%rax
        jmp .L3
.L8:
        vxorps %xmm0, %xmm0, %xmm0
        vcvtsi2sd 0x70(%r14), %xmm0, %xmm0
        vxorps %xmm1, %xmm1, %xmm1
        vcvtsi2sd 0xa0(%r14), %xmm1, %xmm1
        vaddsd %xmm1, %xmm0, %xmm0
        vmovsd %xmm0, 0x70(%r14)
        mov $0x5, 0x78(%r14)
        jmp .L4
.L9:
        mov $0x43e0000000000000, %rax
        mov %rax, 0x80(%r14)
        mov $0x5, 0x88(%r14)
        jmp .L5

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

// 65-bit hexadecimal number
$hex = '10000000000000041';

for ($i = 0; $i < 200; ++$i) {
    $characterReferenceCode = 0;

    for ($j = 0, $len = strlen($hex); $j < $len; ++$j) {
        $characterReferenceCode *= 16;
        $characterReferenceCode += ord($hex[$j]) - 0x0030;
    }

    assert($characterReferenceCode > 0x10FFFF);
}



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-07-06 12:59 UTC] nikic@php.net
This one doesn't reproduce for me.
 [2021-07-06 13:54 UTC] smokey101stair at gmail dot com
Are you able to reproduce if you increase the iterations from 200 to 20000? If not, I'll have to recheck it when I get home. Is there any other info I can provide to help debug this?
 [2021-07-07 00:02 UTC] smokey101stair at gmail dot com
Perhaps you will have better luck reproducing when it is extracted into a function, which also reproduces the issue for me

<?php

// 65-bit hexadecimal number
$hex = '10000000000000041';

function getNumericReference(string $hex) {
    $characterReferenceCode = 0;

    for ($j = 0, $len = strlen($hex); $j < $len; ++$j) {
        $characterReferenceCode *= 16;
        $characterReferenceCode += ord($hex[$j]) - 0x0030;
    }

    return $characterReferenceCode;
}

for ($i = 0; $i < 20000; ++$i) {
    assert(getNumericReference($hex) > 0x10FFFF);
}
 [2021-07-12 13:15 UTC] hao dot sun at arm dot com
I can reproduce this bug in my local environment even with functional JIT.

I noticed that this bug doesn't occur in JIT/x86 on master branch.
After bisect, I guess the root cause is that the following patches in master branch are not merged to PHP-8.0.*.

https://github.com/php/php-src/commit/5e05c70ee727815805697a90b39f4d82cd4b4d3d#diff-c0fa9f6cbf84b02388699bafb28a11d7f69780bbf2b0e1bceea4cb99763c1328
https://github.com/php/php-src/commit/186a5277aa237b1f98cd0a74f43c535b8958f85b#
 [2021-07-20 19:02 UTC] smokey101stair at gmail dot com
Is there anything blocking the back-porting of these 2 commits?
 [2021-07-21 12:20 UTC] nikic@php.net
-Assigned To: +Assigned To: dmitry
 [2021-07-21 16:29 UTC] git@php.net
Automatic comment on behalf of dstogov
Revision: https://github.com/php/php-src/commit/053c56f52e094bcf57958e0d4e71c0c4e3f9a2b2
Log: Fixed bug #81226 (Integer overflow behavior is different with JIT enabled)
 [2021-07-21 16:29 UTC] git@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Sun Nov 28 19:03:38 2021 UTC