fix(generator): use interned strings for persistent class metadata

- Replace zend_string_init with zend_string_init_interned for persistent property defaults
- Use ZVAL_INTERNED_STR instead of ZVAL_STR for interned string values
- Add test case to verify persistent string metadata uses non-refcounted interned zval
- Reduce parallel test jobs from 8 to 4 to accommodate compiler test requirements
master
韩天峰 14 hours ago
parent 422bdc4ce6
commit 642e9a7e4b
  1. 2
      .github/workflows/tests.yml
  2. 21
      phpunit/src/GenStubVersionFlagsTest.php
  3. 8
      src/gen_stub.php

@ -237,7 +237,7 @@ jobs:
- name: Run compiler PHPT suite with bootstrap compiler - name: Run compiler PHPT suite with bootstrap compiler
run: | run: |
mkdir -p build mkdir -p build
php run-tests.php -q -j8 --compiler ./tpc \ php run-tests.php -q -j4 --compiler ./tpc \
-w build/failed-tests.txt -W build/test-results.txt tests/compiler -w build/failed-tests.txt -W build/test-results.txt tests/compiler
- name: Upload PHPT failure artifacts - name: Upload PHPT failure artifacts

@ -2,6 +2,27 @@
final class GenStubVersionFlagsTest extends BaseTest final class GenStubVersionFlagsTest extends BaseTest
{ {
public function testPersistentStringMetadataUsesANonRefcountedInternedZval(): void
{
global $translator;
$translator = \TypePhp\CompilerTest::create(ROOT_PATH);
$value = EvaluatedValue::createFromExpression(
new PhpParser\Node\Scalar\String_('PHP'),
null,
null,
[],
);
$code = $value->initializeZval('property_lang_default_value');
self::assertStringContainsString('zend_string_init_interned("PHP"', $code);
self::assertStringContainsString(
'ZVAL_INTERNED_STR(&property_lang_default_value, property_lang_default_value_str);',
$code,
);
}
public function testFlagIntroducedBeforeMinimumSupportedVersionRemainsEnabled(): void public function testFlagIntroducedBeforeMinimumSupportedVersionRemainsEnabled(): void
{ {
$flags = new VersionFlags(['ZEND_ACC_PRIVATE']); $flags = new VersionFlags(['ZEND_ACC_PRIVATE']);

@ -2753,8 +2753,12 @@ class EvaluatedValue
} }
// getCExpr() emits a C string literal here. sizeof() preserves // getCExpr() emits a C string literal here. sizeof() preserves
// embedded NUL bytes, unlike strlen(). // embedded NUL bytes, unlike strlen().
$code .= "\tzend_string *$forStringDef = zend_string_init($cExpr, sizeof($cExpr) - 1, 1);\n"; // Internal class metadata is persistent. PHP 8.5 rejects
$code .= "\tZVAL_STR(&$zvalName, $forStringDef);\n"; // refcounted zvals in persistent property defaults, so a
// persistent-but-refcounted zend_string is not sufficient.
// Interning also makes the value safe to share under ZTS.
$code .= "\tzend_string *$forStringDef = zend_string_init_interned($cExpr, sizeof($cExpr) - 1, 1);\n";
$code .= "\tZVAL_INTERNED_STR(&$zvalName, $forStringDef);\n";
} }
} elseif ($this->type->isArray()) { } elseif ($this->type->isArray()) {
$code .= "\tZVAL_EMPTY_ARRAY(&$zvalName);\n"; $code .= "\tZVAL_EMPTY_ARRAY(&$zvalName);\n";

Loading…
Cancel
Save