andreiz / php-zookeeper

A PHP extension for interfacing with Apache ZooKeeper

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

watch error:PHP Fatal error: Corrupted fcall_info provided to zend_call_function()

hhp12360 opened this issue · comments

commented
<?php
/**
 * PHP Zookeeper
 *
 * PHP Version 5.3
 *
 * The PHP License, version 3.01
 *
 * @category  Libraries
 * @package   PHP-Zookeeper
 * @author    Lorenzo Alberton <l.alberton@quipo.it>
 * @copyright 2012 PHP Group
 * @license   http://www.php.net/license The PHP License, version 3.01
 * @link      https://github.com/andreiz/php-zookeeper
 */

/**
 * Example interaction with the PHP Zookeeper extension
 *
 * @category  Libraries
 * @package   PHP-Zookeeper
 * @author    Lorenzo Alberton <l.alberton@quipo.it>
 * @copyright 2012 PHP Group
 * @license   http://www.php.net/license The PHP License, version 3.01
 * @link      https://github.com/andreiz/php-zookeeper
 */
class Zookeeper_Example
{
	/**
	 * @var Zookeeper
	 */
	private $zookeeper;

    /**
      * @var Callback container
      */
    private $callback = array();

	/**
	 * Constructor
	 *
	 * @param string $address CSV list of host:port values (e.g. "host1:2181,host2:2181")
	 */
	public function __construct($address) {
		$this->zookeeper = new Zookeeper($address);
	}

	/**
	 * Set a node to a value. If the node doesn't exist yet, it is created.
	 * Existing values of the node are overwritten
	 *
	 * @param string $path  The path to the node
	 * @param mixed  $value The new value for the node
	 *
	 * @return mixed previous value if set, or null
	 */
	public function set($path, $value) {
		if (!$this->zookeeper->exists($path)) {
			$this->makePath($path);
			$this->makeNode($path, $value);
		} else {
			$this->zookeeper->set($path, $value);
		}
	}

	/**
	 * Equivalent of "mkdir -p" on ZooKeeper
	 *
	 * @param string $path  The path to the node
	 * @param string $value The value to assign to each new node along the path
	 *
	 * @return bool
	 */
	public function makePath($path, $value = '') {
		$parts = explode('/', $path);
		$parts = array_filter($parts);
		$subpath = '';
		while (count($parts) > 1) {
			$subpath .= '/' . array_shift($parts);
			if (!$this->zookeeper->exists($subpath)) {
				$this->makeNode($subpath, $value);
			}
		}
	}

	/**
	 * Create a node on ZooKeeper at the given path
	 *
	 * @param string $path   The path to the node
	 * @param string $value  The value to assign to the new node
	 * @param array  $params Optional parameters for the Zookeeper node.
	 *                       By default, a public node is created
	 *
	 * @return string the path to the newly created node or null on failure
	 */
	public function makeNode($path, $value, array $params = array()) {
		if (empty($params)) {
			$params = array(
				array(
					'perms'  => Zookeeper::PERM_ALL,
					'scheme' => 'world',
					'id'     => 'anyone',
				)
			);
		}
		return $this->zookeeper->create($path, $value, $params);
	}

	/**
	 * Get the value for the node
	 *
	 * @param string $path the path to the node
	 *
	 * @return string|null
	 */
	public function get($path) {
		if (!$this->zookeeper->exists($path)) {
			return null;
		}
		return $this->zookeeper->get($path);
	}

	/**
	 * List the children of the given path, i.e. the name of the directories
	 * within the current node, if any
	 *
	 * @param string $path the path to the node
	 *
	 * @return array the subpaths within the given node
	 */
	public function getChildren($path) {
		if (strlen($path) > 1 && preg_match('@/$@', $path)) {
			// remove trailing /
			$path = substr($path, 0, -1);
		}
		return $this->zookeeper->getChildren($path);
	}

	/**
	 * Delete the node if it does not have any children
	 *
	 * @param string $path the path to the node
	 *
	 * @return true if node is deleted else null
	 */

	 public function deleteNode($path)
	 {
	 	if(!$this->zookeeper->exists($path))
	 	{
	 		return null;
	 	}
	 	else
	 	{
	 		return $this->zookeeper->delete($path);
	 	}
	 }

    /**
	 * Wath a given path
	 * @param string $path the path to node
	 * @param callable $callback callback function
	 * @return string|null
	 */
	public function watch($path, $callback)
	{
		if (!is_callable($callback)) {
			return null;
		}

		if ($this->zookeeper->exists($path)) {
			if (!isset($this->callback[$path])) {
				$this->callback[$path] = array();
			}
			if (!in_array($callback, $this->callback[$path])) {
				$this->callback[$path][] = $callback;
				return $this->zookeeper->get($path, array($this, 'watchCallback'));
			}
		}
	}

	/**
	 * Wath event callback warper
	 * @param int $event_type
	 * @param int $stat
	 * @param string $path
	 * @return the return of the callback or null
	 */
	public function watchCallback($event_type, $stat, $path)
	{
		if (!isset($this->callback[$path])) {
			return null;
		}

		foreach ($this->callback[$path] as $callback) {
			$this->zookeeper->get($path, array($this, 'watchCallback'),$stat);
			return call_user_func($callback);
		}
	}

	/**
	 * Delete watch callback on a node, delete all callback when $callback is null
	 * @param string $path
	 * @param callable $callback
	 * @return boolean|NULL
	 */
	public function cancelWatch($path, $callback = null)
	{
		if (isset($this->callback[$path])) {
			if (empty($callback)) {
				unset($this->callback[$path]);
				$this->zookeeper->get($path); //reset the callback
				return true;
			} else {
				$key = array_search($callback, $this->callback[$path]);
				if ($key !== false) {
					unset($this->callback[$path][$key]);
					return true;
				} else {
					return null;
				}
			}
		} else {
			return null;
		}
	}
}


$zk = new Zookeeper_Example("localhost:2181");

function callback() {
    echo "in watch callback\n";
}

$zk->set("/test123","abc");
$ret = $zk->watch("/test123", "callback");
$zk->set("/bar", 1);
$ret = $zk->watch("/bar", "callback");

while (true) {
    sleep(1);	
    zookeeper_dispatch();
}

I set path value many times it's crash and error msg:PHP Fatal error: Corrupted fcall_info provided to zend_call_function() in

Env:php5.6 and php7.0

The steps as follows:
1:set /test123 1;
2:set /bar 1;
3:set /bar 1;
4:set /test123 1; this time it's crash

Confirmed.
Ping @jbboehr 🥇
: )

$ php -dextension=modules/zookeeper.so issue-89.php 
in watch callback
in watch callback
in watch callback
PHP Fatal error:  Corrupted fcall_info provided to zend_call_function() in /home/timandes/php-zookeeper/issue-89.php on line 243

$ php -v
PHP 5.6.11-1ubuntu3.4 (cli) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
$ php -dextension=modules/zookeeper.so issue-89.php 
in watch callback
in watch callback
in watch callback
PHP Fatal error:  Corrupted fcall_info provided to zend_call_function() in Unknown on line 0

Fatal error: Corrupted fcall_info provided to zend_call_function() in Unknown on line 0

$ php -v
PHP 7.1.5 (cli) (built: Jun  3 2017 23:17:36) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

It seems that it is wrong to use member h of struct php_cb_data_t to save the index number indicating where current *cbd located in Hashtable(php_zk_t.callbacks).
When oneshot callbacks removed, the index numbers saved in member h of remaining *cbds are not be fixed. So they may not point to existing Hashtable items.

commented

The problem seems to be solved, thanks