]> granicus.if.org Git - php/commitdiff
Fixed possible segmentation fault upon unset with watchpoints
authorBob Weinand <bobwei9@hotmail.com>
Sat, 22 Mar 2014 13:39:39 +0000 (09:39 -0400)
committerBob Weinand <bobwei9@hotmail.com>
Sat, 22 Mar 2014 13:39:39 +0000 (09:39 -0400)
phpdbg.h
phpdbg_watch.c
phpdbg_watch.h
phpdbg_win.c

index ba59f1d3200aca397ac7a7a11468d17fd9c5d617..c26531559793fbffaa3d746f7fde74bea6a25786 100644 (file)
--- a/phpdbg.h
+++ b/phpdbg.h
@@ -176,6 +176,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
 #endif
        
        phpdbg_btree watchpoint_tree;                /* tree with watchpoints */
+       phpdbg_btree watch_HashTables;               /* tree with original dtors of watchpoints */
        HashTable watchpoints;                       /* watchpoints */
        zend_llist watchlist_mem;                    /* triggered watchpoints */
        zend_bool watchpoint_hit;                    /* a watchpoint was hit */
index f2f127b61ebba70b7fe501189eb4004f6aedf49a..acbbffdb6919647850c70f8d1de4d091df828af3 100644 (file)
@@ -66,12 +66,6 @@ static void phpdbg_change_watchpoint_access(phpdbg_watchpoint_t *watch, int acce
 
        /* pagesize is assumed to be in the range of 2^x */
        m = mprotect(phpdbg_get_page_boundary(watch->addr.ptr), phpdbg_get_total_page_size(watch->addr.ptr, watch->size), access);
-/*
-       if (m == FAILURE) {
-               phpdbg_error("Unable to (un)set watchpoint (mprotect() failed)");
-               zend_bailout();
-       }
-*/
 }
 
 static inline void phpdbg_activate_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
@@ -93,7 +87,6 @@ static inline void phpdbg_remove_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC
 void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch) {
        watch->addr.ptr = addr;
        watch->size = size;
-       watch->type = WATCH_ON_PTR;
 }
 
 void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch) {
@@ -106,12 +99,19 @@ void phpdbg_create_ht_watchpoint(HashTable *ht, phpdbg_watchpoint_t *watch) {
        watch->type = WATCH_ON_HASHTABLE;
 }
 
+void phpdbg_watch_HashTable_dtor(zval **ptr);
+
 static int phpdbg_create_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_DC) {
        watch->flags |= PHPDBG_WATCH_SIMPLE;
 
        phpdbg_store_watchpoint(watch TSRMLS_CC);
        zend_hash_add(&PHPDBG_G(watchpoints), watch->str, watch->str_len, &watch, sizeof(phpdbg_watchpoint_t *), NULL);
 
+       if (watch->type == WATCH_ON_ZVAL) {
+               phpdbg_btree_insert(&PHPDBG_G(watch_HashTables), (zend_ulong)watch->parent_container, watch->parent_container->pDestructor);
+               watch->parent_container->pDestructor = (dtor_func_t)phpdbg_watch_HashTable_dtor;
+       }
+
        phpdbg_activate_watchpoint(watch TSRMLS_CC);
 
        return SUCCESS;
@@ -183,7 +183,7 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
                        }
 
                        new_watch->str = NULL;
-                       new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%.*s%s", watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", new_watch->name_in_parent_len, new_watch->name_in_parent, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":"");
+                       new_watch->str_len = asprintf(&new_watch->str, "%.*s%s%.*s%s", (int)watch->str_len, watch->str, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"[":"->", (int)new_watch->name_in_parent_len, new_watch->name_in_parent, Z_TYPE_P(watch->addr.zv) == IS_ARRAY?"]":"");
 
                        phpdbg_create_zval_watchpoint(*zv, new_watch);
                        phpdbg_create_recursive_watchpoint(new_watch TSRMLS_CC);
@@ -198,7 +198,7 @@ static int phpdbg_create_recursive_watchpoint(phpdbg_watchpoint_t *watch TSRMLS_
                new_watch->name_in_parent = zend_strndup(watch->name_in_parent, watch->name_in_parent_len);
                new_watch->name_in_parent_len = watch->name_in_parent_len;
                new_watch->str = NULL;
-               new_watch->str_len = asprintf(&new_watch->str, "%.*s[]", watch->str_len, watch->str);
+               new_watch->str_len = asprintf(&new_watch->str, "%.*s[]", (int)watch->str_len, watch->str);
                new_watch->flags = PHPDBG_WATCH_RECURSIVE;
 
                phpdbg_create_ht_watchpoint(ht, new_watch);
@@ -229,9 +229,9 @@ static int phpdbg_delete_watchpoint_recursive(phpdbg_watchpoint_t *watch TSRMLS_
                                zend_hash_get_current_key_zval_ex(ht, &key, &position);
                                str = NULL;
                                if (Z_TYPE(key) == IS_STRING) {
-                                       str_len = asprintf(&str, "%.*s%s%.*s%s", watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_STRLEN(key), Z_STRVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
+                                       str_len = asprintf(&str, "%.*s%s%.*s%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_STRLEN(key), Z_STRVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
                                } else {
-                                       str_len = asprintf(&str, "%.*s%s%i%s", watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
+                                       str_len = asprintf(&str, "%.*s%s%li%s", (int)watch->parent->str_len, watch->parent->str, Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"[":"->", Z_LVAL(key), Z_TYPE_P(watch->parent->addr.zv) == IS_ARRAY?"]":"");
                                }
 
                                if (zend_hash_find(&PHPDBG_G(watchpoints), str, str_len, (void **) &watchpoint) == SUCCESS) {
@@ -332,7 +332,7 @@ static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *par
                                        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", i, input, Z_STRLEN_P(key), Z_STRVAL_P(key), input[len - 1] == ']'?"]":"");
+                                       watch->str_len = sprintf(watch->str, "%.*s%.*s%s", (int)i, input, Z_STRLEN_P(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;
@@ -353,7 +353,7 @@ static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *par
                        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) {
-                               phpdbg_error("%.*s is undefined", i, input);
+                               phpdbg_error("%.*s is undefined", (int)i, input);
                                return FAILURE;
                        }
                        last_index[index_len] = last_chr;
@@ -373,7 +373,7 @@ static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *par
                        } else if (Z_TYPE_PP(zv) == IS_ARRAY) {
                                parent = Z_ARRVAL_PP(zv);
                        } else {
-                               phpdbg_error("%.*s is nor an array nor an object", i, input);
+                               phpdbg_error("%.*s is nor an array nor an object", (int)i, input);
                                return FAILURE;
                        }
                        index_len = 0;
@@ -435,6 +435,26 @@ PHPDBG_WATCH(array) /* {{{ */
        return SUCCESS;
 } /* }}} */
 
+void phpdbg_watch_HashTable_dtor(zval **zv) {
+       phpdbg_btree_result *result;
+       if ((result = phpdbg_btree_find(&PHPDBG_G(watchpoint_tree), (zend_ulong)*zv))) {
+               phpdbg_watchpoint_t *watch = result->ptr;
+
+               PHPDBG_G(watchpoint_hit) = 1;
+
+               phpdbg_notice("%.*s was removed, removing watchpoint%s", watch->str_len, watch->str, (watch->flags & PHPDBG_WATCH_RECURSIVE)?" recursively":"");
+
+               if (watch->flags & PHPDBG_WATCH_RECURSIVE) {
+                       phpdbg_delete_watchpoint_recursive(watch TSRMLS_CC);
+               } else {
+                       zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len);
+               }
+       }
+
+       zval_ptr_dtor_wrapper(zv);
+}
+
+
 int phpdbg_create_var_watchpoint(char *input, size_t len TSRMLS_DC) {
        if (phpdbg_rebuild_symtable(TSRMLS_C) == FAILURE) {
                return SUCCESS;
@@ -531,6 +551,7 @@ void phpdbg_setup_watchpoints(TSRMLS_D) {
 
        zend_llist_init(&PHPDBG_G(watchlist_mem), sizeof(void *), phpdbg_watch_mem_dtor, 1);
        phpdbg_btree_init(&PHPDBG_G(watchpoint_tree), sizeof(void *) * 8);
+       phpdbg_btree_init(&PHPDBG_G(watch_HashTables), sizeof(void *) * 8);
        _zend_hash_init(&PHPDBG_G(watchpoints), 8, phpdbg_watch_dtor, 0 ZEND_FILE_LINE_CC);
 }
 
@@ -548,6 +569,10 @@ static void phpdbg_print_changed_zval(phpdbg_watch_memdump *dump TSRMLS_DC) {
                void *oldPtr = (char *)&dump->data + ((size_t)watch->addr.ptr - (size_t)dump->page);
                char reenable = 1;
 
+               if (watch->addr.ptr < dump->page || watch->addr.ptr + watch->size > dump->page + dump->size) {
+                       continue;
+               }
+
                /* Test if the zval was separated and if necessary move the watchpoint */
                if (zend_hash_find(watch->parent_container, watch->name_in_parent, watch->name_in_parent_len + 1, &curTest) == SUCCESS) {
                        if (watch->type == WATCH_ON_HASHTABLE) {
@@ -661,13 +686,12 @@ remove_ht_watch:
 int phpdbg_print_changed_zvals(TSRMLS_D) {
        zend_llist_position pos;
        phpdbg_watch_memdump **dump;
+       int ret;
 
        if (zend_llist_count(&PHPDBG_G(watchlist_mem)) == 0) {
                return FAILURE;
        }
 
-       PHPDBG_G(watchpoint_hit) = 0;
-
        dump = (phpdbg_watch_memdump **)zend_llist_get_last_ex(&PHPDBG_G(watchlist_mem), &pos);
 
        do {
@@ -676,7 +700,10 @@ int phpdbg_print_changed_zvals(TSRMLS_D) {
 
        zend_llist_clean(&PHPDBG_G(watchlist_mem));
 
-       return PHPDBG_G(watchpoint_hit)?SUCCESS:FAILURE;
+       ret = PHPDBG_G(watchpoint_hit)?SUCCESS:FAILURE;
+       PHPDBG_G(watchpoint_hit) = 0;
+
+       return ret;
 }
 
 void phpdbg_list_watchpoints(TSRMLS_D) {
index 71402ae803584bed918d462aa28de3c316b5ab87..a5dac0effabf05e376970a8199a269204a6f8dec 100644 (file)
@@ -52,7 +52,6 @@ static const phpdbg_command_t phpdbg_watch_commands[] = {
 typedef enum {
        WATCH_ON_ZVAL,
        WATCH_ON_HASHTABLE,
-       WATCH_ON_PTR
 } phpdbg_watchtype;
 
 
@@ -109,4 +108,4 @@ static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t s
        return (size_t)phpdbg_get_page_boundary((void *)((size_t)addr + size - 1)) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize;
 }
 
-#endif
\ No newline at end of file
+#endif
index e0180e14c3634ad8ad7ae58838dfca21f022e678..55d4b0f94d1c7a7c3a28dd061a9744953de71abb 100644 (file)
@@ -25,7 +25,6 @@ phpdbg_btree phpdbg_memory_tree;
 
 int mprotect(void *addr, size_t size, int protection) {
        int var;
-       printf("Set protection of %p to %s\n", addr, protection == (PROT_READ | PROT_WRITE) ? "rw": "r-");
        return (int)VirtualProtect(addr, size, protection == (PROT_READ | PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, &var);
 }
 
@@ -33,47 +32,6 @@ size_t virtual_size(void *ptr) {
        return (size_t)phpdbg_btree_find(&phpdbg_memory_tree, (zend_ulong)ptr)->ptr;
 }
 
-/*void *virtual_malloc(size_t size) {
-       size_t real_size = phpdbg_get_total_page_size(NULL, size);
-       void *addr = VirtualAlloc(NULL, real_size, MEM_COMMIT, PAGE_READWRITE);
-       phpdbg_btree_insert(&phpdbg_memory_tree, (zend_ulong)addr, (void *)real_size);
-       return addr;
-}
-
-void virtual_free(void *ptr) {
-       phpdbg_watch_efree(ptr);
-       VirtualFree(ptr, virtual_size(ptr), MEM_RELEASE);
-       phpdbg_btree_delete(&phpdbg_memory_tree, (zend_ulong)ptr);
-}
-
-void *virtual_realloc(void *ptr, size_t size) {
-       void *ret;
-       size_t original_size = virtual_size(ptr);
-
-       if (original_size >= size) {
-               return ptr;
-       }
-       
-       ret = virtual_malloc(size);
-       memcpy(ret, ptr, original_size);
-       virtual_free(ptr);
-       return ret;
-}*/
-
-/*void phpdbg_win_set_mm_heap(zend_mm_heap *heap) {
-       phpdbg_btree_init(&phpdbg_memory_tree, sizeof(void *) * 8);
-       heap->_free = virtual_free;
-       heap->_realloc = virtual_realloc;
-       heap->_malloc = virtual_malloc;
-}
-
-void phpdbg_win_set_mm_storage(zend_mm_storage *storage) {
-       phpdbg_btree_init(&phpdbg_memory_tree, sizeof(void *) * 8);
-       storage->_free = virtual_free;
-       storage->_realloc = virtual_realloc;
-       storage->_malloc = virtual_malloc;
-}*/
-
 int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp) {
        EXCEPTION_RECORD *xr = xp->ExceptionRecord;
        CONTEXT *xc = xp->ContextRecord;
@@ -85,4 +43,4 @@ int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp) {
                }
        }
        return EXCEPTION_CONTINUE_SEARCH;
-}
\ No newline at end of file
+}