ID:               46074
 Comment by:       pogma at thewrittenword dot com
 Reported By:      neko at nekochan dot net
 Status:           Assigned
 Bug Type:         Reproducible crash
 Operating System: IRIX 6.5.30
 PHP Version:      5.3.0alpha2
 Assigned To:      dmitry
 New Comment:

Ok, so the problem is that, by changing the size of execute_data and
the alignment of the Ts member, when an exception occurs, zend no longer
knows when to stop unwinding the stack. 

We added another member to execute_data that keeps a record of the
stack top at the time of creation, we can no longer get there via the Ts
member, because we may have moved it, and the variables used to
calculate it, though they are stored in the execute_data struct, are not
constant, and may have different values at stack unwind time.

We see far fewer problems on ia64-hp-hpux with this patch.


Index: Zend/zend.c
===================================================================
--- Zend/zend.c.orig    2009-07-11 02:57:58.525910184 +0000
+++ Zend/zend.c 2009-07-11 02:59:39.702014580 +0000
@@ -271,12 +276,12 @@
                        }
                        break;
                case IS_DOUBLE:
-                       *expr_copy = *expr;
+                       memcpy(expr_copy,expr,sizeof(zval));
                        zval_copy_ctor(expr_copy);
                        zend_locale_sprintf_double(expr_copy
ZEND_FILE_LINE_CC);
                        break;
                default:
-                       *expr_copy = *expr;
+                       memcpy(expr_copy,expr,sizeof(zval));
                        zval_copy_ctor(expr_copy);
                        convert_to_string(expr_copy);
                        break;
Index: Zend/zend_vm_execute.h
===================================================================
--- Zend/zend_vm_execute.h.orig 2009-07-12 00:32:46.000000000 +0000
+++ Zend/zend_vm_execute.h      2009-07-12 01:38:46.131809202 +0000
@@ -35,6 +35,22 @@
 #undef EX
 #define EX(element) execute_data->element

+#ifndef ZEND_MM_ALIGNMENT
+# define ZEND_MM_ALIGNMENT 8
+# define ZEND_MM_ALIGNMENT_LOG2 3
+#elif ZEND_MM_ALIGNMENT < 4
+# undef ZEND_MM_ALIGNMENT
+# undef ZEND_MM_ALIGNMENT_LOG2
+# define ZEND_MM_ALIGNMENT 4
+# define ZEND_MM_ALIGNMENT_LOG2 2
+#endif
+#ifndef ZEND_MM_ALIGNMENT_MASK
+#define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT-1)
+#endif
+/* Aligned header size */
+#ifndef ZEND_MM_ALIGNED_SIZE
+#define ZEND_MM_ALIGNED_SIZE(size)   ((size + ZEND_MM_ALIGNMENT - 1) &
ZEND_MM_ALIGNMENT_MASK)
+#endif

 ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
 {
@@ -52,13 +68,14 @@
 zend_vm_enter:
        /* Initialize execute_data */
        execute_data = (zend_execute_data *)zend_vm_stack_alloc(
+               (ZEND_MM_ALIGNMENT -1) + (
                sizeof(zend_execute_data) +
                sizeof(zval**) * op_array->last_var *
(EG(active_symbol_table) ? 1 : 2) +
-               sizeof(temp_variable) * op_array->T TSRMLS_CC);
-
+               sizeof(temp_variable) * op_array->T TSRMLS_CC));
        EX(CVs) = (zval***)((char*)execute_data +
sizeof(zend_execute_data));
        memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
-       EX(Ts) = (temp_variable *)(EX(CVs) + op_array->last_var *
(EG(active_symbol_table) ? 1 : 2));
+       EX(top) = zend_vm_stack_top(TSRMLS_C);
+       EX(Ts) = (temp_variable *)
ZEND_MM_ALIGNED_SIZE((size_t)(EX(CVs) + op_array->last_var *
(EG(active_symbol_table) ? 1 : 2)));
        EX(fbc) = NULL;
        EX(called_scope) = NULL;
        EX(object) = NULL;
@@ -602,10 +619,7 @@
        int catched = 0;
        zval restored_error_reporting;

-       void **stack_frame = (void**)EX(Ts) +
-               (sizeof(temp_variable) * EX(op_array)->T) /
sizeof(void*);
-
-       while (zend_vm_stack_top(TSRMLS_C) != stack_frame) {
+       while (zend_vm_stack_top(TSRMLS_C) != EX(top)) {
                zval *stack_zval_p = zend_vm_stack_pop(TSRMLS_C);
                zval_ptr_dtor(&stack_zval_p);
        }
Index: Zend/zend_execute.c
===================================================================
--- Zend/zend_execute.c.orig    2009-07-11 02:57:58.486572714 +0000
+++ Zend/zend_execute.c 2009-07-11 02:59:40.324003151 +0000
@@ -135,7 +135,7 @@
 #define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var &
1L)

 #define INIT_PZVAL_COPY(z,v) \
-       (z)->value = (v)->value; \
+       memcpy(&((z)->value),&((v)->value),sizeof(zvalue_value)); \
        Z_TYPE_P(z) = Z_TYPE_P(v); \
        Z_SET_REFCOUNT_P(z, 1); \
        Z_UNSET_ISREF_P(z);
@@ -722,7 +722,7 @@
                        } else {
                                ALLOC_ZVAL(*variable_ptr_ptr);
                                Z_SET_REFCOUNT_P(value, 1);
-                               **variable_ptr_ptr = *value;
+                              
memcpy(*variable_ptr_ptr,value,sizeof(zval));
                        }
                }
                Z_UNSET_ISREF_PP(variable_ptr_ptr);
Index: Zend/zend_compile.h
===================================================================
--- Zend/zend_compile.h.orig    2009-07-10 03:47:36.000000000 +0000
+++ Zend/zend_compile.h 2009-07-12 01:37:37.230504746 +0000
@@ -324,6 +324,7 @@
        zval *current_this;
        zval *current_object;
        struct _zend_op *call_opline;
+       void **top;
 };

 #define EX(element) execute_data.element


Previous Comments:
------------------------------------------------------------------------

[2009-07-11 17:53:35] neko at nekochan dot net

It's still a huge leap in the right direction. I've been running
phpBB3, 
MediaWiki and Gallery2 under it since shortly after you posted the
patch  
and it's been nothing but fast and stable so far. Previously, I was 
confined to using the 5.2.X branch under IRIX.

Many thanks for tracking this down.

------------------------------------------------------------------------

[2009-07-11 02:13:50] pogma at thewrittenword dot com

Failing a lot of tests. Patch must not be 100% correct. :(

------------------------------------------------------------------------

[2009-07-10 18:32:46] j...@php.net

Dmitry, can you check out the patch above? I wouldn't touch that part
of 
Zend code even with a ten foot stick. :)

------------------------------------------------------------------------

[2009-07-10 18:04:44] neko at nekochan dot net

Excellent, this patch has solved the bus error under MIPSpro/IRIX. 
Thanks much!

------------------------------------------------------------------------

[2009-07-10 17:19:57] pogma at thewrittenword dot com

Zend has a lot of struct assignments, the HP, MIPSPro, DEC compilers
seem to require that both structs be aligned on an 8 byte boundary, when
they're not, we see bus errors at runtime.

At first, I started changing a bunch of struct assignments to memcpy()
but there were too many for my patience, some may be necessary, some not
so much when I changed zend_vm_execute.h to align the Ts member.

How can I attach a patch here?

Oh well, here is the patch inline.
Index: Zend/zend.c
===================================================================
--- Zend/zend.c.orig    2009-07-10 02:55:48.761550751 +0000
+++ Zend/zend.c 2009-07-10 16:12:31.586520160 +0000
@@ -271,12 +276,12 @@
                        }
                        break;
                case IS_DOUBLE:
-                       *expr_copy = *expr;
+                       memcpy(expr_copy,expr,sizeof(zval));
                        zval_copy_ctor(expr_copy);
                        zend_locale_sprintf_double(expr_copy
ZEND_FILE_LINE_CC);
                        break;
                default:
-                       *expr_copy = *expr;
+                       memcpy(expr_copy,expr,sizeof(zval));
                        zval_copy_ctor(expr_copy);
                        convert_to_string(expr_copy);
                        break;
Index: Zend/zend_vm_execute.h
===================================================================
--- Zend/zend_vm_execute.h.orig 2009-07-10 02:55:48.751766645 +0000
+++ Zend/zend_vm_execute.h      2009-07-10 17:03:37.780192396 +0000
@@ -35,6 +35,22 @@
 #undef EX
 #define EX(element) execute_data->element

+#ifndef ZEND_MM_ALIGNMENT
+# define ZEND_MM_ALIGNMENT 8
+# define ZEND_MM_ALIGNMENT_LOG2 3
+#elif ZEND_MM_ALIGNMENT < 4
+# undef ZEND_MM_ALIGNMENT
+# undef ZEND_MM_ALIGNMENT_LOG2
+# define ZEND_MM_ALIGNMENT 4
+# define ZEND_MM_ALIGNMENT_LOG2 2
+#endif
+#ifndef ZEND_MM_ALIGNMENT_MASK
+#define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT-1)
+#endif
+/* Aligned header size */
+#ifndef ZEND_MM_ALIGNED_SIZE
+#define ZEND_MM_ALIGNED_SIZE(size)   ((size + ZEND_MM_ALIGNMENT - 1) &
ZEND_MM_ALIGNMENT_MASK)
+#endif

 ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
 {
@@ -52,13 +67,15 @@
 zend_vm_enter:
        /* Initialize execute_data */
        execute_data = (zend_execute_data *)zend_vm_stack_alloc(
+               ZEND_MM_ALIGNMENT + (
                sizeof(zend_execute_data) +
-               sizeof(zval**) * op_array->last_var *
(EG(active_symbol_table) ? 1 : 2) +
-               sizeof(temp_variable) * op_array->T TSRMLS_CC);
+               sizeof(zval**) * op_array->last_var  * 
+                       (EG(active_symbol_table) ? 1 : 2) +
+               sizeof(temp_variable) * op_array->T TSRMLS_CC));

        EX(CVs) = (zval***)((char*)execute_data +
sizeof(zend_execute_data));
-       memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
-       EX(Ts) = (temp_variable *)(EX(CVs) + op_array->last_var *
(EG(active_symbol_table) ? 1 : 2));
+       memset(EX(CVs), 0, ZEND_MM_ALIGNMENT + (sizeof(zval**) *
op_array->last_var));
+       EX(Ts) = (temp_variable *)
ZEND_MM_ALIGNED_SIZE((size_t)(EX(CVs) + (op_array->last_var) *
(EG(active_symbol_table) ? 1 : 2)));
        EX(fbc) = NULL;
        EX(called_scope) = NULL;
        EX(object) = NULL;
@@ -9085,7 +9102,7 @@
        zend_free_op free_op1;
        zval *value = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1
TSRMLS_CC);

-       EX_T(opline->result.u.var).tmp_var = *value;
+      
memcpy(&EX_T(opline->result.u.var).tmp_var,value,sizeof(zval));
        if (!0) {
                zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
        }
@@ -21620,8 +21637,7 @@

                ZEND_VM_NEXT_OPCODE();
        }
-
-       EX_T(opline->result.u.var).tmp_var = **var_ptr;
+      
memcpy(&EX_T(opline->result.u.var).tmp_var,*var_ptr,sizeof(zval));
        zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var);

        SEPARATE_ZVAL_IF_NOT_REF(var_ptr);
Index: Zend/zend_execute_API.c
===================================================================
--- Zend/zend_execute_API.c.orig        2009-06-05 18:50:32.000000000
+0000
+++ Zend/zend_execute_API.c     2009-07-10 03:47:15.369819116 +0000
@@ -769,7 +769,7 @@

        /* Initialize execute_data */
        if (EG(current_execute_data)) {
-               execute_data = *EG(current_execute_data);
+              
memcpy(&execute_data,EG(current_execute_data),sizeof(zend_execute_data));
                EX(op_array) = NULL;
                EX(opline) = NULL;
                EX(object) = NULL;
Index: Zend/zend_constants.c
===================================================================
--- Zend/zend_constants.c.orig  2009-01-12 21:54:37.000000000 +0000
+++ Zend/zend_constants.c       2009-07-10 16:07:17.211430061 +0000
@@ -263,7 +263,7 @@
        }

        if (retval) {
-               *result = c->value;
+               memcpy(result,&( c->value ), sizeof(zval));
                zval_copy_ctor(result);
                Z_SET_REFCOUNT_P(result, 1);
                Z_UNSET_ISREF_P(result);
Index: Zend/zend_execute.c
===================================================================
--- Zend/zend_execute.c.orig    2009-07-10 02:55:48.000000000 +0000
+++ Zend/zend_execute.c 2009-07-10 15:59:39.100532282 +0000
@@ -135,7 +135,7 @@
 #define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var &
1L)

 #define INIT_PZVAL_COPY(z,v) \
-       (z)->value = (v)->value; \
+       memcpy(&((z)->value),&((v)->value),sizeof(zvalue_value)); \
        Z_TYPE_P(z) = Z_TYPE_P(v); \
        Z_SET_REFCOUNT_P(z, 1); \
        Z_UNSET_ISREF_P(z);
@@ -722,7 +722,7 @@
                        } else {
                                ALLOC_ZVAL(*variable_ptr_ptr);
                                Z_SET_REFCOUNT_P(value, 1);
-                               **variable_ptr_ptr = *value;
+                              
memcpy(*variable_ptr_ptr,value,sizeof(zval));
                        }
                }
                Z_UNSET_ISREF_PP(variable_ptr_ptr);

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/46074

-- 
Edit this bug report at http://bugs.php.net/?id=46074&edit=1

Reply via email to