From 3c5363e58190f673ae721c87cabf082b0faca38b Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 9 Mar 2016 15:07:26 -0500 Subject: [PATCH] PHPC-623: Fix 64-bit integer conversion for BSON keys Fixes #256 --- src/bson.c | 118 ++++++++++++++++++++++------------------ tests/bson/bug0623.phpt | 52 ++++++++++++++++++ 2 files changed, 116 insertions(+), 54 deletions(-) create mode 100644 tests/bson/bug0623.phpt diff --git a/src/bson.c b/src/bson.c index 05cab1e8b..8ba3840c4 100644 --- a/src/bson.c +++ b/src/bson.c @@ -1206,99 +1206,109 @@ PHONGO_API void phongo_zval_to_bson(zval *data, php_phongo_bson_flags_t flags, b #if PHP_VERSION_ID >= 70000 { - zend_string *key; - zend_ulong num_key; - zval *value; - - ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, key, value) { - if (key) { - if (Z_TYPE_P(data) == IS_OBJECT) { - zend_string *member = NULL; - - /* Ignore non-public properties */ - if (!instanceof_function(Z_OBJCE_P(data), php_phongo_serializable_ce) && - !is_public_property(Z_OBJCE_P(data), key, &member TSRMLS_CC)) { - if (member) { - zend_string_release(member); - } - continue; - } - - if (flags & PHONGO_BSON_ADD_ID) { - if (!strncmp(member ? ZSTR_VAL(member) : ZSTR_VAL(key), "_id", sizeof("_id")-1)) { - flags &= ~PHONGO_BSON_ADD_ID; - } - } + zend_string *string_key = NULL; + zend_ulong num_key = 0; + zval *value; + + ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, value) { + /* Ensure we're working with a string key */ + if (!string_key) { + string_key = zend_long_to_str(num_key); + } else { + zend_string_addref(string_key); + } - phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, - member ? ZSTR_VAL(member) : ZSTR_VAL(key), - member ? ZSTR_LEN(member) : ZSTR_LEN(key), - value TSRMLS_CC); + if (Z_TYPE_P(data) == IS_OBJECT) { + zend_string *member = NULL; + /* Ignore non-public properties */ + if (!instanceof_function(Z_OBJCE_P(data), php_phongo_serializable_ce) && + !is_public_property(Z_OBJCE_P(data), string_key, &member TSRMLS_CC)) { if (member) { zend_string_release(member); } - } else { - if (flags & PHONGO_BSON_ADD_ID) { - if (!strncmp(ZSTR_VAL(key), "_id", sizeof("_id")-1)) { - flags &= ~PHONGO_BSON_ADD_ID; - } + zend_string_release(string_key); + continue; + } + + if (flags & PHONGO_BSON_ADD_ID) { + if (!strncmp(member ? ZSTR_VAL(member) : ZSTR_VAL(string_key), "_id", sizeof("_id")-1)) { + flags &= ~PHONGO_BSON_ADD_ID; } - phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, ZSTR_VAL(key), ZSTR_LEN(key), value TSRMLS_CC); + } + + phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, + member ? ZSTR_VAL(member) : ZSTR_VAL(string_key), + member ? ZSTR_LEN(member) : ZSTR_LEN(string_key), + value TSRMLS_CC); + + if (member) { + zend_string_release(member); } } else { - char numbuf[32]; - const char *skey; - unsigned int skey_len = 0; - skey_len = bson_uint32_to_string(num_key, (const char **)&skey, numbuf, sizeof(numbuf)); - phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, skey, skey_len, value TSRMLS_CC); + if (flags & PHONGO_BSON_ADD_ID) { + if (!strncmp(ZSTR_VAL(string_key), "_id", sizeof("_id")-1)) { + flags &= ~PHONGO_BSON_ADD_ID; + } + } + phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, ZSTR_VAL(string_key), ZSTR_LEN(string_key), value TSRMLS_CC); } + + zend_string_release(string_key); } ZEND_HASH_FOREACH_END(); } #else zend_hash_internal_pointer_reset_ex(ht_data, &pos); for (;; zend_hash_move_forward_ex(ht_data, &pos)) { - unsigned int key_len = 0; - uint64_t index = 0; - char numbuf[32]; - char *key = NULL; - zval **entry; - int hash_type = HASH_KEY_NON_EXISTENT; + char *string_key = NULL; + uint string_key_len = 0; + ulong num_key = 0; + zval **value; + int hash_type; - hash_type = zend_hash_get_current_key_ex(ht_data, &key, &key_len, &index, 0, &pos); + hash_type = zend_hash_get_current_key_ex(ht_data, &string_key, &string_key_len, &num_key, 0, &pos); if (hash_type == HASH_KEY_NON_EXISTENT) { break; } - if (zend_hash_get_current_data_ex(ht_data, (void **) &entry, &pos) == FAILURE) { + if (zend_hash_get_current_data_ex(ht_data, (void **) &value, &pos) == FAILURE) { break; } if (hash_type == HASH_KEY_IS_STRING) { if (ht_data_from_properties) { const char *class_name; - zend_unmangle_property_name(key, key_len-1, &class_name, (const char **)&key); - key_len = strlen(key); + zend_unmangle_property_name(string_key, string_key_len-1, &class_name, (const char **)&string_key); + string_key_len = strlen(string_key); /* Ignore non-public properties */ - if (!is_public_property(Z_OBJCE_P(data), key, key_len TSRMLS_CC)) { + if (!is_public_property(Z_OBJCE_P(data), string_key, string_key_len TSRMLS_CC)) { continue; } } else { /* Chop off the \0 from string lengths */ - key_len -= 1; + string_key_len -= 1; } if (flags & PHONGO_BSON_ADD_ID) { - if (!strncmp(key, "_id", sizeof("_id")-1)) { + if (!strncmp(string_key, "_id", sizeof("_id")-1)) { flags &= ~PHONGO_BSON_ADD_ID; } } - } else { - key_len = bson_uint32_to_string(index, (const char **)&key, numbuf, sizeof(numbuf)); } - phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, key, key_len, *entry TSRMLS_CC); + + /* Ensure we're working with a string key */ + if (hash_type == HASH_KEY_IS_LONG) { + spprintf(&string_key, 0, "%ld", num_key); + string_key_len = strlen(string_key); + } + + phongo_bson_append(bson, flags & ~PHONGO_BSON_ADD_ID, string_key, string_key_len, *value TSRMLS_CC); + + if (hash_type == HASH_KEY_IS_LONG) { + efree(string_key); + } } #endif diff --git a/tests/bson/bug0623.phpt b/tests/bson/bug0623.phpt new file mode 100644 index 000000000..b26f4e011 --- /dev/null +++ b/tests/bson/bug0623.phpt @@ -0,0 +1,52 @@ +--TEST-- +PHPC-623: Numeric keys limited to unsigned 32-bit integer +--SKIPIF-- + + +--INI-- +mongodb.debug=stderr +--FILE-- + 'a', + 'X9781449410247' => 'b', + 9781449410248 => 'c', + ], + [ + '4294967295' => 'a', + '4294967296' => 'b', + '4294967297' => 'c', + ] +]; + +foreach ($tests as $test) { + printf("Test %s\n", json_encode($test)); + $bson = fromPHP($test); + hex_dump($bson); + echo toJSON($bson), "\n\n"; +} + +?> +===DONE=== + +--EXPECTF-- +Test {"9781449410247":"a","X9781449410247":"b","9781449410248":"c"} + 0 : 45 00 00 00 02 39 37 38 31 34 34 39 34 31 30 32 [E....97814494102] + 10 : 34 37 00 02 00 00 00 61 00 02 58 39 37 38 31 34 [47.....a..X97814] + 20 : 34 39 34 31 30 32 34 37 00 02 00 00 00 62 00 02 [49410247.....b..] + 30 : 39 37 38 31 34 34 39 34 31 30 32 34 38 00 02 00 [9781449410248...] + 40 : 00 00 63 00 00 [..c..] +{ "9781449410247" : "a", "X9781449410247" : "b", "9781449410248" : "c" } + +Test {"4294967295":"a","4294967296":"b","4294967297":"c"} + 0 : 3b 00 00 00 02 34 32 39 34 39 36 37 32 39 35 00 [;....4294967295.] + 10 : 02 00 00 00 61 00 02 34 32 39 34 39 36 37 32 39 [....a..429496729] + 20 : 36 00 02 00 00 00 62 00 02 34 32 39 34 39 36 37 [6.....b..4294967] + 30 : 32 39 37 00 02 00 00 00 63 00 00 [297.....c..] +{ "4294967295" : "a", "4294967296" : "b", "4294967297" : "c" } + +===DONE===