Skip to content

Commit 479825b

Browse files
committed
Avoid bailout in pattern matching
1 parent b3a15ec commit 479825b

File tree

3 files changed

+50
-61
lines changed

3 files changed

+50
-61
lines changed

Zend/zend_execute_API.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ void init_executor(void) /* {{{ */
198198

199199
EG(filename_override) = NULL;
200200
EG(lineno_override) = -1;
201-
EG(pattern_matching_bailout) = false;
202201

203202
zend_max_execution_timer_init();
204203
zend_fiber_init();

Zend/zend_globals.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,6 @@ struct _zend_executor_globals {
304304
struct sigaction oldact;
305305
#endif
306306

307-
/* Whether the last bailout was triggered while pattern matching */
308-
bool pattern_matching_bailout;
309-
310307
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
311308
};
312309

Zend/zend_pattern_matching.c

Lines changed: 50 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,38 @@
2020
#include "zend_exceptions.h"
2121
#include "zend_type_info.h"
2222

23-
bool zend_pattern_match_ex(zval *zv, zend_ast *pattern);
23+
typedef enum {
24+
PM_ERROR = -1,
25+
PM_MISMATCH = 0,
26+
PM_MATCH = 1,
27+
} pm_result;
2428

25-
static bool match_type(zval *zv, zend_ast *type_ast)
29+
pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern);
30+
31+
static pm_result match_type(zval *zv, zend_ast *type_ast)
2632
{
2733
zend_ast *class_name_ast = type_ast->child[0];
2834
if (class_name_ast) {
2935
if (Z_TYPE_P(zv) != IS_OBJECT) {
30-
return false;
36+
return PM_MISMATCH;
3137
}
3238

3339
zend_object *obj = Z_OBJ_P(zv);
3440
zend_string *class_name = zend_ast_get_str(class_name_ast);
3541
if (!zend_string_equals_ci(obj->ce->name, class_name)) {
3642
zend_class_entry *expected_class = zend_lookup_class_ex(class_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
3743
if (!expected_class || !instanceof_function(Z_OBJ_P(zv)->ce, expected_class)) {
38-
return false;
44+
return PM_MISMATCH;
3945
}
4046
}
4147
} else {
4248
zend_type type = ZEND_TYPE_INIT_MASK(type_ast->attr);
4349
if (!ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE_P(zv))) {
44-
return false;
50+
return PM_MISMATCH;
4551
}
4652
}
4753

48-
return true;
49-
}
50-
51-
static bool pattern_matching_bailout(void)
52-
{
53-
EG(pattern_matching_bailout) = true;
54-
zend_bailout();
54+
return PM_MATCH;
5555
}
5656

5757
static bool match_zval(zval *lhs, zval *rhs)
@@ -68,26 +68,26 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
6868
scope = zend_get_executed_scope();
6969
if (UNEXPECTED(!scope)) {
7070
zend_throw_error(NULL, "%s", "Cannot access \"self\" when no class scope is active");
71-
pattern_matching_bailout();
71+
return NULL;
7272
}
7373
return scope;
7474
case ZEND_FETCH_CLASS_PARENT:
7575
scope = zend_get_executed_scope();
7676
if (UNEXPECTED(!scope)) {
7777
zend_throw_error(NULL, "%s", "Cannot access \"parent\" when no class scope is active");
78-
pattern_matching_bailout();
78+
return NULL;
7979
}
8080
scope = scope->parent;
8181
if (UNEXPECTED(!scope)) {
8282
zend_throw_error(NULL, "%s", "Cannot access \"parent\" when current class scope has no parent");
83-
pattern_matching_bailout();
83+
return NULL;
8484
}
8585
return scope;
8686
case ZEND_FETCH_CLASS_STATIC:
8787
scope = zend_get_called_scope(EG(current_execute_data));
8888
if (UNEXPECTED(!scope)) {
8989
zend_throw_error(NULL, "%s", "Cannot access \"static\" when no class scope is active");
90-
pattern_matching_bailout();
90+
return NULL;
9191
}
9292
return scope;
9393
EMPTY_SWITCH_DEFAULT_CASE();
@@ -96,28 +96,31 @@ static zend_class_entry *get_class_from_fetch_type(uint32_t fetch_type)
9696
return NULL;
9797
}
9898

99-
static bool match_object(zval *zv, zend_ast *pattern)
99+
static pm_result match_object(zval *zv, zend_ast *pattern)
100100
{
101101
if (Z_TYPE_P(zv) != IS_OBJECT) {
102-
return false;
102+
return PM_MISMATCH;
103103
}
104104

105105
zend_object *obj = Z_OBJ_P(zv);
106106
zend_ast *class_name_ast = pattern->child[0];
107-
107+
108108
if (class_name_ast) {
109109
zend_string *class_name = zend_ast_get_str(class_name_ast);
110110
if (!zend_string_equals_ci(obj->ce->name, class_name)) {
111111
zend_class_entry *expected_class = zend_lookup_class_ex(class_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
112112
if (!expected_class || !instanceof_function(Z_OBJ_P(zv)->ce, expected_class)) {
113-
return false;
113+
return PM_MISMATCH;
114114
}
115115
}
116116
} else {
117117
uint32_t fetch_type = pattern->attr;
118118
zend_class_entry *scope = get_class_from_fetch_type(fetch_type);
119+
if (EG(exception)) {
120+
return PM_ERROR;
121+
}
119122
if (!instanceof_function(Z_OBJ_P(zv)->ce, scope)) {
120-
return false;
123+
return PM_MISMATCH;
121124
}
122125
}
123126

@@ -129,40 +132,40 @@ static bool match_object(zval *zv, zend_ast *pattern)
129132
zend_string *property_name = zend_ast_get_str(property_or_method_call);
130133
zval property_result_rv;
131134
zval *property_result = obj->handlers->read_property(obj, property_name, BP_VAR_R, NULL, &property_result_rv);
132-
bool element_matched = zend_pattern_match_ex(property_result, element_pattern);
135+
pm_result element_matched = zend_pattern_match_ex(property_result, element_pattern);
133136
if (property_result == &property_result_rv) {
134137
zval_ptr_dtor(property_result);
135138
}
136-
if (!element_matched) {
137-
return false;
139+
if (element_matched != PM_MATCH) {
140+
return element_matched;
138141
}
139142
}
140143

141-
return true;
144+
return PM_MATCH;
142145
}
143146

144-
static bool match_range(zval *zv, zend_ast *pattern)
147+
static pm_result match_range(zval *zv, zend_ast *pattern)
145148
{
146149
zval *start = zend_ast_get_zval(pattern->child[0]);
147150
zval *end = zend_ast_get_zval(pattern->child[1]);
148151

149152
if (Z_TYPE_P(zv) != Z_TYPE_P(start) && zend_compare(zv, start) == -1) {
150-
return false;
153+
return PM_MISMATCH;
151154
}
152155

153156
int end_check = zend_compare(zv, end);
154157
if (Z_TYPE_P(zv) != Z_TYPE_P(end) || end_check == 1 || (!(pattern->attr & ZEND_AST_RANGE_INCLUSIVE_END) && end_check == 0)) {
155-
return false;
158+
return PM_MISMATCH;
156159
}
157160

158-
return true;
161+
return PM_MATCH;
159162
}
160163

161-
static bool match_binding(zval *zv, zend_ast *pattern)
164+
static pm_result match_binding(zval *zv, zend_ast *pattern)
162165
{
163166
zend_ast *sub_pattern = pattern->child[1];
164167
if (sub_pattern && !zend_pattern_match_ex(zv, sub_pattern)) {
165-
return false;
168+
return PM_MISMATCH;
166169
}
167170

168171
// FIXME: Delay to the end of pattern matching
@@ -172,22 +175,22 @@ static bool match_binding(zval *zv, zend_ast *pattern)
172175
zend_assign_to_variable(cv, zv, IS_CV, EX_USES_STRICT_TYPES());
173176
/* Destructor might throw */
174177
if (EG(exception)) {
175-
pattern_matching_bailout();
178+
return PM_ERROR;
176179
}
177-
return true;
180+
return PM_MATCH;
178181
}
179182

180-
static bool match_array(zval *zv, zend_ast *pattern)
183+
static pm_result match_array(zval *zv, zend_ast *pattern)
181184
{
182185
if (Z_TYPE_P(zv) != IS_ARRAY) {
183-
return false;
186+
return PM_MISMATCH;
184187
}
185188

186189
HashTable *ht = Z_ARRVAL_P(zv);
187190
zend_ast_list *element_list = zend_ast_get_list(pattern->child[0]);
188191

189192
if (!(pattern->attr & ZEND_ARRAY_PATTERN_NON_EXHAUSTIVE) && element_list->children != zend_hash_num_elements(ht)) {
190-
return false;
193+
return PM_MISMATCH;
191194
}
192195

193196
// FIXME: Deal with indexes properly
@@ -211,14 +214,14 @@ static bool match_array(zval *zv, zend_ast *pattern)
211214
index++;
212215
}
213216
if (Z_TYPE_P(element_zv) == IS_UNDEF || !zend_pattern_match_ex(element_zv, pattern_ast)) {
214-
return false;
217+
return PM_MISMATCH;
215218
}
216219
}
217220

218-
return true;
221+
return PM_MATCH;
219222
}
220223

221-
bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
224+
pm_result zend_pattern_match_ex(zval *zv, zend_ast *pattern)
222225
{
223226
ZVAL_DEREF(zv);
224227
// FIXME: Do we need DEINDIRECT too?
@@ -231,10 +234,13 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
231234
case ZEND_AST_OBJECT_PATTERN:
232235
return match_object(zv, pattern);
233236
case ZEND_AST_WILDCARD_PATTERN:
234-
return true;
235-
case ZEND_AST_OR_PATTERN:
236-
return zend_pattern_match_ex(zv, pattern->child[0])
237-
|| zend_pattern_match_ex(zv, pattern->child[1]);
237+
return PM_MATCH;
238+
case ZEND_AST_OR_PATTERN:;
239+
pm_result lhs = zend_pattern_match_ex(zv, pattern->child[0]);
240+
if (lhs != PM_MISMATCH) {
241+
return lhs;
242+
}
243+
return zend_pattern_match_ex(zv, pattern->child[1]);
238244
case ZEND_AST_RANGE_PATTERN:
239245
return match_range(zv, pattern);
240246
case ZEND_AST_BINDING_PATTERN:
@@ -247,18 +253,5 @@ bool zend_pattern_match_ex(zval *zv, zend_ast *pattern)
247253

248254
bool zend_pattern_match(zval *zv, zend_ast *pattern)
249255
{
250-
bool result;
251-
252-
zend_first_try {
253-
result = zend_pattern_match_ex(zv, pattern);
254-
} zend_catch {
255-
if (!EG(pattern_matching_bailout)) {
256-
zend_bailout();
257-
}
258-
ZEND_ASSERT(EG(exception));
259-
EG(pattern_matching_bailout) = false;
260-
return false;
261-
} zend_end_try();
262-
263-
return result;
256+
return zend_pattern_match_ex(zv, pattern) == PM_MATCH;
264257
}

0 commit comments

Comments
 (0)