1 #include "php_snuffleupagus.h"
2
get_param_var(zend_execute_data * ed,const char * var_name)3 static zval *get_param_var(zend_execute_data *ed, const char *var_name) {
4 unsigned int nb_param = ed->func->common.num_args;
5
6 for (unsigned int i = 0; i < nb_param; i++) {
7 const char *arg_name;
8 if (ZEND_USER_CODE(ed->func->type)) {
9 arg_name = ZSTR_VAL(ed->func->common.arg_info[i].name);
10 } else {
11 arg_name = ed->func->internal_function.arg_info[i].name;
12 }
13 if (0 == strcmp(arg_name, var_name)) {
14 return ZEND_CALL_VAR_NUM(ed, i);
15 }
16 }
17 return NULL;
18 }
19
get_local_var(zend_execute_data * ed,const char * var_name)20 static zval *get_local_var(zend_execute_data *ed, const char *var_name) {
21 zend_execute_data *orig_execute_data = ed;
22 zend_execute_data *current = ed;
23
24 while (current) {
25 zval *value = NULL;
26 zend_string *key = NULL;
27 EG(current_execute_data) = current;
28 zend_array *symtable = zend_rebuild_symbol_table();
29
30 if (UNEXPECTED(symtable == NULL)) {
31 EG(current_execute_data) = orig_execute_data;
32 return NULL;
33 }
34
35 ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) {
36 if (0 == strcmp(var_name, key->val)) {
37 if (Z_TYPE_P(value) == IS_INDIRECT) {
38 value = Z_INDIRECT_P(value);
39 }
40 EG(current_execute_data) = orig_execute_data;
41 return value;
42 }
43 }
44 ZEND_HASH_FOREACH_END();
45 current = current->prev_execute_data;
46 }
47 EG(current_execute_data) = orig_execute_data;
48 return NULL;
49 }
50
get_constant(const char * value)51 static zval *get_constant(const char *value) {
52 zend_string *name = zend_string_init(value, strlen(value), 0);
53 zval *zvalue = zend_get_constant_ex(name, NULL, ZEND_FETCH_CLASS_SILENT);
54
55 zend_string_release(name);
56 return zvalue;
57 }
58
get_var_value(zend_execute_data * ed,const char * var_name,bool is_param)59 static zval *get_var_value(zend_execute_data *ed, const char *var_name,
60 bool is_param) {
61 if (!var_name) {
62 return NULL; // LCOV_EXCL_LINE
63 }
64
65 if (*var_name != VARIABLE_TOKEN) {
66 return get_constant(var_name);
67 } else {
68 var_name++;
69 }
70
71 if (is_param) {
72 zval *zvalue = get_param_var(ed, var_name);
73 if (!zvalue) {
74 return get_local_var(ed, var_name);
75 }
76 return zvalue;
77 }
78
79 return get_local_var(ed, var_name);
80 }
81
get_entry_hashtable(const HashTable * ht,const char * entry,size_t entry_len)82 static void *get_entry_hashtable(const HashTable *ht, const char *entry,
83 size_t entry_len) {
84 zval *zvalue = zend_hash_str_find(ht, entry, entry_len);
85
86 if (!zvalue) {
87 zvalue = zend_hash_index_find(ht, atol(entry));
88 }
89
90 while (zvalue &&
91 (Z_TYPE_P(zvalue) == IS_INDIRECT || Z_TYPE_P(zvalue) == IS_PTR)) {
92 if (Z_TYPE_P(zvalue) == IS_INDIRECT) {
93 zvalue = Z_INDIRECT_P(zvalue);
94 } else {
95 zvalue = Z_PTR_P(zvalue);
96 }
97 }
98 return zvalue;
99 }
100
get_array_value(zend_execute_data * ed,zval * zvalue,const sp_tree * tree)101 static zval *get_array_value(zend_execute_data *ed, zval *zvalue,
102 const sp_tree *tree) {
103 zval *idx_value = sp_get_var_value(ed, tree->idx, false);
104
105 if (!zvalue || !idx_value) {
106 return NULL;
107 }
108
109 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
110 const zend_string *idx = sp_zval_to_zend_string(idx_value);
111 return get_entry_hashtable(Z_ARRVAL_P(zvalue), ZSTR_VAL(idx),
112 ZSTR_LEN(idx));
113 }
114
115 return NULL;
116 }
117
get_object_property(zend_execute_data * ed,zval * object,const char * property,bool is_param)118 static zval *get_object_property(zend_execute_data *ed, zval *object,
119 const char *property, bool is_param) {
120 char *class_name = object->value.obj->ce->name->val;
121 HashTable *array = Z_OBJPROP_P(object);
122 zval *zvalue = NULL;
123 zval *property_val = get_var_value(ed, property, is_param);
124 size_t len;
125
126 if (property_val) {
127 if (Z_TYPE_P(property_val) != IS_STRING) {
128 return NULL;
129 } else {
130 property = Z_STRVAL_P(property_val);
131 }
132 }
133 zvalue = get_entry_hashtable(array, property, strlen(property));
134 // TODO do we want to log overflow?
135 if (!zvalue) {
136 len = strlen(property) + 4;
137 char *protected_property = emalloc(len);
138 snprintf(protected_property, len, PROTECTED_PROP_FMT, 0, 0, property);
139 zvalue = get_entry_hashtable(array, protected_property, len - 1);
140 efree(protected_property);
141 }
142 if (!zvalue) {
143 len = strlen(class_name) + 3 + strlen(property);
144 char *private_property = emalloc(len);
145 snprintf(private_property, len, PRIVATE_PROP_FMT, 0, class_name, 0,
146 property);
147 zvalue = get_entry_hashtable(array, private_property, len - 1);
148 efree(private_property);
149 }
150 return zvalue;
151 }
152
get_class(const char * value)153 static zend_class_entry *get_class(const char *value) {
154 zend_string *name = zend_string_init(value, strlen(value), 0);
155 zend_class_entry *ce = zend_lookup_class(name);
156 zend_string_release(name);
157 return ce;
158 }
159
get_unknown_type(const char * restrict value,zval * zvalue,zend_class_entry * ce,zend_execute_data * ed,const sp_tree * tree,bool is_param)160 static zval *get_unknown_type(const char *restrict value, zval *zvalue,
161 zend_class_entry *ce, zend_execute_data *ed,
162 const sp_tree *tree, bool is_param) {
163 if (ce) {
164 zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value));
165 ce = NULL;
166 } else if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) {
167 zvalue = get_object_property(ed, zvalue, value, is_param);
168 } else if (!zvalue) {
169 if (tree->type == CONSTANT) {
170 zvalue = get_constant(value);
171 }
172 if (!zvalue) {
173 zvalue = emalloc(sizeof(zval));
174 ZVAL_PSTRING(zvalue, value);
175 }
176 } else {
177 return NULL;
178 }
179 return zvalue;
180 }
181
sp_get_var_value(zend_execute_data * ed,const sp_tree * tree,bool is_param)182 zval *sp_get_var_value(zend_execute_data *ed, const sp_tree *tree,
183 bool is_param) {
184 zval *zvalue = NULL;
185 zend_class_entry *ce = NULL;
186
187 while (tree) {
188 switch (tree->type) {
189 case ARRAY:
190 if (ce) {
191 zvalue = get_entry_hashtable(&ce->constants_table, tree->value,
192 strlen(tree->value));
193 ce = NULL;
194 } else if (!zvalue) {
195 zvalue = get_var_value(ed, tree->value, is_param);
196 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
197 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
198 }
199 zvalue = get_array_value(ed, zvalue, tree);
200 break;
201 case VAR:
202 if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) {
203 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
204 } else {
205 zvalue = get_var_value(ed, tree->value, is_param);
206 }
207 break;
208 case OBJECT:
209 if (!zvalue) {
210 zvalue = get_var_value(ed, tree->value, is_param);
211 } else if (Z_TYPE_P(zvalue) == IS_OBJECT) {
212 if (0 != strlen(tree->value)) {
213 zvalue = get_object_property(ed, zvalue, tree->value, is_param);
214 }
215 } else {
216 return NULL;
217 }
218 break;
219 case CLASS:
220 ce = get_class(tree->value);
221 zvalue = NULL;
222 break;
223 default:
224 zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param);
225 ce = NULL;
226 break;
227 }
228 if (!zvalue && !ce) {
229 return NULL;
230 }
231 tree = tree->next;
232 }
233 return zvalue;
234 }
235