Skip to content

Segfault with frameless jumps and minimal JIT #15981

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

Closed
YuanchengJiang opened this issue Sep 22, 2024 · 5 comments
Closed

Segfault with frameless jumps and minimal JIT #15981

YuanchengJiang opened this issue Sep 22, 2024 · 5 comments

Comments

@YuanchengJiang
Copy link

Description

The following code:

<?php
require('tester.inc');
$cfg = <<<EOT
EOT;
$code = <<<EOT
EOT;
$tester = new FPM\Tester($cfg, $code);
$tester->start();

Resulted in this output:

Zend/zend_vm_execute.h:6025:2: runtime error: member access within misaligned address 0x7fd6e5c0520f for type 'zval' (aka 'struct _zval_struct'), which requires 8 byte alignment
0x7fd6e5c0520f: note: pointer points here
 00 00 00 00 00  f8 12 0c 41 00 00 00 00  00 00 00 00 00 00 00 00  f0 51 c0 e5 d6 7f 00 00  58 09 0c
             ^ 
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior Zend/zend_vm_execute.h:6025:2

To reproduce:

-d "opcache.jit_hot_loop=1" -d "zend_extension=/php-src/modules/opcache.so" -d "opcache.enable_cli=1" -d "opcache.jit=1131"

tester.inc:

sapi/fpm/tests/tester.inc

PHP Version

PHP 8.4.0-dev

Operating System

ubuntu 22.04

@cmb69
Copy link
Member

cmb69 commented Sep 22, 2024

Looks related to #15658.

@nielsdos
Copy link
Member

nielsdos commented Sep 24, 2024

Semi-automatically reduced to:

<?php

namespace NS { // Namespace is important to reproduce the issue
    class Tester {
        static public function findExecutable(): string {
            for ($i = 0; $i < 2; $i++) {
                // Need this loop to reproduce
            }
            return dirname(__DIR__);
        }
    }
}

namespace {
    NS\Tester::findExecutable();
}

Or with opcache.jit=1111:

<?php

namespace NS { // Namespace is important to reproduce the issue
    class Tester {
        static public function findExecutable(): string {
            return dirname(__DIR__);
        }
    }
}

namespace {
    NS\Tester::findExecutable();
}

@nielsdos
Copy link
Member

nielsdos commented Sep 24, 2024

It's again related to FLFs.

ZEND_INIT_NS_FCALL_BY_NAME VM handler is called with opline->opcode == JMP_FRAMELESS and pointing at the wrong cache slot as a consequence.

I think the JIT should generate a move to %r15 with the right opline in both possible successor blocks of JMP_FRAMELESS, but I'm not sure how to do that properly. Using zend_jit_reset_last_valid_opline in zend_jit_jmp_frameless doesn't work because the following code resets the last valid opline:

if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW)
&& ssa->cfg.blocks[b].start != 0
&& (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP
|| op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG
|| op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING
|| op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) {
zend_jit_reset_last_valid_opline(&ctx);
} else {
zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
}

@nielsdos
Copy link
Member

cc @dstogov I'm not sure how to fix this, I would need some input to know how to tackle this issue please.

@dstogov
Copy link
Member

dstogov commented Sep 25, 2024

I don't know this new code...
It looks like JIT code generated by zend_jit_jmp_frameless() doesn't update EX(opline).
Actually JIT with optimization_level=1 shouldn't generate the complex code at all.

cc @iluuu1994

@nielsdos nielsdos changed the title Segmentation fault in Zend/zend_vm_execute.h Segfault with frameless jumps and minimal JIT Jan 2, 2025
@nielsdos nielsdos linked a pull request Jan 2, 2025 that will close this issue
nielsdos added a commit that referenced this issue Jan 9, 2025
* PHP-8.4:
  Fix GH-17307: Internal closure causes JIT failure
  Generate inline frameless icall handlers only if the optimization level is set to inline
  Fix GH-15981: Segfault with frameless jumps and minimal JIT
  Fix GH-15833: Segmentation fault (access null pointer) in ext/spl/spl_array.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants