Commits

rickysu committed 0c827e8 Merge

Merge remote-tracking branch 'upstream/master'

  • Participants
  • Parent commits 23845fd, 02864a8

Comments (0)

Files changed (14)

+-------------------------------------------------------------------- 
+                  The PHP License, version 3.01
+Copyright (c) 1999 - 2013 The PHP Group. All rights reserved.
+-------------------------------------------------------------------- 
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions
+are met:
+
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+ 
+  3. The name "PHP" must not be used to endorse or promote products
+     derived from this software without prior written permission. For
+     written permission, please contact group@php.net.
+  
+  4. Products derived from this software may not be called "PHP", nor
+     may "PHP" appear in their name, without prior written permission
+     from group@php.net.  You may indicate that your software works in
+     conjunction with PHP by saying "Foo for PHP" instead of calling
+     it "PHP Foo" or "phpfoo"
+ 
+  5. The PHP Group may publish revised and/or new versions of the
+     license from time to time. Each version will be given a
+     distinguishing version number.
+     Once covered code has been published under a particular version
+     of the license, you may always continue to use it under the terms
+     of that version. You may also choose to use such covered code
+     under the terms of any subsequent version of the license
+     published by the PHP Group. No one other than the PHP Group has
+     the right to modify the terms applicable to covered code created
+     under this License.
+
+  6. Redistributions of any form whatsoever must retain the following
+     acknowledgment:
+     "This product includes PHP software, freely available from
+     <http://www.php.net/software/>".
+
+THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 
+ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
+PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PHP
+DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------- 
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the PHP Group.
+
+The PHP Group can be contacted via Email at group@php.net.
+
+For more information on the PHP Group and the PHP project, 
+please see <http://www.php.net>.
+
+PHP includes the Zend Engine, freely available at
+<http://www.zend.com>.
+

File classes/buffer.c

 		return;
 	}
 
-	if (!Z_ISREF_P(zdata)) {
-		/* Was not passed by reference */
-		return;
-	}
-
 	PHP_EVENT_FETCH_BUFFER(b, zbuf);
 
 	data = emalloc(sizeof(char) * max_bytes + 1);
 }
 /* }}} */
 
+/* {{{ proto int EventBuffer::readFrom(mixed fd[, int howmuch]);
+ *
+ * Read data from a file descriptor onto the end of the buffer.
+ *
+ * Returns the number of bytes read, or &false; on error.
+ */
+PHP_METHOD(EventBuffer, readFrom)
+{
+	zval                *zbuf = getThis();
+	php_event_buffer_t  *b;
+	zval               **ppzfd;
+	evutil_socket_t      fd;
+	long                 res;
+	long                 howmuch = -1;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l",
+				&ppzfd, &howmuch) == FAILURE) {
+		return;
+	}
+
+	fd = php_event_zval_to_fd(ppzfd TSRMLS_CC);
+	if (fd == -1) {
+		RETURN_FALSE;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	res = evbuffer_read(b->buf, fd, howmuch);
+
+	if (res == -1) {
+		RETURN_FALSE;
+	}
+
+	RETVAL_LONG(res);
+}
+/* }}} */
+
 /* {{{ proto string EventBuffer::substr(int start[, int length]);
  * Returns portion of the buffer contents specified by
  * <parameter>start</parameter> and <parameter>length</parameter>

File classes/buffer_event.c

 	struct timeval      tv_read;
 	struct timeval      tv_write;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll",
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd",
 				&timeout_read, &timeout_write) == FAILURE) {
 		return;
 	}

File classes/event_util.c

 }
 /* }}} */
 
+/* {{{ proto bool EventUtil::getSocketFd(mixed socket)
+ *    Gets numeric file descriptor of a socket. */
+PHP_METHOD(EventUtil, getSocketFd) {
+	zval **ppzfd = NULL;
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z",
+				&ppzfd) == FAILURE) {
+		return;
+	}
+
+	RETVAL_LONG(ppzfd ? php_event_zval_to_fd(ppzfd TSRMLS_CC) : -1);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4

File classes/listener.c

 	PHP_EVENT_FETCH_BASE(base, zbase);
 
 	if (Z_TYPE_PP(ppztarget) == IS_STRING) {
-		struct sockaddr_storage *ss;
+		struct sockaddr_storage ss;
 		socklen_t ss_len = sizeof(ss);
 		memset(&ss, 0, sizeof(ss));
 
     <email>osmanov@php.net</email>
     <active>yes</active>
   </lead>
-  <date>2013-04-17</date>
+  <date>2013-07-21</date>
   <!--{{{ Current version -->
   <version>
-    <release>1.6.1</release>
-    <api>1.6.0</api>
+    <release>1.7.1</release>
+    <api>1.7.0</api>
   </version>
   <stability>
     <release>stable</release>
   </stability>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
-  Fix: bug #64652 where Event::__construct returned valid object, however, with
-  uninitialized internal struct which caused segmentation faults in further
-  method calls
+  Fix: segmentation fault on gc_collect_cycles() after calling Event::free(), 5lava @ Bitbucket reported
+  Fix: assignment reference to "data" property caused 'Fatal error:  Cannot assign by reference to overloaded object'
+  Fix: evnt object dtors sometimes didn't free the 'data' member until the script shutdown phase
   ]]></notes>
   <!--}}}-->
   <!--{{{ Contents -->
       <file role="doc" name="CREDITS"/>
       <file role="doc" name="EXPERIMENTAL"/>
       <file role="doc" name="INSTALL.md"/>
+      <file role="doc" name="LICENSE"/>
       <file role="doc" name="README.md"/>
       <file role="src" name="config.m4"/>
       <file role="src" name="php_event.c"/>
         <file role="src" name="06-timer.phpt"/>
         <file role="src" name="07-listener-error.phpt"/>
         <file role="src" name="08-buffer.phpt"/>
+        <file role="src" name="09-gc-cycles.phpt"/>
+        <file role="src" name="10-event-data-dtor.phpt"/>
       </dir>
     </dir>
   </contents>
   </extsrcrelease>
   <!--{{{ changelog-->
   <changelog>
+    <!--{{{ 1.7.1 -->
+    <release>
+      <version>
+        <release>1.7.1</release>
+        <api>1.7.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 on gc_collect_cycles() after calling Event::free(), 5lava @ Bitbucket reported
+  Fix: assignment reference to "data" property caused 'Fatal error:  Cannot assign by reference to overloaded object'
+  Fix: evnt object dtors sometimes didn't free the 'data' member until the script shutdown phase
+  ]]></notes>
+    </release>
+    <!--}}}-->
+    <!--{{{ 1.7.0 -->
+    <release>
+      <version>
+        <release>1.7.0</release>
+        <api>1.7.0</api>
+      </version>
+      <stability>
+        <release>stable</release>
+        <api>stable</api>
+      </stability>
+      <license uri="http://www.php.net/license">PHP</license>
+      <notes><![CDATA[
+    Merged in 5lava/pecl-event (pull request #1) @bitbucket:
+    Fix: EventBufferEvent::setTimeouts() didn't work with double values
+    Fix: EventBuffer::copyout() didn't work in some cases
+    Add: EventBuffer::readFrom() method (corresponds to evbuffer_read())
+    Add: EventUtil::getSocketFD() method
+  ]]></notes>
+    </release>
+    <!--}}}-->
+    <!--{{{ 1.6.2  -->
+    <release>
+      <version>
+        <release>1.6.2</release>
+        <api>1.6.0</api>
+      </version>
+      <stability>
+        <release>stable</release>
+        <api>stable</api>
+      </stability>
+      <license uri="http://www.php.net/license">PHP</license>
+      <notes><![CDATA[
+  Fix: bug #64678 where Fedora Packaging Guidlines required LICENSE file
+  Fix: bug #64680 where we should check for SKIP_ONLINE_TESTS environment variable
+  Fix: bug #64679 where we had buffer overflow caused by struct sockaddr_storage * pointer
+  ]]></notes>
+    </release>
+    <!--}}}-->
     <!--{{{ 1.6.1 -->
     <release>
       <version>
 	}
 	if (ret == SUCCESS) {
 	    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);
-	    }
 	} else {
 	    zend_object_handlers * std_hnd = zend_get_std_object_handlers();
 	    std_hnd->write_property(object, member, value, key TSRMLS_CC);
 #ifndef PHP_EVENT_H
 #define PHP_EVENT_H
 
-#define PHP_EVENT_VERSION "1.6.1"
+#define PHP_EVENT_VERSION "1.7.1"
 
 #define PHP_EVENT_SUN_PREFIX "unix:"
 
 	ZEND_ARG_INFO(0, len)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_copyout, 0, 0, 2)
+	ZEND_ARG_INFO(1, data)
+	ZEND_ARG_INFO(0, max_bytes)
+ZEND_END_ARG_INFO();
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_len, 0, 0, 1)
 	ZEND_ARG_INFO(0, len)
 ZEND_END_ARG_INFO();
 	ZEND_ARG_INFO(1, port)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_event_util_get_socket_fd, 0, 0, 1)
+	ZEND_ARG_INFO(0, socket)
+ZEND_END_ARG_INFO();
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_event_util_set_socket_option, 0, 0, 4)
 	ZEND_ARG_INFO(0, socket)
 	ZEND_ARG_INFO(0, level)
 	PHP_ME(EventBuffer, prepend,       arginfo_evbuffer_add,           ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, prependBuffer, arginfo_evbuffer_add_buffer,    ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, drain,         arginfo_evbuffer_len,           ZEND_ACC_PUBLIC)
-	PHP_ME(EventBuffer, copyout,       arginfo_evbuffer_remove,        ZEND_ACC_PUBLIC)
+	PHP_ME(EventBuffer, copyout,       arginfo_evbuffer_copyout,       ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, readLine,      arginfo_evbuffer_read_line,     ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, search,        arginfo_evbuffer_search,        ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, searchEol,     arginfo_evbuffer_search_eol,    ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, pullup,        arginfo_evbuffer_pullup,        ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, write,         arginfo_evbuffer_write,         ZEND_ACC_PUBLIC)
+	PHP_ME(EventBuffer, readFrom,      arginfo_evbuffer_write,         ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, substr,        arginfo_evbuffer_substr,        ZEND_ACC_PUBLIC)
 
 	PHP_FE_END
 	PHP_ME(EventUtil, sslRandPoll,           arginfo_event__void,                ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 #endif
 	PHP_ME(EventUtil, getSocketName,   arginfo_event_util_get_socket_name,   ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, getSocketFd,     arginfo_event_util_get_socket_fd,     ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 	PHP_ME(EventUtil, setSocketOption, arginfo_event_util_set_socket_option, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 
 	PHP_FE_END
 PHP_METHOD(EventBuffer, searchEol);
 PHP_METHOD(EventBuffer, pullup);
 PHP_METHOD(EventBuffer, write);
+PHP_METHOD(EventBuffer, readFrom);
 PHP_METHOD(EventBuffer, substr);
 
 PHP_METHOD(EventUtil, getLastSocketErrno);
 PHP_METHOD(EventUtil, sslRandPoll);
 #endif
 PHP_METHOD(EventUtil, getSocketName);
+PHP_METHOD(EventUtil, getSocketFd);
 PHP_METHOD(EventUtil, setSocketOption);
 
 PHP_METHOD(EventBufferPosition, __construct);
 #include "src/priv.h"
 #include "src/util.h"
 
-static inline void _prop_write_zval(zval **ppz, const zval *value)
+#define PHP_EVENT_PROP_REQUIRE(x) \
+	do {                          \
+		if (!(x)) return FAILURE; \
+	} while (0);
+
+static inline void _prop_write_zval(zval **ppz, zval *value)
 {
+#if 0
 	if (!*ppz) {
 		MAKE_STD_ZVAL(*ppz);
 	}
 	/* Make a copy of the zval, avoid direct binding to the address
 	 * of value, since it breaks refcount in 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));
+#endif
+	if (!*ppz) {
+		/* if we assign referenced variable, we should separate it */
+		Z_ADDREF_P(value);
+		if (PZVAL_IS_REF(value)) {
+			SEPARATE_ZVAL(&value);
+		}
+		*ppz = value;
+	} else if (PZVAL_IS_REF(*ppz)) {
+		zval garbage = **ppz; /* old value should be destroyed */
+
+		/* To check: can't *ppz be some system variable like error_zval here? */
+		Z_TYPE_PP(ppz) = Z_TYPE_P(value);
+		(*ppz)->value = value->value;
+		if (Z_REFCOUNT_P(value) > 0) {
+			zval_copy_ctor(*ppz);
+		}
+		zval_dtor(&garbage);
+	} else {
+		zval *garbage = *ppz;
+
+		/* if we assign referenced variable, we should separate it */
+		Z_ADDREF_P(value);
+		if (PZVAL_IS_REF(value)) {
+			SEPARATE_ZVAL(&value);
+		}
+		*ppz = value;
+		zval_ptr_dtor(&garbage);
+	}
 }
 
 static inline void _prop_read_zval(zval *pz, zval **retval)
 	}
 
 	MAKE_STD_ZVAL(*retval);
-	/*REPLACE_ZVAL_VALUE(retval, pz, 1);*/
 	ZVAL_ZVAL(*retval, pz, 1, 0);
 }
 
 {
 	php_event_t *e = (php_event_t *) obj;
 
-	PHP_EVENT_ASSERT(e->event);
+	PHP_EVENT_PROP_REQUIRE(e->event);
 
 	MAKE_STD_ZVAL(*retval);
 	ZVAL_BOOL(*retval, (php_event_is_pending(e->event) ? 1 : 0));
 {
 	php_event_t *e = (php_event_t *) obj;
 
-	PHP_EVENT_ASSERT(e->event);
-
-	return (e->data ? &e->data : NULL);
+	if (!e->event) return NULL;
+	if (!e->data) {
+		MAKE_STD_ZVAL(e->data);
+	}
+	return &e->data;
 }
 /* }}} */
 
 {
 	php_event_t *e = (php_event_t *) obj;
 
-	PHP_EVENT_ASSERT(e->event);
+	PHP_EVENT_PROP_REQUIRE(e->event);
 
 	_prop_read_zval(e->data, retval);
 
 {
 	php_event_t *e = (php_event_t *) obj;
 
-	PHP_EVENT_ASSERT(e->event);
+	PHP_EVENT_PROP_REQUIRE(e->event);
 
 	_prop_write_zval(&e->data, value);
 
 {
 	php_event_buffer_t *b = (php_event_buffer_t *) obj;
 
-	PHP_EVENT_ASSERT(b->buf);
+	PHP_EVENT_PROP_REQUIRE(b->buf);
 
 	MAKE_STD_ZVAL(*retval);
 	if(b && b->buf){
 {
 	php_event_buffer_t *b = (php_event_buffer_t *) obj;
 
-	PHP_EVENT_ASSERT(b->buf);
+	PHP_EVENT_PROP_REQUIRE(b->buf);
 
 	MAKE_STD_ZVAL(*retval);
 	ZVAL_LONG(*retval, evbuffer_get_contiguous_space(b->buf));
 	MAKE_STD_ZVAL(*retval);
 
 	/* Uninitialized / free'd */
+#if 0
 	if (!b->bevent) {
 		ZVAL_NULL(*retval);
 		return SUCCESS;
 	}
-	PHP_EVENT_ASSERT(b->bevent);
+#endif
+	PHP_EVENT_PROP_REQUIRE(b->bevent);
 
 	fd = bufferevent_getfd(b->bevent);
 	if (fd == -1) {

File tests/04-bevent-socket.phpt

 --TEST--
 Check for event_buffer sockets 
+--SKIPIF--
+<?php
+    if (!extension_loaded('event')) {
+        die('skip - event extension not available.');
+    }
+    if (getenv("SKIP_ONLINE_TESTS")) {
+        die("skip test requiring internet connection");
+    }
+?>
 --FILE--
 <?php 
 $base = new EventBase();

File tests/09-gc-cycles.phpt

+--TEST--
+Check for gc_collect_cycles appled after event free
+--SKIPIF--
+<?php if (!function_exists("gc_collect_cycles")) print "skip"; ?>
+--FILE--
+<?php
+$base = new EventBase();
+$e = new Event($base, 0, Event::READ, function(){});
+$e->free();
+gc_collect_cycles(); // segfaults if something goes wrong
+echo "ok";
+?>
+--EXPECT--
+ok

File tests/10-event-data-dtor.phpt

+--TEST--
+Check for event destructor depending on the data property value
+--FILE--
+<?php
+class _Indicator {
+	public $i;
+	public function __construct($i) {
+		$this->i = $i;
+	}
+	public function __destruct() {
+		echo $this->i, "\n";
+	}
+}
+
+$base = new EventBase();
+
+$e1 = new Event($base, -1, Event::TIMEOUT, function() {
+	echo "2\n";
+});
+$e1->addTimer(0.10);
+$e2 = new Event($base, -1, Event::TIMEOUT, function() {
+	echo "3\n";
+});
+$e2->addTimer(0.11);
+
+// obj
+$i1 = new _Indicator(1);
+$e1->data = &$i1;
+
+// obj by ref
+$i2 = new _Indicator(4);
+$e2->data = $i2;
+
+echo "start\n";
+$i1 = null;
+$i2 = null;
+
+$base->loop();
+
+$e1 = null;
+$e2 = null;
+echo "end";
+?>
+--EXPECT--
+start
+1
+2
+3
+4
+end