# Passing HashTable data from php.ini to an extension method: corrupted values

- Thread: https://externals.io/message/111898
- Original archive: https://news-web.php.net/php.internals/111898
- Started by Alexander Mashin on 2020-09-18T05:01:52+00:00
- Messages: 2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #111898 — Alexander Mashin — 2020-09-18T05:01:52+00:00

URL: https://externals.io/message/111898#111898

Dear all,

I am trying to make a PHP (7.4) extension use in an extension method a
setting from php.ini (like myext.map=key1=val1,key2=val2;) parsed as an
associative array. I want the parsing to happen in PHP_MINIT_FUNCTION(myext)
.

So, I declared a php setting, uncommented REGISTER_INI_ENTRIES(); in
PHP_MINIT_FUNCTION(myext), declared:

ZEND_BEGIN_MODULE_GLOBALS(myext)
    HashTable map;
ZEND_END_MODULE_GLOBALS(myext)

and filled MYEXT_G(map) from the php.ini settingJR:

PHP_INI_MH(myext_update_map) {// The part that parses new_value into
(key => val) pairs is skipped. It works.//...// key = val assignments
have been counted.
zend_hash_init(&MYEXT_G(map), count, NULL, NULL, 1); // 1 for
"persistent".// ...// Iterating (key => value) pairs.
    // key, key_len, val, val_len have been successfully extracted from php.ini.
    zend_string * key_z = zend_string_init( key, key_len, 1 );
    zval val_z;
    ZVAL_STRINGL( &val_z, val, val_len );
    zend_hash_add_new( &MYEXT_G(map), key_z, &val_z );

Then, in a PHP method, I try to read data from &MYEXT_G(map):

PHP_METHOD(MyExt, getMap) {// ...
zend_string * key_z;
zval * val_z;
ZEND_HASH_FOREACH_STR_KEY_VAL(&MYEXT_G(map), key_z, val_z)
    php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "ZSTR_VAL(key_z) =
%s\n", ZSTR_VAL(key_z) );
    php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "Z_STRVAL_P(val_z) =
%s\n", Z_STRVAL_P(val_z) );
    php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "Z_STRLEN_P(val_z) =
%lu\n", Z_STRLEN_P(val_z) );
ZEND_HASH_FOREACH_END();

If the PHP script containing MyExt::getLibraries() is called from the
command line, the PHP warnings print keys and values as they were set in
php.ini.

However, if the script is called by HTTP request, in the warning messages,
ZSTR_VAL(key_z) is correct but both Z_STRVAL_P(val_z) and Z_STRLEN_P(val_z)
contain garbage.

All involved functions are either defined as PHP macros or receive TSRMLS_DC
.

It seems that the values (but not keys) in a global hashtable get
deallocated between module initialisation and serving HTTP request.

I have made sure that scalar values in MYEXT_G survive from
PHP_MINIT_FUNCTION(myExt) into PHP method called from HTTP request.

So, how can I make sure that HashTable values are really persistent?

Alexander Mashin

---

## #111899 — Nikita Popov — 2020-09-18T07:36:18+00:00

URL: https://externals.io/message/111898#111899 · In reply to: #111898

On Fri, Sep 18, 2020 at 7:02 AM Alexander Mashin <alex.mashin@gmail.com>
wrote:

> Dear all,
>
> I am trying to make a PHP (7.4) extension use in an extension method a
> setting from php.ini (like myext.map=key1=val1,key2=val2;) parsed as an
> associative array. I want the parsing to happen in
> PHP_MINIT_FUNCTION(myext)
> .
>
> So, I declared a php setting, uncommented REGISTER_INI_ENTRIES(); in
> PHP_MINIT_FUNCTION(myext), declared:
>
> ZEND_BEGIN_MODULE_GLOBALS(myext)
>     HashTable map;
> ZEND_END_MODULE_GLOBALS(myext)
>
> and filled MYEXT_G(map) from the php.ini settingJR:
>
> PHP_INI_MH(myext_update_map) {// The part that parses new_value into
> (key => val) pairs is skipped. It works.//...// key = val assignments
> have been counted.
> zend_hash_init(&MYEXT_G(map), count, NULL, NULL, 1); // 1 for
> "persistent".// ...// Iterating (key => value) pairs.
>     // key, key_len, val, val_len have been successfully extracted from
> php.ini.
>     zend_string * key_z = zend_string_init( key, key_len, 1 );
>     zval val_z;
>     ZVAL_STRINGL( &val_z, val, val_len );
>     zend_hash_add_new( &MYEXT_G(map), key_z, &val_z );
>

ZVAL_STRINGL allocates a per-request string. You'll want to use
ZVAL_STR(&val_z, zend_string_init(val, val_len, 1)); or so.

Nikita


> Then, in a PHP method, I try to read data from &MYEXT_G(map):
>
> PHP_METHOD(MyExt, getMap) {// ...
> zend_string * key_z;
> zval * val_z;
> ZEND_HASH_FOREACH_STR_KEY_VAL(&MYEXT_G(map), key_z, val_z)
>     php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "ZSTR_VAL(key_z) =
> %s\n", ZSTR_VAL(key_z) );
>     php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "Z_STRVAL_P(val_z) =
> %s\n", Z_STRVAL_P(val_z) );
>     php_error_docref( `NULL` TSRMLS_CC, E_WARNING, "Z_STRLEN_P(val_z) =
> %lu\n", Z_STRLEN_P(val_z) );
> ZEND_HASH_FOREACH_END();
>
> If the PHP script containing MyExt::getLibraries() is called from the
> command line, the PHP warnings print keys and values as they were set in
> php.ini.
>
> However, if the script is called by HTTP request, in the warning messages,
> ZSTR_VAL(key_z) is correct but both Z_STRVAL_P(val_z) and Z_STRLEN_P(val_z)
> contain garbage.
>
> All involved functions are either defined as PHP macros or receive
> TSRMLS_DC
> .
>
> It seems that the values (but not keys) in a global hashtable get
> deallocated between module initialisation and serving HTTP request.
>
> I have made sure that scalar values in MYEXT_G survive from
> PHP_MINIT_FUNCTION(myExt) into PHP method called from HTTP request.
>
> So, how can I make sure that HashTable values are really persistent?
>
> Alexander Mashin
