Commits

Ruslan Osmanov committed eb0ded1

Fix: segmentation fault in EvLoop/EvWatcher dtors caused by reference variables stored in 'data' property
Fix: EvLoop/EvWatcher object dtors sometimes didn't free the 'data' member until the script shutdown phase

Comments (0)

Files changed (6)

 	    ret = zend_hash_find((HashTable *) obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd);
 	}
 	if (ret == SUCCESS) {
+	    Z_ADDREF_P(value);
 	    hnd->write_func(obj, value TSRMLS_CC);
-	    if (! PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) == 0) {
-	        Z_ADDREF_P(value);
-	        zval_ptr_dtor(&value);
-	    }
+	    zval_ptr_dtor(&value);
 	} else {
 	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
 	    std_hnd->write_property(object, member, value, key TSRMLS_CC);
   <date>2013-07-20</date>
   <!--{{{ Current version -->
   <version>
-    <release>0.2.7</release>
+    <release>0.2.8</release>
     <api>0.2.0</api>
   </version>
   <stability>
   </stability>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
-  Fix: because of a typo in ev.c dump stuff didn't work in PHP<5.5.0
-  Change: removed "Returning previously created default loop" warning 
+  Fix: segmentation fault in EvLoop/EvWatcher dtors caused by reference variables stored in 'data' property
+  Fix: EvLoop/EvWatcher object dtors sometimes didn't free the 'data' member until the script shutdown phase
   ]]></notes>
   <!--}}}-->
   <!--{{{ Contents -->
         <file role="src" name="08_priority.phpt"/>
         <file role="src" name="09_loop_timer.phpt"/>
         <file role="src" name="10_signal.phpt"/>
+        <file role="src" name="11_watcher_data.phpt"/>
         <file role="src" name="bug64788.phpt"/>
       </dir>
       <dir name="libev">
   </extsrcrelease>
   <!--{{{ changelog-->
   <changelog>
+    <!--{{{ 0.2.8 -->
+    <release>
+      <version>
+        <release>0.2.8</release>
+        <api>0.2.0</api>
+      </version>
+      <stability>
+        <release>stable</release>
+        <api>stable</api>
+      </stability>
+      <license uri="http://www.php.net/license">PHP</license>
+      <notes><![CDATA[
+  Fix: segmentation fault in EvLoop/EvWatcher dtors caused by reference variables stored in 'data' property
+  Fix: EvLoop/EvWatcher object dtors sometimes didn't free the 'data' member until the script shutdown phase
+  ]]></notes>
+    </release>
+    <!--}}}-->
     <!--{{{ 0.2.7 -->
     <release>
       <version>
     /* Make a copy of the zval, avoid direct binding to the address
      * of value, since it breaks refcount in php_ev_read_property()
      * causing further leaks and memory access violations */
-	REPLACE_ZVAL_VALUE(ppz, value, 1);
+	REPLACE_ZVAL_VALUE(ppz, value, PZVAL_IS_REF((zval *)value));
 }
 
 static inline void php_ev_prop_read_zval(const zval *pz, zval **retval)
 	}
 
     MAKE_STD_ZVAL(*retval);
-    REPLACE_ZVAL_VALUE(retval, pz, 1);
+
+    REPLACE_ZVAL_VALUE(retval, pz, PZVAL_IS_REF((zval *)pz));
 }
 
 
 {
 	PHP_EV_ASSERT(obj->ptr);
 
-	return &PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data;
+	if (!PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data) {
+		MAKE_STD_ZVAL(PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data);
+	}
+	return &(PHP_EV_LOOP_OBJECT_FETCH_FROM_OBJECT(obj)->data);
 }
 /* }}} */
 
 {
 	PHP_EV_ASSERT(obj->ptr);
 
+	zval *data = PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)->data;
+	if (!data) {
+		MAKE_STD_ZVAL(PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)->data);
+	}
+
 	return &PHP_EV_WATCHER_FETCH_FROM_OBJECT(obj)->data;
 }
 /* }}} */
 extern zend_module_entry ev_module_entry;
 #define phpext_ev_ptr &ev_module_entry
 
-#define PHP_EV_VERSION "0.2.7"
+#define PHP_EV_VERSION "0.2.8"
 
 #endif /* PHP_EV_H */
 

tests/02_ev_construct_variation.phpt

 --FILE--
 <?php
 
+class _A {
+	function __destruct() { echo __METHOD__, PHP_EOL; }
+}
+$obj = new _A();
+
 $prev_data = "prev_data";
 $third_data = "new_data";
 
 $loop->data = $third_data;
 var_dump($loop->data);
 
+$loop->data = &$obj;
+var_dump($loop->data);
+
 // Multiple attempts to create the default loop
 $loop2 = EvLoop::defaultLoop();
 $loop2 = EvLoop::defaultLoop();
 $loop = new EvLoop(Ev::FLAG_AUTO);
 // Should be NULL
 var_dump($loop->data);
+$obj = NULL;
 ?>
---CLEAN--
 --EXPECTF--
 string(9) "prev_data"
 string(8) "new data"
 string(12) "new new data"
 string(8) "new_data"
+object(_A)#1 (0) {
+}
 NULL
+_A::__destruct

tests/11_watcher_data.phpt

+--TEST--
+Check for watcher destruction depending on it's data property value
+--FILE--
+<?php
+class indicator {
+	public $i;
+	public function __construct($i) {
+		$this->i = $i;
+	}
+	public function __destruct() {
+		echo $this->i;
+	}
+}
+
+function test() {
+	$loop = new EvLoop();
+	$i1 = new indicator(1);
+	$i2 = new indicator(2);
+
+	// store data as ref to object
+	$t1 = $loop->timer(1, 0, function () {});
+	$t1->data = &$i1;
+
+	// store data as object
+	$t2 = $loop->timer(1, 0, function () {});
+	$t2->data = $i2;
+
+	echo "0";
+	$t1->stop();
+	$t2->stop();
+	$loop->stop();
+
+	$i1     = null;
+	$i2     = null;
+	$timer  = null;
+	$timer2 = null;
+	$loop   = null;
+	echo "3";
+}
+
+test();
+?>
+--EXPECT--
+0123
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.