diff options
| author | xXx-caillou-xXx | 2017-12-20 18:09:53 +0100 |
|---|---|---|
| committer | jvoisin | 2017-12-20 18:09:53 +0100 |
| commit | e7f541396715ee2895abcf73044b91ae9b746201 (patch) | |
| tree | ba0e9765e7f14f04b92585df1f3fcd1830ab4b00 /src/sp_var_value.c | |
| parent | 8d6cc4f2b63c3f0dc31fe6cecd34ac023ea1cccb (diff) | |
Better parsing of the rules
Thanks to this huge commit from @xXx-caillou-xXx, we can now write amazingly flexible rules.
Diffstat (limited to 'src/sp_var_value.c')
| -rw-r--r-- | src/sp_var_value.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/sp_var_value.c b/src/sp_var_value.c new file mode 100644 index 0000000..304ece9 --- /dev/null +++ b/src/sp_var_value.c | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 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 | |||
| 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 | zval *value = NULL; | ||
| 24 | |||
| 25 | while (current) { | ||
| 26 | zend_string* key = NULL; | ||
| 27 | EG(current_execute_data) = current; | ||
| 28 | zend_array* symtable = zend_rebuild_symbol_table(); | ||
| 29 | ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) { | ||
| 30 | if (0 == strcmp(var_name, key->val)) { | ||
| 31 | if (Z_TYPE_P(value) == IS_INDIRECT) { | ||
| 32 | value = Z_INDIRECT_P(value); | ||
| 33 | } | ||
| 34 | EG(current_execute_data) = orig_execute_data; | ||
| 35 | return value; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | ZEND_HASH_FOREACH_END(); | ||
| 39 | current = current->prev_execute_data; | ||
| 40 | } | ||
| 41 | EG(current_execute_data) = orig_execute_data; | ||
| 42 | return NULL; | ||
| 43 | } | ||
| 44 | |||
| 45 | static zval *get_constant(const char *value) { | ||
| 46 | zend_string *name = zend_string_init(value, strlen(value), 0); | ||
| 47 | zval *zvalue = zend_get_constant_ex(name, NULL, 0); | ||
| 48 | |||
| 49 | zend_string_release(name); | ||
| 50 | return zvalue; | ||
| 51 | } | ||
| 52 | |||
| 53 | static zval *get_var_value(zend_execute_data *ed, const char *var_name, | ||
| 54 | bool is_param) { | ||
| 55 | zval *zvalue = NULL; | ||
| 56 | |||
| 57 | if (!var_name) { | ||
| 58 | return NULL; | ||
| 59 | } | ||
| 60 | if (*var_name != VARIABLE_TOKEN) { | ||
| 61 | return get_constant(var_name); | ||
| 62 | } else { | ||
| 63 | var_name++; | ||
| 64 | } | ||
| 65 | if (is_param) { | ||
| 66 | zvalue = get_param_var(ed, var_name); | ||
| 67 | if (!zvalue) { | ||
| 68 | return get_local_var(ed, var_name); | ||
| 69 | } | ||
| 70 | return zvalue; | ||
| 71 | } | ||
| 72 | return get_local_var(ed, var_name); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void *get_entry_hashtable(const HashTable *ht, const char *entry, | ||
| 76 | size_t entry_len) { | ||
| 77 | zval *zvalue = zend_hash_str_find(ht, entry, entry_len); | ||
| 78 | |||
| 79 | if (!zvalue) { | ||
| 80 | zvalue = zend_hash_index_find(ht, atol(entry)); | ||
| 81 | } | ||
| 82 | while (zvalue && (Z_TYPE_P(zvalue) == IS_INDIRECT | ||
| 83 | || Z_TYPE_P(zvalue) == IS_PTR)) { | ||
| 84 | if (Z_TYPE_P(zvalue) == IS_INDIRECT) { | ||
| 85 | zvalue = Z_INDIRECT_P(zvalue); | ||
| 86 | } else { | ||
| 87 | zvalue = Z_PTR_P(zvalue); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | return zvalue; | ||
| 91 | } | ||
| 92 | |||
| 93 | static zval *get_array_value(zend_execute_data *ed, zval *zvalue, | ||
| 94 | const sp_tree *tree) { | ||
| 95 | zval *idx_value, *ret = NULL; | ||
| 96 | char *idx = NULL; | ||
| 97 | |||
| 98 | idx_value = get_value(ed, tree->idx, false); | ||
| 99 | if (!zvalue || !idx_value) { | ||
| 100 | return NULL; | ||
| 101 | } | ||
| 102 | if (Z_TYPE_P(zvalue) == IS_ARRAY) { | ||
| 103 | idx = sp_convert_to_string(idx_value); | ||
| 104 | ret = get_entry_hashtable(Z_ARRVAL_P(zvalue), idx, strlen(idx)); | ||
| 105 | efree(idx); | ||
| 106 | } | ||
| 107 | return ret; | ||
| 108 | } | ||
| 109 | |||
| 110 | static zval *get_object_property(zend_execute_data *ed, zval *object, | ||
| 111 | const char *property, bool is_param) { | ||
| 112 | char *class_name = object->value.obj->ce->name->val; | ||
| 113 | HashTable *array = Z_OBJPROP_P(object); | ||
| 114 | zval *zvalue = NULL; | ||
| 115 | zval *property_val = get_var_value(ed, property, is_param); | ||
| 116 | size_t len; | ||
| 117 | |||
| 118 | if (property_val) { | ||
| 119 | if (Z_TYPE_P(property_val) != IS_STRING) { | ||
| 120 | return NULL; | ||
| 121 | } else { | ||
| 122 | property = Z_STRVAL_P(property_val); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | zvalue = get_entry_hashtable(array, property, strlen(property)); | ||
| 126 | if (!zvalue) { | ||
| 127 | char *protected_property = emalloc(strlen(property) + 4); | ||
| 128 | len = sprintf(protected_property, PROTECTED_PROP_FMT, 0, 0, property); | ||
| 129 | zvalue = get_entry_hashtable(array, protected_property, len); | ||
| 130 | efree(protected_property); | ||
| 131 | } | ||
| 132 | if (!zvalue) { | ||
| 133 | char *private_property = emalloc(strlen(class_name) + 3 + strlen(property)); | ||
| 134 | len = sprintf(private_property, PRIVATE_PROP_FMT, 0, class_name, 0, property); | ||
| 135 | zvalue = get_entry_hashtable(array, private_property, len); | ||
| 136 | efree(private_property); | ||
| 137 | } | ||
| 138 | return zvalue; | ||
| 139 | } | ||
| 140 | |||
| 141 | static zend_class_entry *get_class(const char *value) { | ||
| 142 | zend_string *name; | ||
| 143 | zend_class_entry *ce; | ||
| 144 | |||
| 145 | name = zend_string_init(value, strlen(value), 0); | ||
| 146 | ce = zend_lookup_class(name); | ||
| 147 | zend_string_release(name); | ||
| 148 | return ce; | ||
| 149 | } | ||
| 150 | |||
| 151 | static zval *get_unknown_type(const char *restrict value, zval *zvalue, | ||
| 152 | zend_class_entry *ce, zend_execute_data *ed, | ||
| 153 | const sp_tree *tree, bool is_param) { | ||
| 154 | if (ce) { | ||
| 155 | zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value)); | ||
| 156 | ce = NULL; | ||
| 157 | } else if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT && value[0]) { | ||
| 158 | zvalue = get_object_property(ed, zvalue, value, is_param); | ||
| 159 | } else if (!tree->next && !zvalue) { | ||
| 160 | if (tree->type == CONSTANT) { | ||
| 161 | zvalue = get_constant(value); | ||
| 162 | } | ||
| 163 | if (!zvalue) { | ||
| 164 | zvalue = emalloc(sizeof(zval)); | ||
| 165 | zvalue->value.str = zend_string_init(value, strlen(value), 0); | ||
| 166 | zvalue->u1.v.type = IS_STRING; | ||
| 167 | } | ||
| 168 | } else { | ||
| 169 | return NULL; | ||
| 170 | } | ||
| 171 | return zvalue; | ||
| 172 | } | ||
| 173 | |||
| 174 | zval *get_value(zend_execute_data *ed, const sp_tree *tree, | ||
| 175 | bool is_param) { | ||
| 176 | zval *zvalue = NULL; | ||
| 177 | zend_class_entry *ce = NULL; | ||
| 178 | |||
| 179 | while (tree) { | ||
| 180 | switch (tree->type) { | ||
| 181 | case ARRAY: | ||
| 182 | if (ce) { | ||
| 183 | zvalue = get_entry_hashtable(&ce->constants_table, tree->value, | ||
| 184 | strlen(tree->value)); | ||
| 185 | ce = NULL; | ||
| 186 | } else if (!zvalue) { | ||
| 187 | zvalue = get_var_value(ed, tree->value, is_param); | ||
| 188 | } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { | ||
| 189 | zvalue = get_object_property(ed, zvalue, tree->value, is_param); | ||
| 190 | } | ||
| 191 | zvalue = get_array_value(ed, zvalue, tree); | ||
| 192 | break; | ||
| 193 | case VAR: | ||
| 194 | if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) { | ||
| 195 | zvalue = get_object_property(ed, zvalue, tree->value, is_param); | ||
| 196 | } else { | ||
| 197 | zvalue = get_var_value(ed, tree->value, is_param); | ||
| 198 | } | ||
| 199 | break; | ||
| 200 | case OBJECT: | ||
| 201 | if (!zvalue) { | ||
| 202 | zvalue = get_var_value(ed, tree->value, is_param); | ||
| 203 | } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { | ||
| 204 | if (0 != strlen(tree->value)) { | ||
| 205 | zvalue = get_object_property(ed, zvalue, tree->value, is_param); | ||
| 206 | } | ||
| 207 | } else { | ||
| 208 | return NULL; | ||
| 209 | } | ||
| 210 | break; | ||
| 211 | case CLASS: | ||
| 212 | ce = get_class(tree->value); | ||
| 213 | zvalue = NULL; | ||
| 214 | break; | ||
| 215 | default: | ||
| 216 | zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param); | ||
| 217 | ce = NULL; | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | if (!zvalue && !ce) { | ||
| 221 | return NULL; | ||
| 222 | } | ||
| 223 | tree = tree->next; | ||
| 224 | } | ||
| 225 | return zvalue; | ||
| 226 | } | ||
