Ruslan Osmanov avatar Ruslan Osmanov committed 465e943

Fix: crash due to destruction of the internal bufferevent buffers

Comments (0)

Files changed (5)

classes/buffer_event.c

 		PHP_EVENT_ASSERT(bev->self);
 
 		if (bev->self) {
-			ZVAL_ZVAL(arg_bevent, bev->self, 0, 0);
-			Z_ADDREF_P(bev->self);
+			ZVAL_ZVAL(arg_bevent, bev->self, 1, 0);
 		} else {
 			ZVAL_NULL(arg_bevent);
 		}
 		PHP_EVENT_ASSERT(bev->self);
 
 		if (bev->self) {
-			ZVAL_ZVAL(arg_bevent, bev->self, 0, 0);
-			Z_ADDREF_P(bev->self);
+			ZVAL_ZVAL(arg_bevent, bev->self, 1, 0);
 		} else {
 			ZVAL_NULL(arg_bevent);
 		}
 /* }}} */
 
 /* {{{ proto EventBuffer EventBufferEvent::getInput(void);
+ *
  * Returns an input EventBuffer object associated with the buffer event */
 PHP_METHOD(EventBufferEvent, getInput)
 {
 
 	PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_buffer_ce);
 	PHP_EVENT_FETCH_BUFFER(b, return_value);
+	/* Don't do this. It's normal to have refcount = 1 here.
+	 * If we got bugs, we most likely free'd an internal buffer somewhere
+	 * Z_ADDREF_P(return_value);*/
 
-	b->buf = bufferevent_get_input(bev->bevent);
+	b->buf      = bufferevent_get_input(bev->bevent);
+	b->internal = 1;
 }
 /* }}} */
 
 /* {{{ proto EventBuffer EventBufferEvent::getOutput(void);
+ *
  * Returns an output EventBuffer object associated with the buffer event */
 PHP_METHOD(EventBufferEvent, getOutput)
 {
 
 	PHP_EVENT_INIT_CLASS_OBJECT(return_value, php_event_buffer_ce);
 	PHP_EVENT_FETCH_BUFFER(b, return_value);
+	/* Don't do this. It's normal to have refcount = 1 here.
+	 * If we got bugs, we most likely free'd an internal buffer somewhere
+	 * Z_ADDREF_P(return_value);*/
 
-	b->buf = bufferevent_get_output(bev->bevent);
+	b->buf      = bufferevent_get_output(bev->bevent);
+	b->internal = 1;
 }
 /* }}} */
 

examples/httpv0client.php

 
 /* Read callback */
 function readcb($bev, $base) {
-	echo __FUNCTION__, PHP_EOL;
 	$input = $bev->getInput();
 
 	while (($n = $input->remove($buf, 1024)) > 0) {

examples/httpv0client2.php

 
 /* Read callback */
 function readcb($bev, $base) {
-	echo __FUNCTION__, PHP_EOL;
 	$input = $bev->getInput();
 
 	while (($n = $input->remove($buf, 1024)) > 0) {
 static HashTable event_config_properties;
 static HashTable event_bevent_properties;
 static HashTable event_buffer_properties;
+
+#if 0
 static HashTable event_util_properties;
 
 #if HAVE_EVENT_EXTRA_LIB
 static HashTable event_http_conn_properties;
 static HashTable event_http_properties;
 #endif
+#endif
 
 static zend_object_handlers object_handlers;
 
 
 	PHP_EVENT_ASSERT(b && b->buf);
 
-	evbuffer_free(b->buf);
+	/* If we got the buffer in, say, a read callback the buffer
+	 * is destroyed when the callback is done as any normal variable.
+	 * Zend MM calls destructor which eventually calls this function.
+	 * We'll definitely crash, if we call evbuffer_free() on an internal
+	 * bufferevent buffer. */
 
-	event_generic_object_free_storage(ptr TSRMLS_CC);
+	if (!b->internal) {
+		evbuffer_free(b->buf);
+
+		event_generic_object_free_storage(ptr TSRMLS_CC);
+	}
 }
 /* }}} */
 
 	php_event_abstract_object_t *obj;
 	zend_class_entry *ce_parent = ce;
 
-	obj = ecalloc(1, size);
-	obj->prop_handler = NULL;
+	obj = emalloc(size);
+	memset(obj, 0, size);
 
 	while (ce_parent->type != ZEND_INTERNAL_CLASS && ce_parent->parent != NULL) {
 		ce_parent = ce_parent->parent;
 
 	struct bufferevent    *bevent;
 	int                    stream_id;   /* Resource ID of the file descriptor. -1 if none */
-	zval                  *self;        /* Object itself. For callbacks       */
-	zval                  *data;        /* User custom data                   */
+	zval                  *self;        /* Object itself. For callbacks                   */
+	zval                  *data;        /* User custom data                               */
 
     /* fci and fcc members represent userspace callbacks */
 	zend_fcall_info       *fci_read;
 /* Represents EventBuffer object */
 typedef struct {
 	PHP_EVENT_OBJECT_HEAD;
+	zend_bool internal; /* Whether is an internal buffer of a bufferevent */
 
 	struct evbuffer *buf;
 } php_event_buffer_t;
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.