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

krakjoe / uopz / 10227248408

03 Aug 2024 10:17AM UTC coverage: 95.497%. Remained the same
10227248408

push

github

cmb69
CI: run Linjux on PHP master, too

912 of 955 relevant lines covered (95.5%)

4895.64 hits per line

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

93.26
/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) { /* {{{ */
117✔
33
        zend_function  *copy = (zend_function*) zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
117✔
34

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

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

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

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

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

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

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

57
#if PHP_VERSION_ID >= 80200
58
                ZEND_MAP_PTR_INIT(
3✔
59
                        copy->op_array.static_variables_ptr, copy->op_array.static_variables);
60
#else
61
                ZEND_MAP_PTR_INIT(
6✔
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);
108✔
66
        }
67

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

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

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

81
        if (clazz && clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
135✔
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);
135✔
90
        key = zend_new_interned_string(key);
135✔
91

92
        if (zend_hash_exists(table, key)) {
135✔
93
                if (clazz) {
18✔
94
                        uopz_exception(
9✔
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(
9✔
100
                                "will not replace existing function %s, use uopz_set_return instead",
101
                                ZSTR_VAL(name));
102
                }
103
                zend_string_release(key);
18✔
104
                return 0;
18✔
105
        }
106

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

110
        if (clazz) {
117✔
111
                if (all) {
108✔
112
                        zend_class_entry *next;
36✔
113

114
                        ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
13,932✔
115
                                if (next->parent == clazz) {
13,824✔
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);
108✔
125
        }
126

127
        zend_string_release(key);
117✔
128

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

132
zend_bool uopz_del_function(zend_class_entry *clazz, zend_string *name, zend_bool all) { /* {{{ */
45✔
133
        HashTable *table = clazz ? &clazz->function_table : CG(function_table);
45✔
134
        zend_string *key = zend_string_tolower(name);
45✔
135
        zend_function *function = zend_hash_find_ptr(table, key);
45✔
136
        
137
        if (!function) {
39✔
138
                if (clazz) {
18✔
139
                        uopz_exception(
9✔
140
                                "cannot delete method %s::%s, it does not exist",
141
                                ZSTR_VAL(clazz->name),
142
                                ZSTR_VAL(name));
143
                } else {
144
                        uopz_exception(
9✔
145
                                "cannot delete function %s, it does not exist",
146
                                ZSTR_VAL(name));
147
                }
148
                zend_string_release(key);
18✔
149
                return 0;
18✔
150
        }
151
        
152
        if (!(function->common.fn_flags & ZEND_ACC_UOPZ)) {
27✔
153
                if (clazz) {
18✔
154
                        uopz_exception(
9✔
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(
9✔
160
                                "cannot delete function %s, it was not added by uopz",
161
                                ZSTR_VAL(name));
162
                }
163
                zend_string_release(key);
18✔
164
                return 0;
18✔
165
        }
166
        
167
        if (clazz && all) {
9✔
168
                zend_class_entry *next;
3✔
169

170
                ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
1,161✔
171
                        if (next->parent == clazz) {
1,152✔
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);
9✔
181
        zend_string_release(key);
9✔
182

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

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

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

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

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

210
                if (clazz->ce_flags & ZEND_ACC_IMMUTABLE) {
9✔
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;
9✔
218
                clazz->ce_flags = flags;
9✔
219
                if (current & ZEND_ACC_LINKED) {
9✔
220
                        clazz->ce_flags |= ZEND_ACC_LINKED;
9✔
221
                }
222
                RETURN_LONG(current);
9✔
223
        }
224

225
        zend_function *function = uopz_find_function(table, name);
45✔
226
        if (!function) {
45✔
227
                if (clazz) {
27✔
228
                        uopz_exception(
9✔
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(
18✔
233
                                "failed to set or get flags of function %s, it does not exist",
234
                                ZSTR_VAL(name));
235
                }
236
                return;
27✔
237
        }
238

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

243
        current = function->common.fn_flags;
9✔
244
        if (flags) {
9✔
245
                if (function->common.fn_flags & ZEND_ACC_IMMUTABLE) {
9✔
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;
9✔
254
                function->common.fn_flags =
9✔
255
                        (function->common.fn_flags & ~allowed_flags) | (flags & allowed_flags);
9✔
256
        }
257
        RETURN_LONG(current);
9✔
258
} /* }}} */
259

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

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

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

294
                return 0;
18✔
295
        }
296

297
        if (!entry->op_array.static_variables) {
63✔
298
                if (clazz) {
18✔
299
                        uopz_exception(
9✔
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(
9✔
304
                                "failed to set statics in function %s, no statics declared",
305
                                ZSTR_VAL(function));
306
                }
307

308
                return 0;
18✔
309
        }
310

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

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

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

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

322
                if (Z_REFCOUNTED_P(v)) {
45✔
323
                        zval_ptr_dtor(v);
27✔
324
                }
325

326
                if (!(y = zend_hash_find(Z_ARRVAL_P(statics), k))) {
45✔
327
                        ZVAL_NULL(v);
9✔
328
                        
329
                        continue;
9✔
330
                }
331

332
                ZVAL_COPY(v, y);
39✔
333
        } ZEND_HASH_FOREACH_END();
334

335
        return 1;
30✔
336
} /* }}} */
337

338
zend_bool uopz_get_static(zend_class_entry *clazz, zend_string *function, zval *return_value) { /* {{{ */
108✔
339
        zend_function *entry;
36✔
340

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

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

370
                return 0;
18✔
371
        }
372

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

384
                return 0;
18✔
385
        }
386

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

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

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

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

405
#endif        /* UOPZ_FUNCTION */
406

407
/*
408
 * Local variables:
409
 * tab-width: 4
410
 * c-basic-offset: 4
411
 * End:
412
 * vim600: noet sw=4 ts=4 fdm=marker
413
 * vim<600: noet sw=4 ts=4
414
 */
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