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

krakjoe / uopz / 12858070881

19 Jan 2025 11:19PM UTC coverage: 95.502%. Remained the same
12858070881

Pull #189

github

web-flow
Merge 2769ac9f9 into dcb01f128
Pull Request #189: Attempt to fix lcov CI

913 of 956 relevant lines covered (95.5%)

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

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

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

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

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

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

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

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

57
#if PHP_VERSION_ID >= 80200
58
                ZEND_MAP_PTR_INIT(
8✔
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);
192✔
66
        }
67

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

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

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

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

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

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

110
        if (clazz) {
208✔
111
                if (all) {
192✔
112
                        zend_class_entry *next;
96✔
113

114
                        ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
25,488✔
115
                                if (next->parent == clazz) {
25,296✔
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);
192✔
125
        }
126

127
        zend_string_release(key);
208✔
128

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

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

170
                ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
2,124✔
171
                        if (next->parent == clazz) {
2,108✔
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);
16✔
181
        zend_string_release(key);
16✔
182

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

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

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

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

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

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

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

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

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

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

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

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

294
                return 0;
32✔
295
        }
296

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

308
                return 0;
32✔
309
        }
310

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

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

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

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

322
                if (Z_REFCOUNTED_P(v)) {
80✔
323
                        zval_ptr_dtor(v);
48✔
324
                }
325

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

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

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

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

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

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

371
                return 0;
32✔
372
        }
373

374
        if (!entry->op_array.static_variables) {
128✔
375
                if (clazz) {
32✔
376
                        uopz_exception(
16✔
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(
16✔
381
                                "failed to set statics in function %s, no statics declared",
382
                                ZSTR_VAL(function));
383
                }
384

385
                return 0;
32✔
386
        }
387

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

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

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

402
        ZVAL_ARR(return_value, zend_array_dup(variables));
96✔
403
        return 1;
96✔
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