]> granicus.if.org Git - php/commitdiff
Added support for a restricted ev (variables only) in async safe contexts
authorBob Weinand <bobwei9@hotmail.com>
Fri, 3 Oct 2014 10:43:32 +0000 (12:43 +0200)
committerBob Weinand <bobwei9@hotmail.com>
Fri, 3 Oct 2014 10:43:32 +0000 (12:43 +0200)
phpdbg_cmd.c
phpdbg_prompt.c
phpdbg_utils.c
phpdbg_utils.h
phpdbg_watch.c

index e9811dc43b94d4eedce82b624ee2c53bbc1ab9bd..8fb86a5cbd876c7e6abd1bc15802d221322a4daa 100644 (file)
@@ -750,11 +750,7 @@ PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why, zend_bool
 
        switch (top->type) {
                case EVAL_PARAM:
-                       if (allow_async_unsafe) {
-                               return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC);
-                       }
-                       spprintf(why, 0, "ev command is disallowed during hard interrupt");
-                       return FAILURE;
+                       return PHPDBG_COMMAND_HANDLER(ev)(top TSRMLS_CC);
 
                case RUN_PARAM:
                        if (allow_async_unsafe) {
index 7bb84077303630fc8739f7ccf2ad912a8beb8938..a993c6c8293ee06ffeb41418b74f21f30415ab39 100644 (file)
@@ -44,7 +44,7 @@ const phpdbg_command_t phpdbg_prompt_commands[] = {
        PHPDBG_COMMAND_D(step,    "step through execution",                   's', NULL, 0, PHPDBG_ASYNC_SAFE),
        PHPDBG_COMMAND_D(continue,"continue execution",                       'c', NULL, 0, PHPDBG_ASYNC_SAFE),
        PHPDBG_COMMAND_D(run,     "attempt execution",                        'r', NULL, "|s", 0),
-       PHPDBG_COMMAND_D(ev,      "evaluate some code",                        0 , NULL, "i", 0), /* restricted ASYNC_SAFE */
+       PHPDBG_COMMAND_D(ev,      "evaluate some code",                        0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
        PHPDBG_COMMAND_D(until,   "continue past the current line",           'u', NULL, 0, 0),
        PHPDBG_COMMAND_D(finish,  "continue past the end of the stack",       'F', NULL, 0, 0),
        PHPDBG_COMMAND_D(leave,   "continue until the end of the stack",      'L', NULL, 0, 0),
@@ -671,13 +671,32 @@ out:
        return SUCCESS;
 } /* }}} */
 
+int phpdbg_output_ev_variable(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC) {
+       phpdbg_notice("Printing variable %.*s", (int) len, name);
+       zend_print_zval_r(*zv, 0 TSRMLS_CC);
+       phpdbg_writeln(EMPTY);
+       efree(name);
+       efree(keyname);
+
+       return SUCCESS;
+}
+
 PHPDBG_COMMAND(ev) /* {{{ */
 {
        zend_bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING)==PHPDBG_IS_STEPPING);
        zval retval;
 
+       if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
+               phpdbg_try_access {
+                       phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0 TSRMLS_CC);
+               } phpdbg_catch_access {
+                       phpdbg_error("Could not fetch data, invalid data source");
+               } phpdbg_end_try_access();
+               return SUCCESS;
+       }
+
        if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
-               PHPDBG_G(flags) &= ~ PHPDBG_IS_STEPPING;
+               PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
        }
 
        /* disable stepping while eval() in progress */
@@ -685,8 +704,7 @@ PHPDBG_COMMAND(ev) /* {{{ */
        zend_try {
                if (zend_eval_stringl(param->str, param->len,
                        &retval, "eval()'d code" TSRMLS_CC) == SUCCESS) {
-                       zend_print_zval_r(
-                               &retval, 0 TSRMLS_CC);
+                       zend_print_zval_r(&retval, 0 TSRMLS_CC);
                        phpdbg_writeln(EMPTY);
                        zval_dtor(&retval);
                }
@@ -1292,12 +1310,13 @@ zend_vm_enter:
                }
 
                if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
+                       PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
+
                        phpdbg_writeln(EMPTY);
                        phpdbg_notice("Program received signal SIGINT");
                        DO_INTERACTIVE(1);
                }
 
-               PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
 next:
 
                PHPDBG_G(last_line) = execute_data->opline->lineno;
index d12a304d129c7941a71164c0682e64eb6fea2cef..aba0d60241f1380abf3f327a7ebfa5df4f2f17ef 100644 (file)
@@ -506,3 +506,117 @@ int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry
                return zend_lookup_class(name, name_length, ce TSRMLS_CC);
        }
 }
+
+char *phpdbg_get_property_key(char *key) {
+       if (*key != 0) {
+               return key;
+       }
+       return strchr(key + 1, 0) + 1;
+}
+
+static int phpdbg_parse_variable_arg_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, phpdbg_parse_var_func callback TSRMLS_DC) {
+       return callback(name, len, keyname, keylen, parent, zv TSRMLS_CC);
+}
+
+PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC) {
+       return phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_parse_variable_arg_wrapper, silent, callback TSRMLS_CC);
+}
+
+PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC) {
+       int ret = FAILURE;
+       zend_bool new_index = 1;
+       char *last_index;
+       size_t index_len = 0;
+       zval **zv;
+
+       if (len < 2 || *input != '$') {
+               goto error;
+       }
+
+       while (i++ < len) {
+               if (i == len) {
+                       new_index = 1;
+               } else {
+                       switch (input[i]) {
+                               case '[':
+                                       new_index = 1;
+                                       break;
+                               case ']':
+                                       break;
+                               case '>':
+                                       if (last_index[index_len - 1] == '-') {
+                                               new_index = 1;
+                                               index_len--;
+                                       }
+                                       break;
+
+                               default:
+                                       if (new_index) {
+                                               last_index = input + i;
+                                               new_index = 0;
+                                       }
+                                       if (input[i - 1] == ']') {
+                                               goto error;
+                                       }
+                                       index_len++;
+                       }
+               }
+
+               if (new_index && index_len == 0) {
+                       HashPosition position;
+                       for (zend_hash_internal_pointer_reset_ex(parent, &position);
+                            zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
+                            zend_hash_move_forward_ex(parent, &position)) {
+                               if (i == len || (i == len - 1 && input[len - 1] == ']')) {
+                                       zval *key = emalloc(sizeof(zval));
+                                       size_t namelen;
+                                       char *name;
+                                       char *keyname = estrndup(last_index, index_len);
+                                       zend_hash_get_current_key_zval_ex(parent, key, &position);
+                                       convert_to_string(key);
+                                       name = emalloc(i + Z_STRLEN_P(key) + 2);
+                                       namelen = sprintf(name, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":"");
+                                       efree(key);
+
+                                       ret = callback(name, namelen, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
+                               } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
+                                       phpdbg_parse_variable_with_arg(input, len, Z_OBJPROP_PP(zv), i, callback, silent, arg TSRMLS_CC);
+                               } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
+                                       phpdbg_parse_variable_with_arg(input, len, Z_ARRVAL_PP(zv), i, callback, silent, arg TSRMLS_CC);
+                               } else {
+                                       /* Ignore silently */
+                               }
+                       }
+                       return ret;
+               } else if (new_index) {
+                       char last_chr = last_index[index_len];
+                       last_index[index_len] = 0;
+                       if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
+                               if (!silent) {
+                                       phpdbg_error("%.*s is undefined", (int)i, input);
+                               }
+                               return FAILURE;
+                       }
+                       last_index[index_len] = last_chr;
+                       if (i == len) {
+                               char *name = estrndup(input, len);
+                               char *keyname = estrndup(last_index, index_len);
+
+                               ret = callback(name, len, keyname, index_len, parent, zv, arg TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
+                       } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
+                               parent = Z_OBJPROP_PP(zv);
+                       } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
+                               parent = Z_ARRVAL_PP(zv);
+                       } else {
+                               phpdbg_error("%.*s is nor an array nor an object", (int)i, input);
+                               return FAILURE;
+                       }
+                       index_len = 0;
+               }
+       }
+
+       return ret;
+       error:
+               phpdbg_error("Malformed input");
+               return FAILURE;
+}
index 01aa8490fe55b9ee51a5ab0bb4be191c9084cf23..b54a1d46841cd9f350b7f4c5bfb3342162cc94e9 100644 (file)
@@ -148,4 +148,12 @@ static void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, Ha
 
 int phpdbg_safe_class_lookup(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC);
 
+char *phpdbg_get_property_key(char *key);
+
+typedef int (*phpdbg_parse_var_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv TSRMLS_DC);
+typedef int (*phpdbg_parse_var_with_arg_func)(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, void *arg TSRMLS_DC);
+
+PHPDBG_API int phpdbg_parse_variable(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_func callback, zend_bool silent TSRMLS_DC);
+PHPDBG_API int phpdbg_parse_variable_with_arg(char *input, size_t len, HashTable *parent, size_t i, phpdbg_parse_var_with_arg_func callback, zend_bool silent, void *arg TSRMLS_DC);
+
 #endif /* PHPDBG_UTILS_H */
index e88622444bf7d741bcff1413bc373662731c8ed0..ee937f90631f4fbeb53a81cd555a4acb295828db 100644 (file)
@@ -138,13 +138,6 @@ static int phpdbg_create_array_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC)
        return SUCCESS;
 }
 
-static char *phpdbg_get_property_key(char *key) {
-       if (*key != 0) {
-               return key;
-       }
-       return strchr(key + 1, 0) + 1;
-}
-
 static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
        HashTable *ht;
 
@@ -281,118 +274,37 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) {
                ret = zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
        }
 
-       free(tmp_watch->str);
+       efree(tmp_watch->str);
+       efree(tmp_watch->name_in_parent);
        efree(tmp_watch);
 
        return ret;
 }
 
-static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) {
-       int ret = FAILURE;
-       zend_bool new_index = 1;
-       char *last_index;
-       int index_len = 0;
-       zval **zv;
-
-       if (len < 2 || *input != '$') {
-               goto error;
-       }
-
-       while (i++ < len) {
-               if (i == len) {
-                       new_index = 1;
-               } else {
-                       switch (input[i]) {
-                               case '[':
-                                       new_index = 1;
-                                       break;
-                               case ']':
-                                       break;
-                               case '>':
-                                       if (last_index[index_len - 1] == '-') {
-                                               new_index = 1;
-                                               index_len--;
-                                       }
-                                       break;
-
-                               default:
-                                       if (new_index) {
-                                               last_index = input + i;
-                                               new_index = 0;
-                                       }
-                                       if (input[i - 1] == ']') {
-                                               goto error;
-                                       }
-                                       index_len++;
-                       }
-               }
-
-               if (new_index && index_len == 0) {
-                       HashPosition position;
-                       for (zend_hash_internal_pointer_reset_ex(parent, &position);
-                            zend_hash_get_current_data_ex(parent, (void **)&zv, &position) == SUCCESS;
-                            zend_hash_move_forward_ex(parent, &position)) {
-                               if (i == len || (i == len - 1 && input[len - 1] == ']')) {
-                                       zval *key = emalloc(sizeof(zval));
-                                       phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
-                                       watch->flags = 0;
-                                       zend_hash_get_current_key_zval_ex(parent, key, &position);
-                                       convert_to_string(key);
-                                       watch->str = malloc(i + Z_STRLEN_P(key) + 2);
-                                       watch->str_len = sprintf(watch->str, "%.*s%s%s", (int)i, input, phpdbg_get_property_key(Z_STRVAL_P(key)), input[len - 1] == ']'?"]":"");
-                                       efree(key);
-                                       watch->name_in_parent = zend_strndup(last_index, index_len);
-                                       watch->name_in_parent_len = index_len;
-                                       watch->parent_container = parent;
-                                       phpdbg_create_zval_watchpoint(*zv, watch);
-
-                                       ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
-                               } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
-                                       phpdbg_watchpoint_parse_input(input, len, Z_OBJPROP_PP(zv), i, callback, silent TSRMLS_CC);
-                               } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
-                                       phpdbg_watchpoint_parse_input(input, len, Z_ARRVAL_PP(zv), i, callback, silent TSRMLS_CC);
-                               } else {
-                                       /* Ignore silently */
-                               }
-                       }
-                       return ret;
-               } else if (new_index) {
-                       char last_chr = last_index[index_len];
-                       last_index[index_len] = 0;
-                       if (zend_symtable_find(parent, last_index, index_len + 1, (void **)&zv) == FAILURE) {
-                               if (!silent) {
-                                       phpdbg_error("%.*s is undefined", (int)i, input);
-                               }
-                               return FAILURE;
-                       }
-                       last_index[index_len] = last_chr;
-                       if (i == len) {
-                               phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
-                               watch->flags = 0;
-                               watch->str = zend_strndup(input, len);
-                               watch->str_len = len;
-                               watch->name_in_parent = zend_strndup(last_index, index_len);
-                               watch->name_in_parent_len = index_len;
-                               watch->parent_container = parent;
-                               phpdbg_create_zval_watchpoint(*zv, watch);
-
-                               ret = callback(watch TSRMLS_CC) == SUCCESS || ret == SUCCESS?SUCCESS:FAILURE;
-                       } else if (Z_TYPE_PP(zv) == IS_OBJECT) {
-                               parent = Z_OBJPROP_PP(zv);
-                       } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
-                               parent = Z_ARRVAL_PP(zv);
-                       } else {
-                               phpdbg_error("%.*s is nor an array nor an object", (int)i, input);
-                               return FAILURE;
-                       }
-                       index_len = 0;
-               }
+static int phpdbg_watchpoint_parse_wrapper(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval **zv, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) {
+       int ret;
+       phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
+       watch->flags = 0;
+       watch->str = name;
+       watch->str_len = len;
+       watch->name_in_parent = keyname;
+       watch->name_in_parent_len = keylen;
+       watch->parent_container = parent;
+       phpdbg_create_zval_watchpoint(*zv, watch);
+
+       ret = callback(watch TSRMLS_CC);
+
+       if (ret != SUCCESS) {
+               efree(watch);
+               efree(name);
+               efree(keyname);
        }
 
        return ret;
-       error:
-               phpdbg_error("Malformed input");
-               return FAILURE;
+}
+
+PHPDBG_API int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC), zend_bool silent TSRMLS_DC) {
+       phpdbg_parse_variable_with_arg(input, len, parent, i, (phpdbg_parse_var_with_arg_func) phpdbg_watchpoint_parse_wrapper, 0, callback TSRMLS_CC);
 }
 
 static int phpdbg_watchpoint_parse_symtables(char *input, size_t len, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) {
@@ -550,8 +462,8 @@ static void phpdbg_watch_dtor(void *pDest) {
        phpdbg_deactivate_watchpoint(watch TSRMLS_CC);
        phpdbg_remove_watchpoint(watch TSRMLS_CC);
 
-       free(watch->str);
-       free(watch->name_in_parent);
+       efree(watch->str);
+       efree(watch->name_in_parent);
        efree(watch);
 }