• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

krakjoe / uopz / 11991226253

23 Nov 2024 11:24PM UTC coverage: 95.502%. Remained the same
11991226253

Pull #185

github

web-flow
Merge 238b04d08 into dcb01f128
Pull Request #185: Support `exit()` function in PHP 8.4

913 of 956 relevant lines covered (95.5%)

11626.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.3
/src/function.c
1
/*
2
  +----------------------------------------------------------------------+
3
  | uopz                                                                 |
4
  +----------------------------------------------------------------------+
5
  | Copyright (c) Joe Watkins 2016-2021                                  |
6
  +----------------------------------------------------------------------+
7
  | This source file is subject to version 3.01 of the PHP license,      |
8
  | that is bundled with this package in the file LICENSE, and is        |
9
  | available through the world-wide-web at the following url:           |
10
  | http://www.php.net/license/3_01.txt                                  |
11
  | If you did not receive a copy of the PHP license and are unable to   |
12
  | obtain it through the world-wide-web, please send a note to          |
13
  | license@php.net so we can mail you a copy immediately.               |
14
  +----------------------------------------------------------------------+
15
  | Author: Joe Watkins <krakjoe@php.net>                                |
16
  +----------------------------------------------------------------------+
17
 */
18

19
#ifndef UOPZ_FUNCTION
20
#define UOPZ_FUNCTION
21

22
#include "php.h"
23
#include "uopz.h"
24

25
#include "util.h"
26
#include "function.h"
27

28
#include <Zend/zend_closures.h>
29

30
ZEND_EXTERN_MODULE_GLOBALS(uopz);
31

32
static zend_function* uopz_copy_function(zend_class_entry *scope, zend_string *name, zend_object *closure, zend_long flags) { /* {{{ */
260✔
33
        zend_function  *copy = (zend_function*) zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
260✔
34

35
        memcpy(copy, zend_get_closure_method_def(closure), sizeof(zend_op_array));
260✔
36

37
        copy->op_array.fn_flags &= ~ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE|ZEND_ACC_ARENA_ALLOCATED;
260✔
38

39
        copy->op_array.function_name = zend_string_copy(name);
260✔
40

41
        copy->op_array.scope = scope;
260✔
42

43
        if (flags & ZEND_ACC_PPP_MASK) {
260✔
44
                copy->op_array.fn_flags &= ~ZEND_ACC_PPP_MASK;
240✔
45
                copy->op_array.fn_flags |= flags & ZEND_ACC_PPP_MASK;
240✔
46
        } else {
47
                copy->op_array.fn_flags |= ZEND_ACC_PUBLIC;
20✔
48
        }
49

50
        if (flags & ZEND_ACC_STATIC) {
260✔
51
                copy->op_array.fn_flags |= ZEND_ACC_STATIC;
20✔
52
        }
53

54
        if (copy->op_array.static_variables) {
260✔
55
                copy->op_array.static_variables = zend_array_dup(copy->op_array.static_variables);
20✔
56

57
#if PHP_VERSION_ID >= 80200
58
                ZEND_MAP_PTR_INIT(
12✔
59
                        copy->op_array.static_variables_ptr, copy->op_array.static_variables);
60
#else
61
                ZEND_MAP_PTR_INIT(
8✔
62
                        copy->op_array.static_variables_ptr, &copy->op_array.static_variables);
63
#endif
64
        } else {
65
                ZEND_MAP_PTR_INIT(copy->op_array.static_variables_ptr, NULL);
240✔
66
        }
67

68
        if (copy->op_array.refcount) {
260✔
69
                (*copy->op_array.refcount)++;
260✔
70
        }
71
        copy->op_array.fn_flags |= ZEND_ACC_UOPZ;
260✔
72

73
        return copy;
260✔
74
} /* }}} */
75

76
zend_bool uopz_add_function(zend_class_entry *clazz, zend_string *name, zval *closure, zend_long flags, zend_bool all) { /* {{{ */
300✔
77
        HashTable *table = clazz ? &clazz->function_table : CG(function_table);
300✔
78
        zend_string *key;
150✔
79
        zend_function *function = NULL;
300✔
80

81
        if (clazz && clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
300✔
82
                uopz_exception(
×
83
                        "cannot add method %s::%s to immutable class, use uopz_set_return instead",
84
                        ZSTR_VAL(clazz->name),
85
                        ZSTR_VAL(name));
86
                return 0;
×
87
        }
88

89
        key = zend_string_tolower(name);
300✔
90
        key = zend_new_interned_string(key);
300✔
91

92
        if (zend_hash_exists(table, key)) {
300✔
93
                if (clazz) {
40✔
94
                        uopz_exception(
20✔
95
                                "will not replace existing method %s::%s, use uopz_set_return instead",
96
                                ZSTR_VAL(clazz->name),
97
                                ZSTR_VAL(name));
98
                } else {
99
                        uopz_exception(
20✔
100
                                "will not replace existing function %s, use uopz_set_return instead",
101
                                ZSTR_VAL(name));
102
                }
103
                zend_string_release(key);
40✔
104
                return 0;
40✔
105
        }
106

107
        function = uopz_copy_function(clazz, name, Z_OBJ_P(closure), flags);
260✔
108
        zend_hash_update_ptr(table, key, (void*) function);
260✔
109

110
        if (clazz) {
260✔
111
                if (all) {
240✔
112
                        zend_class_entry *next;
120✔
113

114
                        ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
32,976✔
115
                                if (next->parent == clazz) {
32,736✔
116
                                        if (zend_hash_exists(&next->function_table, key)) {
×
117
                                                continue;
×
118
                                        }
119
                                        uopz_add_function(next, name, closure, flags, all);
×
120
                                }
121
                        } ZEND_HASH_FOREACH_END();
122
                }
123

124
                uopz_handle_magic(clazz, name, function);
240✔
125
        }
126

127
        zend_string_release(key);
260✔
128

129
        return 1;
130✔
130
} /* }}} */
131

132
zend_bool uopz_del_function(zend_class_entry *clazz, zend_string *name, zend_bool all) { /* {{{ */
100✔
133
        HashTable *table = clazz ? &clazz->function_table : CG(function_table);
100✔
134
        zend_string *key = zend_string_tolower(name);
100✔
135
        zend_function *function = zend_hash_find_ptr(table, key);
100✔
136
        
137
        if (!function) {
80✔
138
                if (clazz) {
40✔
139
                        uopz_exception(
20✔
140
                                "cannot delete method %s::%s, it does not exist",
141
                                ZSTR_VAL(clazz->name),
142
                                ZSTR_VAL(name));
143
                } else {
144
                        uopz_exception(
20✔
145
                                "cannot delete function %s, it does not exist",
146
                                ZSTR_VAL(name));
147
                }
148
                zend_string_release(key);
40✔
149
                return 0;
40✔
150
        }
151
        
152
        if (!(function->common.fn_flags & ZEND_ACC_UOPZ)) {
60✔
153
                if (clazz) {
40✔
154
                        uopz_exception(
20✔
155
                                "cannot delete method %s::%s, it was not added by uopz",
156
                                ZSTR_VAL(clazz->name),
157
                                ZSTR_VAL(name));
158
                } else {
159
                        uopz_exception(
20✔
160
                                "cannot delete function %s, it was not added by uopz",
161
                                ZSTR_VAL(name));
162
                }
163
                zend_string_release(key);
40✔
164
                return 0;
40✔
165
        }
166
        
167
        if (clazz && all) {
20✔
168
                zend_class_entry *next;
10✔
169

170
                ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
2,748✔
171
                        if (next->parent == clazz) {
2,728✔
172
                                if (!zend_hash_exists(&next->function_table, key)) {
×
173
                                        continue;
×
174
                                }
175
                                uopz_del_function(next, name, all);
×
176
                        }
177
                } ZEND_HASH_FOREACH_END();
178
        }
179

180
        zend_hash_del(table, key);
20✔
181
        zend_string_release(key);
20✔
182

183
        return 1;
10✔
184
} /* }}} */
185

186
/* {{{ */
187
void uopz_flags(zend_class_entry *clazz, zend_string *name, zend_long flags, zval *return_value) {
180✔
188
        HashTable *table = clazz ? &clazz->function_table : CG(function_table);
180✔
189
        zend_long current = 0;
180✔
190

191
        if (clazz && (!name || !ZSTR_LEN(name))) {
180✔
192
                if (flags == ZEND_LONG_MAX) {
80✔
193
                        RETURN_LONG(clazz->ce_flags);
20✔
194
                }
195

196
                if (flags & ZEND_ACC_PPP_MASK) {
60✔
197
                        uopz_exception(
20✔
198
                                "attempt to set public, private or protected on class entry %s, not allowed",
199
                                ZSTR_VAL(clazz->name));
200
                        return;
20✔
201
                }
202

203
                if (flags & ZEND_ACC_STATIC) {
40✔
204
                        uopz_exception(
20✔
205
                                "attempt to set static on class entry %s, not allowed",
206
                                ZSTR_VAL(clazz->name));
207
                        return;
20✔
208
                }
209

210
                if (clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
20✔
211
                        uopz_exception(
×
212
                                "attempt to set flags of immutable class entry %s, not allowed",
213
                                ZSTR_VAL(clazz->name));
214
                        return;
×
215
                }
216

217
                current = clazz->ce_flags;
20✔
218
                clazz->ce_flags = flags;
20✔
219
                if (current & ZEND_ACC_LINKED) {
20✔
220
                        clazz->ce_flags |= ZEND_ACC_LINKED;
20✔
221
                }
222
                RETURN_LONG(current);
20✔
223
        }
224

225
        zend_function *function = uopz_find_function(table, name);
100✔
226
        if (!function) {
100✔
227
                if (clazz) {
60✔
228
                        uopz_exception(
20✔
229
                                "failed to set or get flags of method %s::%s, it does not exist",
230
                                ZSTR_VAL(clazz->name), ZSTR_VAL(name));
231
                } else {
232
                        uopz_exception(
40✔
233
                                "failed to set or get flags of function %s, it does not exist",
234
                                ZSTR_VAL(name));
235
                }
236
                return;
60✔
237
        }
238

239
        if (flags == ZEND_LONG_MAX) {
40✔
240
                RETURN_LONG(function->common.fn_flags);
20✔
241
        }
242

243
        current = function->common.fn_flags;
20✔
244
        if (flags) {
20✔
245
                if (function->common.fn_flags & ZEND_ACC_IMMUTABLE) {
20✔
246
                        uopz_exception(
×
247
                                "attempt to set flags of immutable function entry %s, not allowed",
248
                                ZSTR_VAL(name));
249
                        return;
×
250
                }
251

252
                /* Only allow changing a whitelist of flags, don't allow modifying internal flags. */
253
                uint32_t allowed_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_FINAL;
20✔
254
                function->common.fn_flags =
20✔
255
                        (function->common.fn_flags & ~allowed_flags) | (flags & allowed_flags);
20✔
256
        }
257
        RETURN_LONG(current);
20✔
258
} /* }}} */
259

260
zend_bool uopz_set_static(zend_class_entry *clazz, zend_string *function, zval *statics) { /* {{{ */
220✔
261
        zend_function *entry;
110✔
262
        zend_string *k = NULL;
220✔
263
        zval *v = NULL;
220✔
264

265
        if (clazz) {
220✔
266
                entry = uopz_find_function(&clazz->function_table, function);
160✔
267
                if (!entry) {
160✔
268
                        uopz_exception(
20✔
269
                                "failed to set statics in method %s::%s, it does not exist",
270
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
271
                        return 0;
20✔
272
                }
273
        } else {
274
                entry = uopz_find_function(CG(function_table), function);
60✔
275
                if (!entry) {
60✔
276
                        uopz_exception(
20✔
277
                                "failed to set statics in function %s, it does not exist",
278
                                ZSTR_VAL(function));
279
                        return 0;
20✔
280
                }
281
        }
282

283
        if (entry->type != ZEND_USER_FUNCTION) {
180✔
284
                if (clazz) {
40✔
285
                        uopz_exception(
20✔
286
                                "failed to set statics in internal method %s::%s",
287
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
288
                } else {
289
                        uopz_exception(
20✔
290
                                "failed to set statics in internal function %s",
291
                                ZSTR_VAL(function));
292
                }
293

294
                return 0;
40✔
295
        }
296

297
        if (!entry->op_array.static_variables) {
140✔
298
                if (clazz) {
40✔
299
                        uopz_exception(
20✔
300
                                "failed to set statics in method %s::%s, no statics declared",
301
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
302
                } else {
303
                        uopz_exception(
20✔
304
                                "failed to set statics in function %s, no statics declared",
305
                                ZSTR_VAL(function));
306
                }
307

308
                return 0;
40✔
309
        }
310

311
        HashTable *variables = ZEND_MAP_PTR_GET(entry->op_array.static_variables_ptr);
100✔
312

313
        if (!variables) {
100✔
314
                variables = zend_array_dup(entry->op_array.static_variables);
18✔
315

316
                ZEND_MAP_PTR_SET(entry->op_array.static_variables_ptr, variables);
18✔
317
        }
318

319
        ZEND_HASH_FOREACH_STR_KEY_VAL(variables, k, v) {
200✔
320
                zval *y;
50✔
321

322
                if (Z_REFCOUNTED_P(v)) {
100✔
323
                        zval_ptr_dtor(v);
60✔
324
                }
325

326
                ZEND_ASSERT(Z_TYPE_P(statics) == IS_ARRAY);
100✔
327
                if (!(y = zend_hash_find(Z_ARRVAL_P(statics), k))) {
100✔
328
                        ZVAL_NULL(v);
20✔
329
                        
330
                        continue;
20✔
331
                }
332

333
                ZVAL_COPY(v, y);
90✔
334
        } ZEND_HASH_FOREACH_END();
335

336
        return 1;
50✔
337
} /* }}} */
338

339
zend_bool uopz_get_static(zend_class_entry *clazz, zend_string *function, zval *return_value) { /* {{{ */
240✔
340
        zend_function *entry;
120✔
341

342
        if (clazz) {
240✔
343
                entry = uopz_find_function(&clazz->function_table, function);
180✔
344
                if (!entry) {
180✔
345
                        uopz_exception(
20✔
346
                                "failed to get statics from method %s::%s, it does not exist",
347
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
348
                        return 0;
20✔
349
                }
350
        } else {
351
                entry = uopz_find_function(CG(function_table), function);
60✔
352
                if (!entry) {
60✔
353
                        uopz_exception(
20✔
354
                                "failed to get statics from function %s, it does not exist",
355
                                ZSTR_VAL(function));
356
                        return 0;
20✔
357
                }
358
        }
359

360
        if (entry->type != ZEND_USER_FUNCTION) {
200✔
361
                if (clazz) {
40✔
362
                        uopz_exception(
20✔
363
                                "failed to get statics from internal method %s::%s",
364
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
365
                } else {
366
                        uopz_exception(
20✔
367
                                "failed to get statics from internal function %s",
368
                                ZSTR_VAL(function));
369
                }
370

371
                return 0;
40✔
372
        }
373

374
        if (!entry->op_array.static_variables) {
160✔
375
                if (clazz) {
40✔
376
                        uopz_exception(
20✔
377
                                "failed to set statics in method %s::%s, no statics declared",
378
                                ZSTR_VAL(clazz->name), ZSTR_VAL(function));
379
                } else {
380
                        uopz_exception(
20✔
381
                                "failed to set statics in function %s, no statics declared",
382
                                ZSTR_VAL(function));
383
                }
384

385
                return 0;
40✔
386
        }
387

388
        HashTable *variables = ZEND_MAP_PTR_GET(entry->op_array.static_variables_ptr);
120✔
389

390
        if (!variables) {
120✔
391
                variables = zend_array_dup(entry->op_array.static_variables);
36✔
392
                ZEND_MAP_PTR_SET(entry->op_array.static_variables_ptr, variables);
36✔
393
        }
394

395
        zval *val;
60✔
396
        ZEND_HASH_FOREACH_VAL(variables, val) {
280✔
397
                if (zval_update_constant_ex(val, entry->common.scope) != SUCCESS) {
160✔
398
                        return false;
399
                }
400
        } ZEND_HASH_FOREACH_END();
401

402
        ZVAL_ARR(return_value, zend_array_dup(variables));
120✔
403
        return 1;
120✔
404
} /* }}} */
405

406
#endif        /* UOPZ_FUNCTION */
407

408
/*
409
 * Local variables:
410
 * tab-width: 4
411
 * c-basic-offset: 4
412
 * End:
413
 * vim600: noet sw=4 ts=4 fdm=marker
414
 * vim<600: noet sw=4 ts=4
415
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc