Skip to content

Assertion with function/tracing JIT #12428

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
danog opened this issue Oct 12, 2023 · 10 comments
Closed

Assertion with function/tracing JIT #12428

danog opened this issue Oct 12, 2023 · 10 comments

Comments

@danog
Copy link
Contributor

danog commented Oct 12, 2023

Description

Description

Running the infection phpunit testsuite, commit 2789fdd689689b0c85f2c0ae9db50c8d2b39fb92 throws an assertion:

php: /root/php-src/Zend/zend_execute.c:251: zval *_get_zval_ptr_tmp(uint32_t, zend_execute_data *): Assertion `zval_get_type(&(*(ret))) != 10' failed.

php.ini:

memory_limit = -1
zend.assertions = 1
display_errors = On
display_startup_errors = On
extension=uv
extension=gmp
extension=iconv
[opcache]
zend_extension=opcache
opcache.memory_consumption=4096M
opcache.enable=1
opcache.enable_cli=1
opcache.jit=tracing
opcache.validate_timestamps=0
opcache.jit_buffer_size=1G
opcache.file_update_protection=0
opcache.max_accelerated_files=1000000
opcache.interned_strings_buffer=64

;opcache.jit_debug=28672
;opcache.jit_debug=16384

opcache.jit_prof_threshold=0.000000001
opcache.jit_max_root_traces=  30000000
opcache.jit_max_side_traces=  30000000
opcache.jit_max_exit_counters=30000000
opcache.jit_hot_loop=1
opcache.jit_hot_func=1
opcache.jit_hot_return=1
opcache.jit_hot_side_exit=1

opcache.jit_blacklist_root_trace=255
opcache.jit_blacklist_side_trace=255

opcache.protect_memory=1

Command:

php patch.php vendor/bin/phpunit ./tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php --filter test_it_can_create_a_config --debug

Result:

patch.php from https://github.com/php/php-src/pull/12425/files:

<?php

register_shutdown_function(function () {
    $status = opcache_get_status(false);
    var_dump($status);

    $ok = true;
    if ($status["memory_usage"]["free_memory"] < 10*1024*1024) {
        echo "Not enough free opcache memory!".PHP_EOL;
        $ok = false;
    }
    if ($status["interned_strings_usage"]["free_memory"] < 1*1024*1024) {
        echo "Not enough free interned strings memory!".PHP_EOL;
        $ok = false;
    }
    if ($status["jit"]["buffer_free"] < 10*1024*1024) {
        echo "Not enough free JIT memory!".PHP_EOL;
        $ok = false;
    }
    if (!$status["jit"]["on"]) {
        echo "JIT is not enabled!".PHP_EOL;
        $ok = false;
    }

    unset($status);
    gc_collect_cycles();

    if (!$ok) die(130);
});

$argc--;
array_shift($argv);

$_SERVER['argc']--;
array_shift($_SERVER['argv']);

require $argv[0];

Ping @dstogov

PHP Version

3a41dc8

Operating System

No response

@danog
Copy link
Contributor Author

danog commented Oct 12, 2023

Full output:

vendor/bin/phpunit ./tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php --filter test_it_can_create_a_config --debug
PHPUnit 9.6.13 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.4.0-dev
Configuration: /root/infection/phpunit.xml.dist
Random Seed:   1697134123

Testing Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayUdiffUassoc] enabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayUdiffUassoc] enabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][BCMath] true" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][BCMath] true" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][Coalesce] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][Coalesce] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][profile] @default ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][profile] @default ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayUintersectAssoc] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayUintersectAssoc] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayDiffAssoc] enabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayDiffAssoc] enabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapLcFirst] ignore empty & untrimmed" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapLcFirst] ignore empty & untrimmed" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][profile] @loop ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][profile] @loop ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][ArrayItemRemoval] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][ArrayItemRemoval] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "minimal" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "minimal" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][NotIdentical] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][NotIdentical] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayKeys] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][UnwrapArrayKeys] disabled" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][FloatNegation] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[mutators][generic][FloatNegation] ignore" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[minCoveredMsi] is int" ('{\n    "source": {\n        "... 32\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[minCoveredMsi] is int" ('{\n    "source": {\n        "... 32\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' ended
Test 'Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config with data set "[logs][perMutator] nominal" ('{\n    "source": {\n        "...  }\n}', Infection\Configuration\Schema\SchemaConfiguration Object (...))' started
php: /root/php-src/Zend/zend_execute.c:251: zval *_get_zval_ptr_tmp(uint32_t, zend_execute_data *): Assertion `zval_get_type(&(*(ret))) != 10' failed.
Aborted

@danog
Copy link
Contributor Author

danog commented Oct 12, 2023

Same assertion occurs when using function JIT, not when JIT is disabled.

@danog danog changed the title Assertion with tracing JIT Assertion with function/tracing JIT Oct 12, 2023
@danog
Copy link
Contributor Author

danog commented Oct 12, 2023

Backtraces:

(gdb) back
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7209859 in __GI_abort () at abort.c:79
#2  0x00007ffff7209729 in __assert_fail_base (fmt=0x7ffff739f588 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x2ac4d20 <str> "zval_get_type(&(*(ret))) != 10",
    file=0x2ab75a0 <str> "/root/php-src/Zend/zend_execute.c", line=251, function=<optimized out>) at assert.c:92
#3  0x00007ffff721afd6 in __GI___assert_fail (assertion=0x2ac4d20 <str> "zval_get_type(&(*(ret))) != 10", file=0x2ab75a0 <str> "/root/php-src/Zend/zend_execute.c", line=251,
    function=0x2ac4d60 <__PRETTY_FUNCTION__._get_zval_ptr_tmp> "zval *_get_zval_ptr_tmp(uint32_t, zend_execute_data *)") at assert.c:101
#4  0x00000000019967d5 in _get_zval_ptr_tmp (var=144, execute_data=0x7ffff1e08ed0) at Zend/zend_execute.c:251
#5  0x0000000001935ef5 in ZEND_COALESCE_SPEC_TMP_HANDLER (execute_data=0x7ffff1e08ed0) at Zend/zend_vm_execute.h:19710
#6  0x00007fffb17379d0 in ?? ()
#7  0x0000000000000000 in ?? ()
(gdb) zback
[0x7ffff1e08ed0] Infection\Configuration\Schema\SchemaConfigurationFactory->create("/path/to/config", object[0x7ffff1e08f30])
/root/infection/src/Configuration/Schema/SchemaConfigurationFactory.php:59
[0x7ffff1e08e10] Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest->test_it_can_create_a_config("{\12    "source": {\12        "directories": ["src"]\12    },\12    "logs": {
\12        "perMutator": "perMutator.log"\12    }\12}", object[0x7ffff1e08e70]) /root/infection/tests/phpunit/Configuration/Schema/SchemaConfigurationFactoryTest.php:104
[0x7ffff1e08d70] PHPUnit\Framework\TestCase->runTest() /root/infection/vendor/phpunit/phpunit/src/Framework/TestCase.php:1612
[0x7ffff1e08ca0] PHPUnit\Framework\TestCase->runBare() /root/infection/vendor/phpunit/phpunit/src/Framework/TestCase.php:1218
[0x7ffff1e08a50] PHPUnit\Framework\TestResult->run(object[0x7ffff1e08aa0]) /root/infection/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
[0x7ffff1e08800] PHPUnit\Framework\TestCase->run(object[0x7ffff1e08850]) /root/infection/vendor/phpunit/phpunit/src/Framework/TestCase.php:968
[0x7ffff1e086b0] PHPUnit\Framework\TestSuite->run(object[0x7ffff1e08700]) /root/infection/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
[0x7ffff1e08560] PHPUnit\Framework\TestSuite->run(object[0x7ffff1e085b0]) /root/infection/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684
[0x7ffff1e082d0] PHPUnit\TextUI\TestRunner->run(object[0x7ffff1e08320], reference, reference, true) /root/infection/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651
[0x7ffff1e081f0] PHPUnit\TextUI\Command->run(array(5)[0x7ffff1e08240], true) /root/infection/vendor/phpunit/phpunit/src/TextUI/Command.php:144
[0x7ffff1e08150] PHPUnit\TextUI\Command->main() /root/infection/vendor/phpunit/phpunit/src/TextUI/Command.php:97
[0x7ffff1e080a0] (main) /root/infection/vendor/phpunit/phpunit/phpunit:107
[0x7ffff1e08020] (main) /root/infection/vendor/bin/phpunit:122

@danog
Copy link
Contributor Author

danog commented Oct 15, 2023

Minimal reproducer:

<?php

function validate($value)
{
    foreach ([0] as $_) {
        $a = &$value->a;
        $value->a ?? null;
    }
}

validate((object) []);
validate((object) []);
validate((object) ['b' => 0]);

dstogov added a commit that referenced this issue Oct 16, 2023
* PHP-8.1:
  Fixed GH-12428: Assertion with function/tracing JIT
dstogov added a commit that referenced this issue Oct 16, 2023
* PHP-8.2:
  Fixed GH-12428: Assertion with function/tracing JIT
dstogov added a commit that referenced this issue Oct 16, 2023
* PHP-8.3:
  Fixed GH-12428: Assertion with function/tracing JIT
@dstogov
Copy link
Member

dstogov commented Oct 16, 2023

Thanks for the small test case. It's fixed now.
When do you plan to land all these community tests improvements?

@danog
Copy link
Contributor Author

danog commented Oct 16, 2023

Hi @dstogov, no problem, but it seems another similar assertion is still being emitted when running the testsuite, will try to isolate again but maybe there's another similar place in the code that can trigger the issue?

(gdb) back
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff6ffa8a3 in __pthread_kill_internal (signo=6, threadid=<optimized out>) at pthread_kill.c:78
#2  0x00007ffff6faa668 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff6f924b8 in __GI_abort () at abort.c:79
#4  0x00007ffff6f923dc in __assert_fail_base (fmt=0x7ffff710bae8 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
    assertion=assertion@entry=0x555557953f60 <str> "zval_get_type(&(*(ret))) != 10",
    file=file@entry=0x55555794f240 <str> "/home/daniil/repos/php-src/Zend/zend_execute.c", line=line@entry=251,
    function=function@entry=0x555557953fa0 <__PRETTY_FUNCTION__._get_zval_ptr_tmp> "zval *_get_zval_ptr_tmp(uint32_t, zend_execute_data *)")
    at assert.c:92
#5  0x00007ffff6fa2d26 in __assert_fail (assertion=0x555557953f60 <str> "zval_get_type(&(*(ret))) != 10",
    file=0x55555794f240 <str> "/home/daniil/repos/php-src/Zend/zend_execute.c", line=251,
    function=0x555557953fa0 <__PRETTY_FUNCTION__._get_zval_ptr_tmp> "zval *_get_zval_ptr_tmp(uint32_t, zend_execute_data *)") at assert.c:101
#6  0x0000555556ac6d5c in _get_zval_ptr_tmp (var=160, execute_data=0x7ffff4802610) at /home/daniil/repos/php-src/Zend/zend_execute.c:251
#7  0x0000555556a6eaa4 in ZEND_COALESCE_SPEC_TMP_HANDLER (execute_data=0x7ffff4802610) at Zend/zend_vm_execute.h:19710
#8  0x00007fffb16ebdcb in TRACE-608$Infection\Tests\Configuration\Schema\SchemaConfigurationFactoryTest::test_it_can_create_a_config$106 ()
    at unknown:1

Regarding the testsuite improvements PRs, #12425 is ready to merge, as is #12406.

Will submit a new PR with a nightly test for infection, and another PR that further improves JIT coverage by running all unit tests 3x times in a php-fpm daemon, or by using the file cache this weekend.

@dstogov dstogov reopened this Oct 16, 2023
@dstogov dstogov self-assigned this Oct 16, 2023
@dstogov
Copy link
Member

dstogov commented Oct 18, 2023

I can't reproduce the bug with infection

@danog
Copy link
Contributor Author

danog commented Oct 19, 2023

Hi @dstogov, I can reproduce with this slightly reduced testcase using commit 745a346 of php-src:

<?php

require 'vendor/autoload.php';

use Infection\Configuration\Entry\Logs;
use Infection\Configuration\Entry\PhpUnit;
use Infection\Configuration\Entry\Source;
use Infection\Configuration\Schema\SchemaConfiguration;
use Infection\Configuration\Schema\SchemaConfigurationFactory;
use JsonSchema\Validator;

function test_it_can_create_a_config(
    string $json,
): void {
    $rawConfig = json_decode($json);

    $validator = new Validator();

    $validator->validate($rawConfig, json_decode('{
        "$schema": "https://json-schema.org/draft-07/schema#",
        "properties": {
            "source": {"type": "string"}
        }
    }'));

    $actual = (new SchemaConfigurationFactory())->create(
        '/path/to/config',
        $rawConfig
    );
}

function provideRawConfig(): iterable
{

    yield '[timeout] nominal' => [
        <<<'JSON'
{
"timeout": 100,
"source": {
    "directories": ["src"]
}
}
JSON
        ,
    ];


    yield '[logs][text] nominal' => [
        <<<'JSON'
{
"source": {
    "directories": ["src"]
},
"logs": {
    "text": "text.log"
}
}
JSON
        ,
    ];
    yield '[logs][html] nominal' => [
        <<<'JSON'
{
"source": {
    "directories": ["src"]
},
"logs": {
    "html": "report.html"
}
}
JSON
        ,
    ];
}

for ($x = 0; $x < 10000; $x++) {
    foreach (provideRawConfig() as [$a]) {
        test_it_can_create_a_config($a);
    }
}

The same assertion also occurs when running phpunit.

Same config as usual:

memory_limit = -1
zend.assertions = 1
display_errors = On
display_startup_errors = On
extension=uv
extension=gmp
extension=iconv
[opcache]
zend_extension=opcache
opcache.memory_consumption=4096M
opcache.enable=1
opcache.enable_cli=1
opcache.jit=tracing
opcache.validate_timestamps=0
opcache.jit_buffer_size=1G
opcache.file_update_protection=0
opcache.max_accelerated_files=1000000
opcache.interned_strings_buffer=64

;opcache.jit_debug=28672
;opcache.jit_debug=16384

opcache.jit_prof_threshold=0.000000001
opcache.jit_max_root_traces=  30000000
opcache.jit_max_side_traces=  30000000
opcache.jit_max_exit_counters=30000000
opcache.jit_hot_loop=1
opcache.jit_hot_func=1
opcache.jit_hot_return=1
opcache.jit_hot_side_exit=1

opcache.jit_blacklist_root_trace=255
opcache.jit_blacklist_side_trace=255

opcache.protect_memory=1

@dstogov
Copy link
Member

dstogov commented Oct 23, 2023

I still can't reproduce this

@danog
Copy link
Contributor Author

danog commented Oct 23, 2023

Indeed, can't reproduce anymore with https://github.com/danog/jit_bugs, quite strange, closing this then.

@danog danog closed this as completed Oct 23, 2023
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

2 participants