Skip to content
This repository was archived by the owner on May 27, 2022. It is now read-only.

Commit 33a1a98

Browse files
committed
Use a string index count instead of hash size as string ids.
The string serailizers (object name and string) assigned strings ids based on the duplicate strings hash size. Because compact_strings only applies to strings and not objects the string index could go out of sync. During deserialization object name id:s incorrectly back reference to normal strings, causing creation of "incomplete classes" etc.
1 parent 8f41c07 commit 33a1a98

File tree

2 files changed

+68
-5
lines changed

2 files changed

+68
-5
lines changed

igbinary.c

+10-5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct igbinary_serialize_data {
9898
bool compact_strings; /**< Check for duplicate strings. */
9999
struct hash_si strings; /**< Hash of already serialized strings. */
100100
struct hash_si objects; /**< Hash of already serialized objects. */
101+
int string_count; /**< Serialized string count, used for back referencing */
101102
int error; /**< Error number. Not used. */
102103
};
103104

@@ -464,6 +465,7 @@ inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *i
464465
igsd->buffer = NULL;
465466
igsd->buffer_size = 0;
466467
igsd->buffer_capacity = 32;
468+
igsd->string_count = 0;
467469
igsd->error = 0;
468470

469471
igsd->buffer = (uint8_t *) emalloc(igsd->buffer_capacity);
@@ -669,11 +671,14 @@ inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd
669671

670672
if (igsd->scalar || !igsd->compact_strings || hash_si_find(&igsd->strings, s, len, i) == 1) {
671673
if (!igsd->scalar && igsd->compact_strings) {
672-
t = hash_si_size(&igsd->strings);
673-
hash_si_insert(&igsd->strings, s, len, t);
674+
hash_si_insert(&igsd->strings, s, len, igsd->string_count);
674675
}
675676

676-
igbinary_serialize_chararray(igsd, s, len TSRMLS_CC);
677+
igsd->string_count += 1;
678+
679+
if (igbinary_serialize_chararray(igsd, s, len TSRMLS_CC) != 0) {
680+
return 1;
681+
}
677682
} else {
678683
if (*i <= 0xff) {
679684
igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id8 TSRMLS_CC);
@@ -964,8 +969,8 @@ inline static int igbinary_serialize_object_name(struct igbinary_serialize_data
964969
uint32_t *i = &t;
965970

966971
if (hash_si_find(&igsd->strings, class_name, name_len, i) == 1) {
967-
t = hash_si_size(&igsd->strings);
968-
hash_si_insert(&igsd->strings, class_name, name_len, t);
972+
hash_si_insert(&igsd->strings, class_name, name_len, igsd->string_count);
973+
igsd->string_count += 1;
969974

970975
if (name_len <= 0xff) {
971976
igbinary_serialize8(igsd, (uint8_t) igbinary_type_object8 TSRMLS_CC);

tests/043.phpt

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Object serialization with compact strings
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("igbinary")) {
6+
print "skip";
7+
}
8+
?>
9+
--INI--
10+
igbinary.compact_strings=Off
11+
--FILE--
12+
<?php
13+
class Foo {
14+
}
15+
16+
class Bar {
17+
}
18+
19+
20+
$expected_array = array();
21+
for ($i = 0; $i < 10; $i++) {
22+
$expected_array['foo_' . $i] = new Foo;
23+
$expected_array['bar_' . $i] = new Bar;
24+
}
25+
26+
$actual_array = igbinary_unserialize(igbinary_serialize($expected_array));
27+
28+
$error = 'OK';
29+
30+
foreach ($expected_array as $key => $object) {
31+
if (!isset($actual_array[$key])) {
32+
$error = 'ERROR';
33+
echo "Key $key is missing from result.\n";
34+
echo "Expected key/value:\n";
35+
var_dump($key, $object);
36+
var_dump($object);
37+
38+
break;
39+
}
40+
41+
if (!is_object($actual_array[$key]) ||
42+
get_class($object) !== get_class($actual_array[$key])) {
43+
$error = 'ERROR';
44+
echo "Array mismatch on $key\n";
45+
echo "Expected key/value:\n";
46+
var_dump($key, $object);
47+
echo "Actual key/value:\n";
48+
var_dump($key, $actual_array[$key]);
49+
50+
break;
51+
}
52+
53+
}
54+
55+
echo $error, "\n";
56+
57+
--EXPECT--
58+
OK

0 commit comments

Comments
 (0)