Consider the following small test case where $y is first made to be a reference to $x. And next, we assign a literal to $y. Example #1: <?php $x = 5; $y = &$x;
$y = null; <--- When we come to the third assignment statement above we try to increase (followed quickly by a decrease) of the "refcount" on the right hand side ZVAL (the null zval) in the following piece of code in zend_assign_to_variable(): } else if (PZVAL_IS_REF(variable_ptr)) { if (variable_ptr!=value) { zend_uint refcount = variable_ptr->refcount; zval garbage; if (type!=IS_TMP_VAR) { value->refcount++; <----- incrementing the refcount of RHS zval } garbage = *variable_ptr; *variable_ptr = *value; variable_ptr->refcount = refcount; variable_ptr->is_ref = 1; if (type!=IS_TMP_VAR) { zendi_zval_copy_ctor(*variable_ptr); value->refcount--; <------ and then decrementing it back... } zendi_zval_dtor(garbage); } } I am trying to understand the rationale for value->refcount++ and value->refcount-- above. Why do we need that? With PHP running in apache+APC environment, the "null" literal is an IS_CONST operand in the op_array in APC (shared memory). And incrementing/decrementing a ref count on the shared memory area without a mutex can cause unexpected problems due to race conditions (and eventually lead to memory corruptions etc.) Recall that zend_opcode.c:pass_two() sets "is_ref" on all IS_CONST operands to 1, as a way to allow op_arrays to be sharable across processes. And indeed, in the simpler case of an assignment such as in the following example (#2), zend_assign_to_variable() notices that the RHS has "is_ref" set and goes on to make a copy (rather than incrementing the RHS's refcount). Example #2: <?php $a = 5; But in the case the LHS is itself an "is_ref" (like in the example #1) it doesn't seem to make a similar check on the RHS (to see if it is safe to modify the refcount on the RHS). Why? regards, Kannan