-
Notifications
You must be signed in to change notification settings - Fork 8k
Expand file tree
/
Copy pathzend_autoload.c
More file actions
165 lines (144 loc) · 5.93 KB
/
zend_autoload.c
File metadata and controls
165 lines (144 loc) · 5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
| Copyright © Zend Technologies Ltd., a subsidiary company of |
| Perforce Software, Inc., and Contributors. |
+----------------------------------------------------------------------+
| This source file is subject to the Modified BSD License that is |
| bundled with this package in the file LICENSE, and is available |
| through the World Wide Web at <https://www.php.net/license/>. |
| |
| SPDX-License-Identifier: BSD-3-Clause |
+----------------------------------------------------------------------+
| Authors: Gina Peter Banyard <[email protected]> |
+----------------------------------------------------------------------+
*/
#include "zend.h"
#include "zend_API.h"
#include "zend_autoload.h"
#include "zend_hash.h"
#include "zend_types.h"
#include "zend_exceptions.h"
#include "zend_string.h"
ZEND_TLS HashTable *zend_class_autoload_functions;
static void zend_autoload_callback_zval_destroy(zval *element)
{
zend_fcall_info_cache *fcc = Z_PTR_P(element);
zend_fcc_dtor(fcc);
efree(fcc);
}
static Bucket *autoload_find_registered_function(const HashTable *autoloader_table, const zend_fcall_info_cache *function_entry)
{
zend_fcall_info_cache *current_function_entry;
ZEND_HASH_MAP_FOREACH_PTR(autoloader_table, current_function_entry) {
if (zend_fcc_equals(current_function_entry, function_entry)) {
return _p;
}
} ZEND_HASH_FOREACH_END();
return NULL;
}
ZEND_API zend_class_entry *zend_perform_class_autoload(zend_string *class_name, zend_string *lc_name)
{
if (!zend_class_autoload_functions) {
return NULL;
}
zval zname;
ZVAL_STR(&zname, class_name);
const HashTable *class_autoload_functions = zend_class_autoload_functions;
/* Cannot use ZEND_HASH_MAP_FOREACH_PTR here as autoloaders may be
* added/removed during autoloading. */
HashPosition pos;
zend_hash_internal_pointer_reset_ex(class_autoload_functions, &pos);
while (true) {
zend_fcall_info_cache *func_info = zend_hash_get_current_data_ptr_ex(class_autoload_functions, &pos);
if (!func_info) {
break;
}
zend_call_known_fcc(func_info, /* retval */ NULL, /* param_count */ 1, /* params */ &zname, /* named_params */ NULL);
if (EG(exception)) {
return NULL;
}
if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name);
}
zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
return ce;
}
zend_hash_move_forward_ex(class_autoload_functions, &pos);
}
return NULL;
}
/* Needed for compatibility with spl_register_autoload() */
ZEND_API void zend_autoload_register_class_loader(zend_fcall_info_cache *fcc, bool prepend)
{
ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc));
if (!zend_class_autoload_functions) {
ALLOC_HASHTABLE(zend_class_autoload_functions);
zend_hash_init(zend_class_autoload_functions, 1, NULL, zend_autoload_callback_zval_destroy, false);
/* Initialize as non-packed hash table for prepend functionality. */
zend_hash_real_init_mixed(zend_class_autoload_functions);
}
ZEND_ASSERT(
fcc->function_handler->type != ZEND_INTERNAL_FUNCTION
|| !zend_string_equals_literal(fcc->function_handler->common.function_name, "spl_autoload_call")
);
/* If function is already registered, don't do anything */
if (autoload_find_registered_function(zend_class_autoload_functions, fcc)) {
/* Release potential call trampoline */
zend_release_fcall_info_cache(fcc);
return;
}
zend_fcc_addref(fcc);
zend_hash_next_index_insert_mem(zend_class_autoload_functions, fcc, sizeof(zend_fcall_info_cache));
if (prepend && zend_hash_num_elements(zend_class_autoload_functions) > 1) {
/* Move the newly created element to the head of the hashtable */
ZEND_ASSERT(!HT_IS_PACKED(zend_class_autoload_functions));
Bucket tmp = zend_class_autoload_functions->arData[zend_class_autoload_functions->nNumUsed-1];
memmove(zend_class_autoload_functions->arData + 1, zend_class_autoload_functions->arData, sizeof(Bucket) * (zend_class_autoload_functions->nNumUsed - 1));
zend_class_autoload_functions->arData[0] = tmp;
zend_hash_rehash(zend_class_autoload_functions);
}
}
ZEND_API bool zend_autoload_unregister_class_loader(const zend_fcall_info_cache *fcc) {
if (zend_class_autoload_functions) {
Bucket *p = autoload_find_registered_function(zend_class_autoload_functions, fcc);
if (p) {
zend_hash_del_bucket(zend_class_autoload_functions, p);
return true;
}
}
return false;
}
/* We do not return a HashTable* because zend_empty_array is not collectable,
* therefore the zval holding this value must do so. Something that ZVAL_EMPTY_ARRAY(); does. */
ZEND_API void zend_autoload_fcc_map_to_callable_zval_map(zval *return_value) {
if (zend_class_autoload_functions) {
zend_fcall_info_cache *fcc;
zend_array *map = zend_new_array(zend_hash_num_elements(zend_class_autoload_functions));
ZEND_HASH_MAP_FOREACH_PTR(zend_class_autoload_functions, fcc) {
zval tmp;
zend_get_callable_zval_from_fcc(fcc, &tmp);
zend_hash_next_index_insert(map, &tmp);
} ZEND_HASH_FOREACH_END();
RETURN_ARR(map);
}
RETURN_EMPTY_ARRAY();
}
/* Only for deprecated strange behaviour of spl_autoload_unregister() */
ZEND_API void zend_autoload_clean_class_loaders(void)
{
if (zend_class_autoload_functions) {
/* Don't destroy the hash table, as we might be iterating over it right now. */
zend_hash_clean(zend_class_autoload_functions);
}
}
void zend_autoload_shutdown(void)
{
if (zend_class_autoload_functions) {
zend_hash_destroy(zend_class_autoload_functions);
FREE_HASHTABLE(zend_class_autoload_functions);
zend_class_autoload_functions = NULL;
}
}