From 03da5f8e30cc65584d38d478ea566062ff99579b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 29 Nov 2017 19:00:57 +0300 Subject: [PATCH] Try to intern unserualized string keys --- ext/standard/var_unserializer.c | 128 ++++++++++++++++--------------- ext/standard/var_unserializer.re | 64 ++++++++-------- 2 files changed, 100 insertions(+), 92 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 34140a2bb2..42be189874 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -389,7 +389,7 @@ static inline size_t parse_uiv(const unsigned char *p) #define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER); +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key); static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { @@ -399,7 +399,7 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab ZVAL_UNDEF(&key); - if (!php_var_unserialize_internal(&key, p, max, NULL)) { + if (!php_var_unserialize_internal(&key, p, max, NULL, 1)) { zval_ptr_dtor(&key); return 0; } @@ -438,7 +438,7 @@ numeric_key: string_key: { zend_property_info *existing_propinfo; - zend_string *new_key, *unmangled; + zend_string *new_key; const char *unmangled_class = NULL; const char *unmangled_prop; size_t unmangled_prop_len; @@ -448,35 +448,37 @@ string_key: return 0; } - unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); - if (Z_TYPE_P(rval) == IS_OBJECT - && ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) - && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { - if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { - new_key = zend_mangle_property_name( - "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0); - zend_string_release(unmangled); - } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { - if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { + if (Z_TYPE_P(rval) == IS_OBJECT) { + zend_string *unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); + + if (((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) + && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { + if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { new_key = zend_mangle_property_name( - unmangled_class, strlen(unmangled_class), - ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - 0); + "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0); + zend_string_release(unmangled); + } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { + if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { + new_key = zend_mangle_property_name( + unmangled_class, strlen(unmangled_class), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + 0); + } else { + new_key = zend_mangle_property_name( + ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + 0); + } + zend_string_release(unmangled); } else { - new_key = zend_mangle_property_name( - ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), - ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - 0); + ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); + new_key = unmangled; } - zend_string_release(unmangled); + zend_string_release(Z_STR(key)); + ZVAL_STR(&key, new_key); } else { - ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); - new_key = unmangled; + zend_string_release(unmangled); } - zend_string_release(Z_STR(key)); - ZVAL_STR(&key, new_key); - } else { - zend_string_release(unmangled); } if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { @@ -499,7 +501,7 @@ string_key: } } - if (!php_var_unserialize_internal(data, p, max, var_hash)) { + if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) { zval_ptr_dtor(&key); return 0; } @@ -625,7 +627,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0; int result; - result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU); + result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU, 0); if (!result) { /* If the unserialization failed, mark all elements that have been added to var_hash @@ -646,7 +648,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return result; } -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -665,7 +667,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) start = cursor; -#line 669 "ext/standard/var_unserializer.c" +#line 671 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -723,9 +725,9 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) yy2: ++YYCURSOR; yy3: -#line 1066 "ext/standard/var_unserializer.re" +#line 1070 "ext/standard/var_unserializer.re" { return 0; } -#line 729 "ext/standard/var_unserializer.c" +#line 731 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy17; @@ -772,13 +774,13 @@ yy14: goto yy3; yy15: ++YYCURSOR; -#line 1060 "ext/standard/var_unserializer.re" +#line 1064 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 782 "ext/standard/var_unserializer.c" +#line 784 "ext/standard/var_unserializer.c" yy17: yych = *++YYCURSOR; if (yybm[0+yych] & 128) { @@ -789,13 +791,13 @@ yy18: goto yy3; yy19: ++YYCURSOR; -#line 723 "ext/standard/var_unserializer.re" +#line 725 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 799 "ext/standard/var_unserializer.c" +#line 801 "ext/standard/var_unserializer.c" yy21: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -999,7 +1001,7 @@ yy56: goto yy18; yy57: ++YYCURSOR; -#line 673 "ext/standard/var_unserializer.re" +#line 675 "ext/standard/var_unserializer.re" { zend_long id; @@ -1024,7 +1026,7 @@ yy57: return 1; } -#line 1028 "ext/standard/var_unserializer.c" +#line 1030 "ext/standard/var_unserializer.c" yy59: yych = *++YYCURSOR; if (yych == '"') goto yy80; @@ -1035,22 +1037,22 @@ yy60: goto yy18; yy61: ++YYCURSOR; -#line 729 "ext/standard/var_unserializer.re" +#line 731 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_FALSE(rval); return 1; } -#line 1045 "ext/standard/var_unserializer.c" +#line 1047 "ext/standard/var_unserializer.c" yy63: ++YYCURSOR; -#line 735 "ext/standard/var_unserializer.re" +#line 737 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_TRUE(rval); return 1; } -#line 1054 "ext/standard/var_unserializer.c" +#line 1056 "ext/standard/var_unserializer.c" yy65: ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); @@ -1070,7 +1072,7 @@ yy65: } yy67: ++YYCURSOR; -#line 783 "ext/standard/var_unserializer.re" +#line 785 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 use_double: @@ -1079,7 +1081,7 @@ use_double: ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1083 "ext/standard/var_unserializer.c" +#line 1085 "ext/standard/var_unserializer.c" yy69: yych = *++YYCURSOR; if (yych <= ',') { @@ -1101,7 +1103,7 @@ yy71: goto yy18; yy72: ++YYCURSOR; -#line 741 "ext/standard/var_unserializer.re" +#line 743 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1127,14 +1129,14 @@ yy72: ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1131 "ext/standard/var_unserializer.c" +#line 1133 "ext/standard/var_unserializer.c" yy74: yych = *++YYCURSOR; if (yych == '"') goto yy88; goto yy18; yy75: ++YYCURSOR; -#line 698 "ext/standard/var_unserializer.re" +#line 700 "ext/standard/var_unserializer.re" { zend_long id; @@ -1159,14 +1161,14 @@ yy75: return 1; } -#line 1163 "ext/standard/var_unserializer.c" +#line 1165 "ext/standard/var_unserializer.c" yy77: yych = *++YYCURSOR; if (yych == '"') goto yy90; goto yy18; yy78: ++YYCURSOR; -#line 908 "ext/standard/var_unserializer.re" +#line 912 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; zend_long elements; @@ -1318,10 +1320,10 @@ yy78: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1322 "ext/standard/var_unserializer.c" +#line 1324 "ext/standard/var_unserializer.c" yy80: ++YYCURSOR; -#line 830 "ext/standard/var_unserializer.re" +#line 834 "ext/standard/var_unserializer.re" { size_t len, maxlen; zend_string *str; @@ -1355,10 +1357,10 @@ yy80: ZVAL_STR(rval, str); return 1; } -#line 1359 "ext/standard/var_unserializer.c" +#line 1361 "ext/standard/var_unserializer.c" yy82: ++YYCURSOR; -#line 864 "ext/standard/var_unserializer.re" +#line 868 "ext/standard/var_unserializer.re" { zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -1391,7 +1393,7 @@ yy82: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 1395 "ext/standard/var_unserializer.c" +#line 1397 "ext/standard/var_unserializer.c" yy84: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1410,7 +1412,7 @@ yy87: goto yy18; yy88: ++YYCURSOR; -#line 897 "ext/standard/var_unserializer.re" +#line 901 "ext/standard/var_unserializer.re" { zend_long elements; if (!var_hash) return 0; @@ -1421,10 +1423,10 @@ yy88: } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1425 "ext/standard/var_unserializer.c" +#line 1427 "ext/standard/var_unserializer.c" yy90: ++YYCURSOR; -#line 792 "ext/standard/var_unserializer.re" +#line 794 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -1457,15 +1459,17 @@ yy90: ZVAL_EMPTY_STRING(rval); } else if (len == 1) { ZVAL_INTERNED_STR(rval, ZSTR_CHAR((zend_uchar)*str)); + } else if (as_key) { + ZVAL_STR(rval, zend_string_init_interned(str, len, 0)); } else { ZVAL_STRINGL(rval, str, len); } return 1; } -#line 1466 "ext/standard/var_unserializer.c" +#line 1470 "ext/standard/var_unserializer.c" yy92: ++YYCURSOR; -#line 767 "ext/standard/var_unserializer.re" +#line 769 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1481,9 +1485,9 @@ yy92: return 1; } -#line 1485 "ext/standard/var_unserializer.c" +#line 1489 "ext/standard/var_unserializer.c" } -#line 1068 "ext/standard/var_unserializer.re" +#line 1072 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 86d3502746..6c9c36fec0 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -393,7 +393,7 @@ static inline size_t parse_uiv(const unsigned char *p) #define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER); +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key); static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { @@ -403,7 +403,7 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab ZVAL_UNDEF(&key); - if (!php_var_unserialize_internal(&key, p, max, NULL)) { + if (!php_var_unserialize_internal(&key, p, max, NULL, 1)) { zval_ptr_dtor(&key); return 0; } @@ -442,7 +442,7 @@ numeric_key: string_key: { zend_property_info *existing_propinfo; - zend_string *new_key, *unmangled; + zend_string *new_key; const char *unmangled_class = NULL; const char *unmangled_prop; size_t unmangled_prop_len; @@ -452,35 +452,37 @@ string_key: return 0; } - unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); - if (Z_TYPE_P(rval) == IS_OBJECT - && ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) - && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { - if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { - new_key = zend_mangle_property_name( - "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0); - zend_string_release(unmangled); - } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { - if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { + if (Z_TYPE_P(rval) == IS_OBJECT) { + zend_string *unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); + + if (((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) + && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { + if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { new_key = zend_mangle_property_name( - unmangled_class, strlen(unmangled_class), - ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - 0); + "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0); + zend_string_release(unmangled); + } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { + if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { + new_key = zend_mangle_property_name( + unmangled_class, strlen(unmangled_class), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + 0); + } else { + new_key = zend_mangle_property_name( + ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + 0); + } + zend_string_release(unmangled); } else { - new_key = zend_mangle_property_name( - ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), - ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - 0); + ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); + new_key = unmangled; } - zend_string_release(unmangled); + zend_string_release(Z_STR(key)); + ZVAL_STR(&key, new_key); } else { - ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); - new_key = unmangled; + zend_string_release(unmangled); } - zend_string_release(Z_STR(key)); - ZVAL_STR(&key, new_key); - } else { - zend_string_release(unmangled); } if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { @@ -503,7 +505,7 @@ string_key: } } - if (!php_var_unserialize_internal(data, p, max, var_hash)) { + if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) { zval_ptr_dtor(&key); return 0; } @@ -629,7 +631,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0; int result; - result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU); + result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU, 0); if (!result) { /* If the unserialization failed, mark all elements that have been added to var_hash @@ -650,7 +652,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return result; } -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -821,6 +823,8 @@ use_double: ZVAL_EMPTY_STRING(rval); } else if (len == 1) { ZVAL_INTERNED_STR(rval, ZSTR_CHAR((zend_uchar)*str)); + } else if (as_key) { + ZVAL_STR(rval, zend_string_init_interned(str, len, 0)); } else { ZVAL_STRINGL(rval, str, len); } -- 2.40.0