Bug #72936 [NEW]: Zend API's zend_symtable_str_update() asserts key should end with '\0'

From: Date: Thu, 25 Aug 2016 06:15:52 +0000
Subject: Bug #72936 [NEW]: Zend API's zend_symtable_str_update() asserts key should end with '\0'
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-203529@lists.php.net to get a copy of this message
From: arseny dot vakhrushev at gmail dot com Operating system: All PHP version: 7.0.10 Package: Arrays related Bug Type: Bug Bug description:Zend API's zend_symtable_str_update() asserts key should end with '\0' Description: ------------ Hello everyone, I'm a developer of a PHP extension, namely php-amf3, and I'm having an issue with zend_symtable_str_update() defined in Zend/zend_hash.h. The code seems to be encouraged to use zend_symtable_str_update() instead of zend_hash_str_update() for string keys because otherwise in case of "numeric" string keys like "123", "-10", etc, there is no way to index such arrays in PHP scripts when using zend_hash_str_update(). More specifically, a C code: ... zval arr, val; array_init(&arr); ZVAL_TRUE(&val); zend_hash_str_update(HASH_OF(&arr), "123", 3, &val); // zend_symtable_str_update() needs to be used instead ... builds an array ["123" => true] which is impossible to index as $arr["123"]. Internally, the key is tested whether it's "numeric" (which is the case) and then the array is indexed with an integer value of 123 which yields NULL. Ok, switching to zend_symtable_str_update() instead of zend_hash_str_update() seems like a Sunday picnic in the park. They are compatible, and everything looks neat and tidy. The problem arises when PHP is compiled with assertions (my default development mode). zend_symtable_str_update() is essentially a wrapper around zend_hash_index_update() and zend_hash_str_update() calling either of them depending on the provided key being "numeric" or not: zval *zend_symtable_str_update(HashTable *ht, const char *str, size_t len, zval *pData) { zend_ulong idx; if (ZEND_HANDLE_NUMERIC_STR(str, len, idx)) { return zend_hash_index_update(ht, idx, pData); } else { return zend_hash_str_update(ht, str, len, pData); } } The ZEND_HANDLE_NUMERIC_STR macro is essentially a call to: int _zend_handle_numeric_str_ex(const char *key, size_t length, zend_ulong *idx) { register const char *tmp = key; const char *end = key + length; ZEND_ASSERT(*end == '\0'); ... } The problem lies in the ZEND_ASSERT which incurs the following: - It reads beyond 'length' bytes (in contrast, zend_hash_str_update() does not); - Requests keys to have a trailing zero making the whole point of the 'length' argument useless (please note that it DOES NOT rely on a key to end with '\0' anywhere else in the body); - Makes it impossible to avoid allocating a temporary buffer in the case when a source key buffer does not have a trailing zero. It seems that the whole point of having a ZEND_ASSERT here does not make a lot of sense since there is no similar restriction in the underlying zend_hash_str_update() function. I infer that this assertion has been there for some "historical" reasons from the era of trailing zeroes in strings/keys and should be removed. Of course, one can work around the whole issue by allocating a temporary buffer, copying a key into it, finalizing it with a trailing zero and calling zend_symtable_str_update() with it. But I hope everyone can see that little issues like this lead to more issues in the future essentially masking problems at the expense of the user (additional overhead) instead of solving them. Cheers, Arseny -- Edit bug report at https://bugs.php.net/bug.php?id=72936&edit=1 -- Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=72936&r=trysnapshot54 Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=72936&r=trysnapshot55 Try a snapshot (trunk): https://bugs.php.net/fix.php?id=72936&r=trysnapshottrunk Fixed in SVN: https://bugs.php.net/fix.php?id=72936&r=fixed Fixed in release: https://bugs.php.net/fix.php?id=72936&r=alreadyfixed Need backtrace: https://bugs.php.net/fix.php?id=72936&r=needtrace Need Reproduce Script: https://bugs.php.net/fix.php?id=72936&r=needscript Try newer version: https://bugs.php.net/fix.php?id=72936&r=oldversion Not developer issue: https://bugs.php.net/fix.php?id=72936&r=support Expected behavior: https://bugs.php.net/fix.php?id=72936&r=notwrong Not enough info: https://bugs.php.net/fix.php?id=72936&r=notenoughinfo Submitted twice: https://bugs.php.net/fix.php?id=72936&r=submittedtwice register_globals: https://bugs.php.net/fix.php?id=72936&r=globals PHP 4 support discontinued: https://bugs.php.net/fix.php?id=72936&r=php4 Daylight Savings: https://bugs.php.net/fix.php?id=72936&r=dst IIS Stability: https://bugs.php.net/fix.php?id=72936&r=isapi Install GNU Sed: https://bugs.php.net/fix.php?id=72936&r=gnused Floating point limitations: https://bugs.php.net/fix.php?id=72936&r=float No Zend Extensions: https://bugs.php.net/fix.php?id=72936&r=nozend MySQL Configuration Error: https://bugs.php.net/fix.php?id=72936&r=mysqlcfg

« previous php.bugs (#203529) next »