Skip to content

HASH_FLAG_ALLOW_COW_VIOLATION is not preserved by zend_hash_real_init_(mixed|packed)_ex() #12986

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
ju1ius opened this issue Dec 20, 2023 · 5 comments

Comments

@ju1ius
Copy link
Contributor

ju1ius commented Dec 20, 2023

Description

Hi,

Currently the zend_hash_real_init_mixed_ex and zend_hash_real_init_packed_ex functions overwrite the hashtable flags which causes the following example to fail:

// allocate a hashtable 
HashTable *ht = (HashTable*) emalloc(sizeof(HashTable));
_zend_hash_init(ht, HT_MIN_SIZE, NULL, false);
// then sometime later:
{
  GC_ADDREF(ht);
  HT_ALLOW_COW_VIOLATION(ht);

  zval *value;
  ZVAL_LONG(&value, 1);
  // HT_ASSERT_RC1(ht) succeeds here because HASH_FLAG_ALLOW_COW_VIOLATION is set.
  // However, since the hashtable is uninitialized at this point,
  // zend_hash_real_init_packed_ex() is called after the check, which unsets the flag.
  zend_hash_next_index_insert(ht, value);

  ZVAL_LONG(&value, 2);
  // HT_ASSERT_RC1(ht) fails here because HASH_FLAG_ALLOW_COW_VIOLATION
  // was cleared in the previous step.
  zend_hash_next_index_insert(ht, value);

  GC_DELREF(ht);
}

Would you consider a PR that preserves this flag through the initialization process ?

Thanks.

PHP Version

PHP 8.3-dev

Operating System

irrelevant

@SVGAnimate
Copy link
Contributor

Hello,

It seems to me that your code is wrong.

  zval *value;
  ZVAL_LONG(value, 1);

consider :

  zval value;
  ZVAL_LONG(&value, 1);

Can you check on your side?

@ju1ius
Copy link
Contributor Author

ju1ius commented Dec 21, 2023

  zval value;
  ZVAL_LONG(&value, 1);

@SVGAnimate Yes, of course, thanks for fixing the typo. That is not the meat of the issue however. 😉

@iluuu1994
Copy link
Member

What's your use-case? HT_ALLOW_COW_VIOLATION is used only in a very few distinct cases.

  • The GC when destroying arrays that are part of a cycle.
  • In php_auto_globals_create_server for PG(http_globals)[TRACK_VARS_SERVER] because it is modified in place.
  • In unserialize with self-references.

HT_ALLOW_COW_VIOLATION is only used for debug builds and likely more of a workaround than something encouraged to be used. It's generally preferable not to violate RC-rules.

ju1ius added a commit to ju1ius/php-src that referenced this issue Dec 23, 2023
ju1ius added a commit to ju1ius/php-src that referenced this issue Dec 23, 2023
ju1ius added a commit to ju1ius/php-src that referenced this issue Dec 23, 2023
ju1ius added a commit to ju1ius/php-src that referenced this issue Dec 23, 2023
@bwoebi
Copy link
Member

bwoebi commented Dec 23, 2023

@iluuu1994 I recently encountered the very same issue while writing code, where I had to ensure the flag exists before every single insertion in order to ensure that my RC=2 array retains the flag, e.g. DataDog/dd-trace-php@b5d3b66 (probably could have called zend_hash_real_init manually too, but anyway...)

The use case in that code is having control over the destruction (zval_ptr_dtor will fail hard when called on a persistent array - but that's a separate issue).

This was quite ugly, so I'm totally agreeing with improving this here.

@ju1ius
Copy link
Contributor Author

ju1ius commented Jan 2, 2024

I'm closing the issue as WONTFIX.
See discussion in #13013.

@ju1ius ju1ius closed this as not planned Won't fix, can't repro, duplicate, stale Jan 2, 2024
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.

5 participants