1--TEST--
2Bug #78549: Stack overflow due to nested serialized input
3--FILE--
4<?php
5
6function create_nested_data($depth, $prefix, $suffix, $inner = 'i:0;') {
7    return str_repeat($prefix, $depth) . $inner . str_repeat($suffix, $depth);
8}
9
10echo "Invalid max_depth:\n";
11var_dump(unserialize('i:0;', ['max_depth' => 'foo']));
12var_dump(unserialize('i:0;', ['max_depth' => -1]));
13
14echo "Array:\n";
15var_dump(unserialize(
16    create_nested_data(128, 'a:1:{i:0;', '}'),
17    ['max_depth' => 128]
18) !== false);
19var_dump(unserialize(
20    create_nested_data(129, 'a:1:{i:0;', '}'),
21    ['max_depth' => 128]
22));
23
24echo "Object:\n";
25var_dump(unserialize(
26    create_nested_data(128, 'O:8:"stdClass":1:{i:0;', '}'),
27    ['max_depth' => 128]
28) !== false);
29var_dump(unserialize(
30    create_nested_data(129, 'O:8:"stdClass":1:{i:0;', '}'),
31    ['max_depth' => 128]
32));
33
34// Depth can also be adjusted using ini setting
35echo "Ini setting:\n";
36ini_set("unserialize_max_depth", 128);
37var_dump(unserialize(create_nested_data(128, 'a:1:{i:0;', '}')) !== false);
38var_dump(unserialize(create_nested_data(129, 'a:1:{i:0;', '}')));
39
40// But an explicitly specified depth still takes precedence
41echo "Ini setting overridden:\n";
42var_dump(unserialize(
43    create_nested_data(256, 'a:1:{i:0;', '}'),
44    ['max_depth' => 256]
45) !== false);
46var_dump(unserialize(
47    create_nested_data(257, 'a:1:{i:0;', '}'),
48    ['max_depth' => 256]
49));
50
51// Reset ini setting to a large value,
52// so it's clear that it won't be used in the following.
53ini_set("unserialize_max_depth", 4096);
54
55class Test implements Serializable {
56    public function serialize() {
57        return '';
58    }
59    public function unserialize($str) {
60        // Should fail, due to combined nesting level
61        var_dump(unserialize(create_nested_data(129, 'a:1:{i:0;', '}')));
62        // Should succeeed, below combined nesting level
63        var_dump(unserialize(create_nested_data(128, 'a:1:{i:0;', '}')) !== false);
64    }
65}
66echo "Nested unserialize combined depth limit:\n";
67var_dump(is_array(unserialize(
68    create_nested_data(128, 'a:1:{i:0;', '}', 'C:4:"Test":0:{}'),
69    ['max_depth' => 256]
70)));
71
72class Test2 implements Serializable {
73    public function serialize() {
74        return '';
75    }
76    public function unserialize($str) {
77        // If depth limit is overridden, the depth should be counted
78        // from zero again.
79        var_dump(unserialize(
80            create_nested_data(257, 'a:1:{i:0;', '}'),
81            ['max_depth' => 256]
82        ));
83        var_dump(unserialize(
84            create_nested_data(256, 'a:1:{i:0;', '}'),
85            ['max_depth' => 256]
86        ) !== false);
87    }
88}
89echo "Nested unserialize overridden depth limit:\n";
90var_dump(is_array(unserialize(
91    create_nested_data(64, 'a:1:{i:0;', '}', 'C:5:"Test2":0:{}'),
92    ['max_depth' => 128]
93)));
94
95?>
96--EXPECTF--
97Invalid max_depth:
98
99Warning: unserialize(): max_depth should be int in %s on line %d
100bool(false)
101
102Warning: unserialize(): max_depth cannot be negative in %s on line %d
103bool(false)
104Array:
105bool(true)
106
107Warning: unserialize(): Maximum depth of 128 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
108
109Notice: unserialize(): Error at offset 1157 of 1294 bytes in %s on line %d
110bool(false)
111Object:
112bool(true)
113
114Warning: unserialize(): Maximum depth of 128 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
115
116Notice: unserialize(): Error at offset 2834 of 2971 bytes in %s on line %d
117bool(false)
118Ini setting:
119bool(true)
120
121Warning: unserialize(): Maximum depth of 128 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
122
123Notice: unserialize(): Error at offset 1157 of 1294 bytes in %s on line %d
124bool(false)
125Ini setting overridden:
126bool(true)
127
128Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
129
130Notice: unserialize(): Error at offset 2309 of 2574 bytes in %s on line %d
131bool(false)
132Nested unserialize combined depth limit:
133
134Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
135
136Notice: unserialize(): Error at offset 1157 of 1294 bytes in %s on line %d
137bool(false)
138bool(true)
139bool(true)
140Nested unserialize overridden depth limit:
141
142Warning: unserialize(): Maximum depth of 256 exceeded. The depth limit can be changed using the max_depth unserialize() option or the unserialize_max_depth ini setting in %s on line %d
143
144Notice: unserialize(): Error at offset 2309 of 2574 bytes in %s on line %d
145bool(false)
146bool(true)
147bool(true)
148