Skip to content

gen_stub: Fix handling of escape sequences in generated C strings#22273

Open
NattyNarwhal wants to merge 1 commit into
php:masterfrom
NattyNarwhal:gen-stub-string-escape
Open

gen_stub: Fix handling of escape sequences in generated C strings#22273
NattyNarwhal wants to merge 1 commit into
php:masterfrom
NattyNarwhal:gen-stub-string-escape

Conversation

@NattyNarwhal

@NattyNarwhal NattyNarwhal commented Jun 10, 2026

Copy link
Copy Markdown
Member

When handling sequences like this in a stub:

<?php
class Whatever {
    public static string $foobar1 = "CCC \n\r\t\v\e\f\\\$\"\101\x41\u{41} CCC";
    public static string $foobar2 = 'CCC \n\r\t\v\e\f\\\$\"\101\x41\u{41} CCC';
}

...properly generate C headers that properly escape the string. Otherwise, the differing escaping rules and differences between PHP's single and double quoted strings could lead to mangled headers.

The output of these strings after the stub has been generated:

string(22) "BEGIN 

	��\$"AAA END"
string(43) "BEGIN \n\r\t\v\e\f\\\\$\"\101\x41\u{41} END"

And the generated arginfo:

        zend_string *property_doubleQuoteEscaped_default_value_str = zend_string_init("BEGIN \n\r\t\v\x1b\f\\$\"AAA END", strlen("BEGIN \n\r\t\v\x1b\f\\$\"AAA END"), 1);
pp      ZVAL_STR(&property_doubleQuoteEscaped_default_value, property_doubleQuoteEscaped_default_value_str);
        zend_string *property_doubleQuoteEscaped_name = zend_string_init("doubleQuoteEscaped", sizeof("doubleQuoteEscaped") - 1, true);
        zend_declare_typed_property(class_entry, property_doubleQuoteEscaped_name, &property_doubleQuoteEscaped_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
        zend_string_release_ex(property_doubleQuoteEscaped_name, true);

        zval property_singleQuoteEscaped_default_value;
        zend_string *property_singleQuoteEscaped_default_value_str = zend_string_init("BEGIN \\n\\r\\t\\v\\e\\f\\\\\\\\$\\\"\\101\\x41\\u{41} END", strlen("BEGIN \\n\\r\\t\\v\\e\\f\\\\\\\\$\\\"\\101\\x41\\u{41} END"), 1);
        ZVAL_STR(&property_singleQuoteEscaped_default_value, property_singleQuoteEscaped_default_value_str);
        zend_string *property_singleQuoteEscaped_name = zend_string_init("singleQuoteEscaped", sizeof("singleQuoteEscaped") - 1, true);
        zend_declare_typed_property(class_entry, property_singleQuoteEscaped_name, &property_singleQuoteEscaped_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
        zend_string_release_ex(property_singleQuoteEscaped_name, true);

Note that the PHP escape sequence "$" will be handled in a special manner to avoid providing it to C, to avoid C compiler warnings.

Tests are included via the zend_test stub and a phpt file to ensure that the escape sequences match.

Fixes GH-22169.

@TimWolla

Copy link
Copy Markdown
Member

I'm also unsure how best to make tests for gen_stub, so I haven't included any beyond mentioning how to test manually with this commit.

Add it to the ext/zend_test stub.

Comment thread ext/zend_test/test.stub.php

@kocsismate kocsismate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but LGTM otherwise, thank you!

Comment thread ext/zend_test/test.stub.php Outdated
Comment thread ext/zend_test/test.stub.php Outdated
@NattyNarwhal NattyNarwhal force-pushed the gen-stub-string-escape branch from 8ac2225 to 3e50b9c Compare June 13, 2026 22:17
@NattyNarwhal NattyNarwhal marked this pull request as ready for review June 13, 2026 22:24
When handling sequences like this in a stub:

```php
<?php
class Whatever {
    public static string $foobar1 = "CCC \n\r\t\v\e\f\\\$\"\101\x41\u{41} CCC";
    public static string $foobar2 = 'CCC \n\r\t\v\e\f\\\$\"\101\x41\u{41} CCC';
}
```

...properly generate C headers that properly escape the string.
Otherwise, the differing escaping rules and differences between PHP's
single and double quoted strings could lead to mangled headers.

The output of these strings after the stub has been generated:

```
string(22) "BEGIN

	��\$"AAA END"
string(43) "BEGIN \n\r\t\v\e\f\\\\$\"\101\x41\u{41} END"
```

And the generated arginfo:

```c
        zval property_doubleQuoteEscaped_default_value;
        zend_string *property_doubleQuoteEscaped_default_value_str = zend_string_init("BEGIN \n\r\t\v\x1b\f\\$\"AAA END", strlen("BEGIN \n\r\t\v\x1b\f\\$\"AAA END"), 1);
pp      ZVAL_STR(&property_doubleQuoteEscaped_default_value, property_doubleQuoteEscaped_default_value_str);
        zend_string *property_doubleQuoteEscaped_name = zend_string_init("doubleQuoteEscaped", sizeof("doubleQuoteEscaped") - 1, true);
        zend_declare_typed_property(class_entry, property_doubleQuoteEscaped_name, &property_doubleQuoteEscaped_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
        zend_string_release_ex(property_doubleQuoteEscaped_name, true);

        zval property_singleQuoteEscaped_default_value;
        zend_string *property_singleQuoteEscaped_default_value_str = zend_string_init("BEGIN \\n\\r\\t\\v\\e\\f\\\\\\\\$\\\"\\101\\x41\\u{41} END", strlen("BEGIN \\n\\r\\t\\v\\e\\f\\\\\\\\$\\\"\\101\\x41\\u{41} END"), 1);
        ZVAL_STR(&property_singleQuoteEscaped_default_value, property_singleQuoteEscaped_default_value_str);
        zend_string *property_singleQuoteEscaped_name = zend_string_init("singleQuoteEscaped", sizeof("singleQuoteEscaped") - 1, true);
        zend_declare_typed_property(class_entry, property_singleQuoteEscaped_name, &property_singleQuoteEscaped_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
        zend_string_release_ex(property_singleQuoteEscaped_name, true);
```

Note that the PHP escape sequence "\$" will be handled in a special
manner to avoid providing it to C, to avoid C compiler warnings.

Tests are included via the zend_test stub and a phpt file to ensure that
the escape sequences match.

Fixes phpGH-22169.
@NattyNarwhal NattyNarwhal force-pushed the gen-stub-string-escape branch from 3e50b9c to debc17c Compare June 13, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gen_stub.php generated wrong C string

4 participants