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

krakjoe / uopz / 3970452482

pending completion
3970452482

push

github

Christoph M. Becker
Update to setup-php-sdk@v0.7

827 of 886 relevant lines covered (93.34%)

632.46 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

110
        if (clazz) {
13✔
111
                if (all) {
12✔
112
                        zend_class_entry *next;
113

114
                        ZEND_HASH_FOREACH_PTR(CG(class_table), next) {
1,680✔
115
                                if (next->parent == clazz) {
1,668✔
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);
12✔
125
        }
126

127
        zend_string_release(key);
13✔
128

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

294
                return 0;
2✔
295
        }
296

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

308
                return 0;
2✔
309
        }
310

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

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

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

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

322
                if (Z_REFCOUNTED_P(v)) {
5✔
323
                        zval_ptr_dtor(v);
3✔
324
                }
325

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

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

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

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

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

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

370
                return 0;
2✔
371
        }
372

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

384
                return 0;
2✔
385
        }
386

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

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

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

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