From e7f541396715ee2895abcf73044b91ae9b746201 Mon Sep 17 00:00:00 2001 From: xXx-caillou-xXx Date: Wed, 20 Dec 2017 18:09:53 +0100 Subject: Better parsing of the rules Thanks to this huge commit from @xXx-caillou-xXx, we can now write amazingly flexible rules.--- src/sp_var_value.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 src/sp_var_value.c (limited to 'src/sp_var_value.c') 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 @@ +#include "php_snuffleupagus.h" + +static zval *get_param_var(zend_execute_data *ed, const char *var_name) { + unsigned int nb_param = ed->func->common.num_args; + + for (unsigned int i = 0; i < nb_param; i++) { + const char *arg_name; + if (ZEND_USER_CODE(ed->func->type)) { + arg_name = ZSTR_VAL(ed->func->common.arg_info[i].name); + } else { + arg_name = ed->func->internal_function.arg_info[i].name; + } + if (0 == strcmp(arg_name, var_name)) { + return ZEND_CALL_VAR_NUM(ed, i); + } + } + return NULL; +} + +static zval *get_local_var(zend_execute_data *ed, const char *var_name) { + zend_execute_data *orig_execute_data = ed; + zend_execute_data *current = ed; + zval *value = NULL; + + while (current) { + zend_string* key = NULL; + EG(current_execute_data) = current; + zend_array* symtable = zend_rebuild_symbol_table(); + ZEND_HASH_FOREACH_STR_KEY_VAL(symtable, key, value) { + if (0 == strcmp(var_name, key->val)) { + if (Z_TYPE_P(value) == IS_INDIRECT) { + value = Z_INDIRECT_P(value); + } + EG(current_execute_data) = orig_execute_data; + return value; + } + } + ZEND_HASH_FOREACH_END(); + current = current->prev_execute_data; + } + EG(current_execute_data) = orig_execute_data; + return NULL; +} + +static zval *get_constant(const char *value) { + zend_string *name = zend_string_init(value, strlen(value), 0); + zval *zvalue = zend_get_constant_ex(name, NULL, 0); + + zend_string_release(name); + return zvalue; +} + +static zval *get_var_value(zend_execute_data *ed, const char *var_name, + bool is_param) { + zval *zvalue = NULL; + + if (!var_name) { + return NULL; + } + if (*var_name != VARIABLE_TOKEN) { + return get_constant(var_name); + } else { + var_name++; + } + if (is_param) { + zvalue = get_param_var(ed, var_name); + if (!zvalue) { + return get_local_var(ed, var_name); + } + return zvalue; + } + return get_local_var(ed, var_name); +} + +static void *get_entry_hashtable(const HashTable *ht, const char *entry, + size_t entry_len) { + zval *zvalue = zend_hash_str_find(ht, entry, entry_len); + + if (!zvalue) { + zvalue = zend_hash_index_find(ht, atol(entry)); + } + while (zvalue && (Z_TYPE_P(zvalue) == IS_INDIRECT + || Z_TYPE_P(zvalue) == IS_PTR)) { + if (Z_TYPE_P(zvalue) == IS_INDIRECT) { + zvalue = Z_INDIRECT_P(zvalue); + } else { + zvalue = Z_PTR_P(zvalue); + } + } + return zvalue; +} + +static zval *get_array_value(zend_execute_data *ed, zval *zvalue, + const sp_tree *tree) { + zval *idx_value, *ret = NULL; + char *idx = NULL; + + idx_value = get_value(ed, tree->idx, false); + if (!zvalue || !idx_value) { + return NULL; + } + if (Z_TYPE_P(zvalue) == IS_ARRAY) { + idx = sp_convert_to_string(idx_value); + ret = get_entry_hashtable(Z_ARRVAL_P(zvalue), idx, strlen(idx)); + efree(idx); + } + return ret; +} + +static zval *get_object_property(zend_execute_data *ed, zval *object, + const char *property, bool is_param) { + char *class_name = object->value.obj->ce->name->val; + HashTable *array = Z_OBJPROP_P(object); + zval *zvalue = NULL; + zval *property_val = get_var_value(ed, property, is_param); + size_t len; + + if (property_val) { + if (Z_TYPE_P(property_val) != IS_STRING) { + return NULL; + } else { + property = Z_STRVAL_P(property_val); + } + } + zvalue = get_entry_hashtable(array, property, strlen(property)); + if (!zvalue) { + char *protected_property = emalloc(strlen(property) + 4); + len = sprintf(protected_property, PROTECTED_PROP_FMT, 0, 0, property); + zvalue = get_entry_hashtable(array, protected_property, len); + efree(protected_property); + } + if (!zvalue) { + char *private_property = emalloc(strlen(class_name) + 3 + strlen(property)); + len = sprintf(private_property, PRIVATE_PROP_FMT, 0, class_name, 0, property); + zvalue = get_entry_hashtable(array, private_property, len); + efree(private_property); + } + return zvalue; +} + +static zend_class_entry *get_class(const char *value) { + zend_string *name; + zend_class_entry *ce; + + name = zend_string_init(value, strlen(value), 0); + ce = zend_lookup_class(name); + zend_string_release(name); + return ce; +} + +static zval *get_unknown_type(const char *restrict value, zval *zvalue, + zend_class_entry *ce, zend_execute_data *ed, + const sp_tree *tree, bool is_param) { + if (ce) { + zvalue = get_entry_hashtable(&ce->constants_table, value, strlen(value)); + ce = NULL; + } else if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT && value[0]) { + zvalue = get_object_property(ed, zvalue, value, is_param); + } else if (!tree->next && !zvalue) { + if (tree->type == CONSTANT) { + zvalue = get_constant(value); + } + if (!zvalue) { + zvalue = emalloc(sizeof(zval)); + zvalue->value.str = zend_string_init(value, strlen(value), 0); + zvalue->u1.v.type = IS_STRING; + } + } else { + return NULL; + } + return zvalue; +} + +zval *get_value(zend_execute_data *ed, const sp_tree *tree, + bool is_param) { + zval *zvalue = NULL; + zend_class_entry *ce = NULL; + + while (tree) { + switch (tree->type) { + case ARRAY: + if (ce) { + zvalue = get_entry_hashtable(&ce->constants_table, tree->value, + strlen(tree->value)); + ce = NULL; + } else if (!zvalue) { + zvalue = get_var_value(ed, tree->value, is_param); + } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { + zvalue = get_object_property(ed, zvalue, tree->value, is_param); + } + zvalue = get_array_value(ed, zvalue, tree); + break; + case VAR: + if (zvalue && Z_TYPE_P(zvalue) == IS_OBJECT) { + zvalue = get_object_property(ed, zvalue, tree->value, is_param); + } else { + zvalue = get_var_value(ed, tree->value, is_param); + } + break; + case OBJECT: + if (!zvalue) { + zvalue = get_var_value(ed, tree->value, is_param); + } else if (Z_TYPE_P(zvalue) == IS_OBJECT) { + if (0 != strlen(tree->value)) { + zvalue = get_object_property(ed, zvalue, tree->value, is_param); + } + } else { + return NULL; + } + break; + case CLASS: + ce = get_class(tree->value); + zvalue = NULL; + break; + default: + zvalue = get_unknown_type(tree->value, zvalue, ce, ed, tree, is_param); + ce = NULL; + break; + } + if (!zvalue && !ce) { + return NULL; + } + tree = tree->next; + } + return zvalue; +} -- cgit v1.3