com php-src: Refactor HashContext into an object.: NEWS ext/hash/hash.c ext/hash/php_hash.h ext/hash/tests/hash-clone.phpt ex t/hash/tests/hash_copy_002.phpt ext/hash/tests/ne w-context.phpt ext/hash/tests/reuse.phpt ext/hash/tests /serialize-context.phpt

[email protected] (Sara Golemon)
Newsgroups php.cvs
Message-ID <[email protected]>
Commit:    b7f59be9f48d0079e222e26c01cd0a067480b97e
Author:    =?UTF-8?q?Rouven=20We=C3=9Fling?= <[email protected]>         Mon, 26 Dec 2016 17:22:54 -0800
Committer: Sara Golemon <[email protected]>      Tue, 31 Jan 2017 19:28:35 -0800
Parents:   5a9742e34b033dbbf98ede52feed41e6897199e3
Branches:  master

Link:       http://git.php.net/?p=php-src.git;a=commitdiff;h=b7f59be9f48d0079e222e26c01cd0a067480b97e

Log:
Refactor HashContext into an object.

This allows better type hinting as well as potentially adding
methods in a followup diff.

Original patch by Rouven Weßling (github.com/realityking)
Heavily modified by Sara Golemon (github.com/sgolemon)

Changed paths:
  M  NEWS
  M  ext/hash/hash.c
  M  ext/hash/php_hash.h
  A  ext/hash/tests/hash-clone.phpt
  M  ext/hash/tests/hash_copy_002.phpt
  A  ext/hash/tests/new-context.phpt
  A  ext/hash/tests/reuse.phpt
  A  ext/hash/tests/serialize-context.phpt
diff_b7f59be9f48d0079e222e26c01cd0a067480b97e.txt (text/plain, 33.8 KB)
diff --git a/NEWS b/NEWS
index d0157b3..e5cce9c 100644
--- a/NEWS
+++ b/NEWS
@@ -75,6 +75,7 @@ PHP                                                                        NEWS
 - hash:
   . Fixed bug #73961 (environmental build dependency in hash sha3 source).
     (krakjoe)
+  . Changed HashContext from resource to object. (Rouven Weßling, Sara)
 
 - Mbstring:
   . Implemented request #66024 (mb_chr() and mb_ord()). (Masakielastic, Yasuo)
diff --git a/ext/hash/hash.c b/ext/hash/hash.c
index 567c1dd..e2e478f 100644
--- a/ext/hash/hash.c
+++ b/ext/hash/hash.c
@@ -28,8 +28,12 @@
 #include "ext/standard/info.h"
 #include "ext/standard/file.h"
 
-static int php_hash_le_hash;
+#include "zend_interfaces.h"
+#include "zend_exceptions.h"
+
 HashTable php_hash_hashtable;
+zend_class_entry *php_hashcontext_ce;
+static zend_object_handlers php_hashcontext_handlers;
 
 #ifdef PHP_MHASH_BC
 struct mhash_bc_entry {
@@ -327,45 +331,43 @@ PHP_FUNCTION(hash_hmac_file)
 }
 /* }}} */
 
-
-/* {{{ proto resource hash_init(string algo[, int options, string key])
-Initialize a hashing context */
-PHP_FUNCTION(hash_init)
-{
-	char *algo, *key = NULL;
-	size_t algo_len, key_len = 0;
-	int argc = ZEND_NUM_ARGS();
+static void php_hashcontext_ctor(INTERNAL_FUNCTION_PARAMETERS, zval *objval) {
+	zend_string *algo, *key = NULL;
 	zend_long options = 0;
+	int argc = ZEND_NUM_ARGS();
 	void *context;
 	const php_hash_ops *ops;
-	php_hash_data *hash;
+	php_hashcontext_object *hash = php_hashcontext_from_object(Z_OBJ_P(objval));
 
-	if (zend_parse_parameters(argc, "s|ls", &algo, &algo_len, &options, &key, &key_len) == FAILURE) {
-		return;
+	if (zend_parse_parameters(argc, "S|lS", &algo, &options, &key) == FAILURE) {
+		zval_dtor(return_value);
+		RETURN_NULL();
 	}
 
-	ops = php_hash_fetch_ops(algo, algo_len);
+	ops = php_hash_fetch_ops(ZSTR_VAL(algo), ZSTR_LEN(algo));
 	if (!ops) {
-		php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", algo);
-		RETURN_FALSE;
-	}
-
-	if (options & PHP_HASH_HMAC && !ops->is_crypto) {
-		php_error_docref(NULL, E_WARNING, "HMAC requested with a non-cryptographic hashing algorithm: %s", algo);
+		php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", ZSTR_VAL(algo));
+		zval_dtor(return_value);
 		RETURN_FALSE;
 	}
 
-	if (options & PHP_HASH_HMAC &&
-		key_len <= 0) {
-		/* Note: a zero length key is no key at all */
-		php_error_docref(NULL, E_WARNING, "HMAC requested without a key");
-		RETURN_FALSE;
+	if (options & PHP_HASH_HMAC) {
+		if (!ops->is_crypto) {
+			php_error_docref(NULL, E_WARNING, "HMAC requested with a non-cryptographic hashing algorithm: %s", ZSTR_VAL(algo));
+			zval_dtor(return_value);
+			RETURN_FALSE;
+		}
+		if (!key || (ZSTR_LEN(key) <= 0)) {
+			/* Note: a zero length key is no key at all */
+			php_error_docref(NULL, E_WARNING, "HMAC requested without a key");
+			zval_dtor(return_value);
+			RETURN_FALSE;
+		}
 	}
 
 	context = emalloc(ops->context_size);
 	ops->hash_init(context);
 
-	hash = emalloc(sizeof(php_hash_data));
 	hash->ops = ops;
 	hash->context = context;
 	hash->options = options;
@@ -377,14 +379,14 @@ PHP_FUNCTION(hash_init)
 
 		memset(K, 0, ops->block_size);
 
-		if (key_len > (size_t)ops->block_size) {
+		if (ZSTR_LEN(key) > (size_t)ops->block_size) {
 			/* Reduce the key first */
-			ops->hash_update(context, (unsigned char *) key, key_len);
+			ops->hash_update(context, (unsigned char *) ZSTR_VAL(key), ZSTR_LEN(key));
 			ops->hash_final((unsigned char *) K, context);
 			/* Make the context ready to start over */
 			ops->hash_init(context);
 		} else {
-			memcpy(K, key, key_len);
+			memcpy(K, ZSTR_VAL(key), ZSTR_LEN(key));
 		}
 
 		/* XOR ipad */
@@ -394,51 +396,59 @@ PHP_FUNCTION(hash_init)
 		ops->hash_update(context, (unsigned char *) K, ops->block_size);
 		hash->key = (unsigned char *) K;
 	}
+}
 
-	RETURN_RES(zend_register_resource(hash, php_hash_le_hash));
+/* {{{ proto HashContext hash_init(string algo[, int options, string key])
+Initialize a hashing context */
+PHP_FUNCTION(hash_init)
+{
+	object_init_ex(return_value, php_hashcontext_ce);
+	php_hashcontext_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value);
 }
 /* }}} */
 
-/* {{{ proto bool hash_update(resource context, string data)
+#define PHP_HASHCONTEXT_VERIFY(func, hash) { \
+	if (!hash->context) { \
+		php_error(E_WARNING, "%s(): supplied resource is not a valid Hash Context resource", func); \
+		RETURN_NULL(); \
+	} \
+}
+
+/* {{{ proto bool hash_update(HashContext context, string data)
 Pump data into the hashing algorithm */
 PHP_FUNCTION(hash_update)
 {
 	zval *zhash;
-	php_hash_data *hash;
-	char *data;
-	size_t data_len;
+	php_hashcontext_object *hash;
+	zend_string *data;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &zhash, &data, &data_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "OS", &zhash, php_hashcontext_ce, &data) == FAILURE) {
 		return;
 	}
 
-	if ((hash = (php_hash_data *)zend_fetch_resource(Z_RES_P(zhash), PHP_HASH_RESNAME, php_hash_le_hash)) == NULL) {
-		RETURN_FALSE;
-	}
-
-	hash->ops->hash_update(hash->context, (unsigned char *) data, data_len);
+	hash = php_hashcontext_from_object(Z_OBJ_P(zhash));
+	PHP_HASHCONTEXT_VERIFY("hash_update", hash);
+	hash->ops->hash_update(hash->context, (unsigned char *) ZSTR_VAL(data), ZSTR_LEN(data));
 
 	RETURN_TRUE;
 }
 /* }}} */
 
-/* {{{ proto int hash_update_stream(resource context, resource handle[, integer length])
+/* {{{ proto int hash_update_stream(HashContext context, resource handle[, integer length])
 Pump data into the hashing algorithm from an open stream */
 PHP_FUNCTION(hash_update_stream)
 {
 	zval *zhash, *zstream;
-	php_hash_data *hash;
+	php_hashcontext_object *hash;
 	php_stream *stream = NULL;
 	zend_long length = -1, didread = 0;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|l", &zhash, &zstream, &length) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Or|l", &zhash, php_hashcontext_ce, &zstream, &length) == FAILURE) {
 		return;
 	}
 
-	if ((hash = (php_hash_data *)zend_fetch_resource(Z_RES_P(zhash), PHP_HASH_RESNAME, php_hash_le_hash)) == NULL) {
-		RETURN_FALSE;
-	}
-
+	hash = php_hashcontext_from_object(Z_OBJ_P(zhash));
+	PHP_HASHCONTEXT_VERIFY("hash_update_stream", hash);
 	php_stream_from_zval(stream, zstream);
 
 	while (length) {
@@ -462,27 +472,27 @@ PHP_FUNCTION(hash_update_stream)
 }
 /* }}} */
 
-/* {{{ proto bool hash_update_file(resource context, string filename[, resource context])
+/* {{{ proto bool hash_update_file(HashContext context, string filename[, resource context])
 Pump data into the hashing algorithm from a file */
 PHP_FUNCTION(hash_update_file)
 {
 	zval *zhash, *zcontext = NULL;
-	php_hash_data *hash;
+	php_hashcontext_object *hash;
 	php_stream_context *context;
 	php_stream *stream;
-	char *filename, buf[1024];
-	size_t filename_len, n;
+	zend_string *filename;
+	char buf[1024];
+	size_t n;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|r", &zhash, &filename, &filename_len, &zcontext) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "OP|r", &zhash, php_hashcontext_ce, &filename, &zcontext) == FAILURE) {
 		return;
 	}
 
-	if ((hash = (php_hash_data *)zend_fetch_resource(Z_RES_P(zhash), PHP_HASH_RESNAME, php_hash_le_hash)) == NULL) {
-		RETURN_FALSE;
-	}
+	hash = php_hashcontext_from_object(Z_OBJ_P(zhash));
+	PHP_HASHCONTEXT_VERIFY("hash_update_file", hash);
 	context = php_stream_context_from_zval(zcontext, 0);
 
-	stream = php_stream_open_wrapper_ex(filename, "rb", REPORT_ERRORS, NULL, context);
+	stream = php_stream_open_wrapper_ex(ZSTR_VAL(filename), "rb", REPORT_ERRORS, NULL, context);
 	if (!stream) {
 		/* Stream will report errors opening file */
 		RETURN_FALSE;
@@ -497,23 +507,22 @@ PHP_FUNCTION(hash_update_file)
 }
 /* }}} */
 
-/* {{{ proto string hash_final(resource context[, bool raw_output=false])
+/* {{{ proto string hash_final(HashContext context[, bool raw_output=false])
 Output resulting digest */
 PHP_FUNCTION(hash_final)
 {
 	zval *zhash;
-	php_hash_data *hash;
+	php_hashcontext_object *hash;
 	zend_bool raw_output = 0;
 	zend_string *digest;
 	int digest_len;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|b", &zhash, &raw_output) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &zhash, php_hashcontext_ce, &raw_output) == FAILURE) {
 		return;
 	}
 
-	if ((hash = (php_hash_data *)zend_fetch_resource(Z_RES_P(zhash), PHP_HASH_RESNAME, php_hash_le_hash)) == NULL) {
-		RETURN_FALSE;
-	}
+	hash = php_hashcontext_from_object(Z_OBJ_P(zhash));
+	PHP_HASHCONTEXT_VERIFY("hash_final", hash);
 
 	digest_len = hash->ops->digest_size;
 	digest = zend_string_alloc(digest_len, 0);
@@ -538,9 +547,10 @@ PHP_FUNCTION(hash_final)
 		hash->key = NULL;
 	}
 	ZSTR_VAL(digest)[digest_len] = 0;
+
+	/* Invalidate the object from further use */
 	efree(hash->context);
 	hash->context = NULL;
-	zend_list_close(Z_RES_P(zhash));
 
 	if (raw_output) {
 		RETURN_NEW_STR(digest);
@@ -555,42 +565,22 @@ PHP_FUNCTION(hash_final)
 }
 /* }}} */
 
-/* {{{ proto resource hash_copy(resource context)
-Copy hash resource */
+/* {{{ proto HashContext hash_copy(HashContext context)
+Copy hash object */
 PHP_FUNCTION(hash_copy)
 {
 	zval *zhash;
-	php_hash_data *hash, *copy_hash;
-	void *context;
-	int res;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zhash) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zhash, php_hashcontext_ce) == FAILURE) {
 		return;
 	}
 
-	if ((hash = (php_hash_data *)zend_fetch_resource(Z_RES_P(zhash), PHP_HASH_RESNAME, php_hash_le_hash)) == NULL) {
-		RETURN_FALSE;
-	}
-
+	RETVAL_OBJ(Z_OBJ_HANDLER_P(zhash, clone_obj)(zhash));
 
-	context = emalloc(hash->ops->context_size);
-	hash->ops->hash_init(context);
-
-	res = hash->ops->hash_copy(hash->ops, hash->context, context);
-	if (res != SUCCESS) {
-		efree(context);
+	if (php_hashcontext_from_object(Z_OBJ_P(return_value))->context == NULL) {
+		zval_dtor(return_value);
 		RETURN_FALSE;
 	}
-
-	copy_hash = emalloc(sizeof(php_hash_data));
-	copy_hash->ops = hash->ops;
-	copy_hash->context = context;
-	copy_hash->options = hash->options;
-	copy_hash->key = ecalloc(1, hash->ops->block_size);
-	if (hash->key) {
-		memcpy(copy_hash->key, hash->key, hash->ops->block_size);
-	}
-	RETURN_RES(zend_register_resource(copy_hash, php_hash_le_hash));
 }
 /* }}} */
 
@@ -874,28 +864,20 @@ PHP_FUNCTION(hash_equals)
 }
 /* }}} */
 
-/* Module Housekeeping */
-
-static void php_hash_dtor(zend_resource *rsrc) /* {{{ */
-{
-	php_hash_data *hash = (php_hash_data*)rsrc->ptr;
-
-	/* Just in case the algo has internally allocated resources */
-	if (hash->context) {
-		unsigned char *dummy = emalloc(hash->ops->digest_size);
-		hash->ops->hash_final(dummy, hash->context);
-		efree(dummy);
-		efree(hash->context);
-	}
-
-	if (hash->key) {
-		ZEND_SECURE_ZERO(hash->key, hash->ops->block_size);
-		efree(hash->key);
-	}
-	efree(hash);
+/* {{{ proto void HashContext::__construct() */
+static PHP_METHOD(HashContext, __construct) {
+	/* Normally unreachable as private/final */
+	zend_throw_exception(zend_ce_error, "Illegal call to private/final constructor", 0);
 }
 /* }}} */
 
+static zend_function_entry php_hashcontext_methods[] = {
+	PHP_ME(HashContext, __construct, NULL, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR)
+	PHP_FE_END
+};
+
+/* Module Housekeeping */
+
 #define PHP_HASH_HAVAL_REGISTER(p,b)	php_hash_register_algo("haval" #b "," #p , &php_hash_##p##haval##b##_ops);
 
 #ifdef PHP_MHASH_BC
@@ -1104,11 +1086,75 @@ PHP_FUNCTION(mhash_keygen_s2k)
 
 #endif
 
+/* ----------------------------------------------------------------------- */
+
+/* {{{ php_hashcontext_create */
+static zend_object* php_hashcontext_create(zend_class_entry *ce) {
+	php_hashcontext_object *objval = ecalloc(1,
+		sizeof(php_hashcontext_object) + zend_object_properties_size(ce));
+	zend_object *zobj = &(objval->std);
+
+	zend_object_std_init(zobj, ce);
+	zobj->handlers = &php_hashcontext_handlers;
+
+	return zobj;
+}
+/* }}} */
+
+/* {{{ php_hashcontext_dtor */
+static void php_hashcontext_dtor(zend_object *obj) {
+	php_hashcontext_object *hash = php_hashcontext_from_object(obj);
+
+	/* Just in case the algo has internally allocated resources */
+	if (hash->context) {
+		unsigned char *dummy = emalloc(hash->ops->digest_size);
+		hash->ops->hash_final(dummy, hash->context);
+		efree(dummy);
+		efree(hash->context);
+		hash->context = NULL;
+	}
+
+	if (hash->key) {
+		ZEND_SECURE_ZERO(hash->key, hash->ops->block_size);
+		efree(hash->key);
+		hash->key = NULL;
+	}
+}
+/* }}} */
+
+/* {{{ php_hashcontext_clone */
+static zend_object *php_hashcontext_clone(zval *pzv) {
+	php_hashcontext_object *oldobj = php_hashcontext_from_object(Z_OBJ_P(pzv));
+	zend_object *znew = php_hashcontext_create(Z_OBJCE_P(pzv));
+	php_hashcontext_object *newobj = php_hashcontext_from_object(znew);
+
+	zend_objects_clone_members(znew, Z_OBJ_P(pzv));
+
+	newobj->ops = oldobj->ops;
+	newobj->options = oldobj->options;
+	newobj->context = emalloc(newobj->ops->context_size);
+	newobj->ops->hash_init(newobj->context);
+
+	if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) {
+		efree(newobj->context);
+		newobj->context = NULL;
+		return znew;
+	}
+
+	newobj->key = ecalloc(1, newobj->ops->block_size);
+	if (oldobj->key) {
+		memcpy(newobj->key, oldobj->key, newobj->ops->block_size);
+	}
+
+	return znew;
+}
+/* }}} */
+
 /* {{{ PHP_MINIT_FUNCTION
  */
 PHP_MINIT_FUNCTION(hash)
 {
-	php_hash_le_hash = zend_register_list_destructors_ex(php_hash_dtor, NULL, PHP_HASH_RESNAME, module_number);
+	zend_class_entry ce;
 
 	zend_hash_init(&php_hash_hashtable, 35, NULL, NULL, 1);
 
@@ -1170,6 +1216,19 @@ PHP_MINIT_FUNCTION(hash)
 
 	REGISTER_LONG_CONSTANT("HASH_HMAC",		PHP_HASH_HMAC,	CONST_CS | CONST_PERSISTENT);
 
+	INIT_CLASS_ENTRY(ce, "HashContext", php_hashcontext_methods);
+	php_hashcontext_ce = zend_register_internal_class(&ce);
+	php_hashcontext_ce->ce_flags |= ZEND_ACC_FINAL;
+	php_hashcontext_ce->create_object = php_hashcontext_create;
+	php_hashcontext_ce->serialize = zend_class_serialize_deny;
+	php_hashcontext_ce->unserialize = zend_class_unserialize_deny;
+
+	memcpy(&php_hashcontext_handlers, zend_get_std_object_handlers(),
+	       sizeof(zend_object_handlers));
+	php_hashcontext_handlers.offset = XtOffsetOf(php_hashcontext_object, std);
+	php_hashcontext_handlers.dtor_obj = php_hashcontext_dtor;
+	php_hashcontext_handlers.clone_obj = php_hashcontext_clone;
+
 #ifdef PHP_MHASH_BC
 	mhash_init(INIT_FUNC_ARGS_PASSTHRU);
 #endif
diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h
index b67b8c5..07d7a1d 100644
--- a/ext/hash/php_hash.h
+++ b/ext/hash/php_hash.h
@@ -26,7 +26,6 @@
 #define PHP_HASH_EXTNAME	"hash"
 #define PHP_HASH_VERSION	"1.0"
 #define PHP_MHASH_VERSION	"1.0"
-#define PHP_HASH_RESNAME	"Hash Context"
 
 #define PHP_HASH_HMAC		0x0001
 
@@ -49,13 +48,19 @@ typedef struct _php_hash_ops {
 	unsigned is_crypto: 1;
 } php_hash_ops;
 
-typedef struct _php_hash_data {
+typedef struct _php_hashcontext_object {
 	const php_hash_ops *ops;
 	void *context;
 
 	zend_long options;
 	unsigned char *key;
-} php_hash_data;
+
+	zend_object std;
+} php_hashcontext_object;
+
+static inline php_hashcontext_object *php_hashcontext_from_object(zend_object *obj) {
+	return ((php_hashcontext_object*)(obj + 1)) - 1;
+}
 
 extern const php_hash_ops php_hash_md2_ops;
 extern const php_hash_ops php_hash_md4_ops;
@@ -143,6 +148,7 @@ PHP_FUNCTION(hash_algos);
 PHP_FUNCTION(hash_pbkdf2);
 PHP_FUNCTION(hash_equals);
 
+extern PHP_HASH_API zend_class_entry *php_hashcontext_ce;
 PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(const char *algo, size_t algo_len);
 PHP_HASH_API void php_hash_register_algo(const char *algo, const php_hash_ops *ops);
 PHP_HASH_API int php_hash_copy(const void *ops, void *orig_context, void *dest_context);
diff --git a/ext/hash/tests/hash-clone.phpt b/ext/hash/tests/hash-clone.phpt
new file mode 100644
index 0000000..ba9257d
--- /dev/null
+++ b/ext/hash/tests/hash-clone.phpt
@@ -0,0 +1,346 @@
+--TEST--
+hash_copy() via clone
+--SKIPIF--
+<?php extension_loaded('hash') or die('skip'); ?>
+--FILE--
+<?php
+
+$algos = hash_algos();
+
+foreach ($algos as $algo) {
+	var_dump($algo);
+	$orig = hash_init($algo);
+	hash_update($orig, "I can't remember anything");
+	$copy = clone $orig;
+	var_dump(hash_final($orig));
+
+	var_dump(hash_final($copy));
+}
+
+foreach ($algos as $algo) {
+	var_dump($algo);
+	$orig = hash_init($algo);
+	hash_update($orig, "I can't remember anything");
+	$copy = clone $orig;
+	var_dump(hash_final($orig));
+
+	hash_update($copy, "Can’t tell if this is true or dream");
+	var_dump(hash_final($copy));
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(3) "md2"
+string(32) "d5ac4ffd08f6a57b9bd402b8068392ff"
+string(32) "d5ac4ffd08f6a57b9bd402b8068392ff"
+string(3) "md4"
+string(32) "302c45586b53a984bd3a1237cb81c15f"
+string(32) "302c45586b53a984bd3a1237cb81c15f"
+string(3) "md5"
+string(32) "e35759f6ea35db254e415b5332269435"
+string(32) "e35759f6ea35db254e415b5332269435"
+string(4) "sha1"
+string(40) "29f62a228f726cd728efa7a0ac6a2aba318baf15"
+string(40) "29f62a228f726cd728efa7a0ac6a2aba318baf15"
+string(6) "sha224"
+string(56) "51fd0aa76a00b4a86103895cad5c7c2651ec7da9f4fc1e50c43ede29"
+string(56) "51fd0aa76a00b4a86103895cad5c7c2651ec7da9f4fc1e50c43ede29"
+string(6) "sha256"
+string(64) "d3a13cf52af8e9390caed78b77b6b1e06e102204e3555d111dfd149bc5d54dba"
+string(64) "d3a13cf52af8e9390caed78b77b6b1e06e102204e3555d111dfd149bc5d54dba"
+string(6) "sha384"
+string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b4433d6e554e11e40a7cdcf510ea3"
+string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b4433d6e554e11e40a7cdcf510ea3"
+string(10) "sha512/224"
+string(56) "a2573d0e3f6c3e2d174c935a35a8ea31032f04e9e83499ac3ceda568"
+string(56) "a2573d0e3f6c3e2d174c935a35a8ea31032f04e9e83499ac3ceda568"
+string(10) "sha512/256"
+string(64) "fddacab80b3a610ba024c9d75a5fe0cafe5ae7c789f829b3c5fbea8ef11ccc1a"
+string(64) "fddacab80b3a610ba024c9d75a5fe0cafe5ae7c789f829b3c5fbea8ef11ccc1a"
+string(6) "sha512"
+string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(8) "sha3-224"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(8) "sha3-256"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(8) "sha3-384"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(8) "sha3-512"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(9) "ripemd128"
+string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
+string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
+string(9) "ripemd160"
+string(40) "02a2a535ee10404c6b5cf9acb178a04fbed67269"
+string(40) "02a2a535ee10404c6b5cf9acb178a04fbed67269"
+string(9) "ripemd256"
+string(64) "547d2ed85ca0a0e3208b5ecf4fc6a7fc1e64db8ff13493e4beaf11e4d71648e2"
+string(64) "547d2ed85ca0a0e3208b5ecf4fc6a7fc1e64db8ff13493e4beaf11e4d71648e2"
+string(9) "ripemd320"
+string(80) "785a7df56858f550966cddfd59ce14b13bf4b18e7892c4c1ad91bf23bf67639bd2c96749ba29cfa6"
+string(80) "785a7df56858f550966cddfd59ce14b13bf4b18e7892c4c1ad91bf23bf67639bd2c96749ba29cfa6"
+string(9) "whirlpool"
+string(128) "6e60597340640e621e25f975cef2b000b0c4c09a7af7d240a52d193002b0a8426fa7da7acc5b37ed9608016d4f396db834a0ea2f2c35f900461c9ac7e5604082"
+string(128) "6e60597340640e621e25f975cef2b000b0c4c09a7af7d240a52d193002b0a8426fa7da7acc5b37ed9608016d4f396db834a0ea2f2c35f900461c9ac7e5604082"
+string(10) "tiger128,3"
+string(32) "8d68e78bc5e62ba925a67aa48595cfc6"
+string(32) "8d68e78bc5e62ba925a67aa48595cfc6"
+string(10) "tiger160,3"
+string(40) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e0"
+string(40) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e0"
+string(10) "tiger192,3"
+string(48) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e08224fc35"
+string(48) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e08224fc35"
+string(10) "tiger128,4"
+string(32) "a26ca3f58e74fb32ee44b099cb1b5122"
+string(32) "a26ca3f58e74fb32ee44b099cb1b5122"
+string(10) "tiger160,4"
+string(40) "a26ca3f58e74fb32ee44b099cb1b512203375900"
+string(40) "a26ca3f58e74fb32ee44b099cb1b512203375900"
+string(10) "tiger192,4"
+string(48) "a26ca3f58e74fb32ee44b099cb1b512203375900f30b741d"
+string(48) "a26ca3f58e74fb32ee44b099cb1b512203375900f30b741d"
+string(6) "snefru"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(9) "snefru256"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(4) "gost"
+string(64) "5820c7c4a0650587538b30ef4099f2b5993069758d5c847a552e6ef7360766a5"
+string(64) "5820c7c4a0650587538b30ef4099f2b5993069758d5c847a552e6ef7360766a5"
+string(11) "gost-crypto"
+string(64) "f7c4e35548d66aabe2b106f20515d289fde90969225d3d7b83f6dd12d694f043"
+string(64) "f7c4e35548d66aabe2b106f20515d289fde90969225d3d7b83f6dd12d694f043"
+string(7) "adler32"
+string(8) "6f7c0928"
+string(8) "6f7c0928"
+string(5) "crc32"
+string(8) "e5cfc160"
+string(8) "e5cfc160"
+string(6) "crc32b"
+string(8) "69147a4e"
+string(8) "69147a4e"
+string(6) "fnv132"
+string(8) "98139504"
+string(8) "98139504"
+string(7) "fnv1a32"
+string(8) "aae4e042"
+string(8) "aae4e042"
+string(6) "fnv164"
+string(16) "14522659f8138684"
+string(16) "14522659f8138684"
+string(7) "fnv1a64"
+string(16) "bebc746a33b6ab62"
+string(16) "bebc746a33b6ab62"
+string(5) "joaat"
+string(8) "aaebf370"
+string(8) "aaebf370"
+string(10) "haval128,3"
+string(32) "86362472c8895e68e223ef8b3711d8d9"
+string(32) "86362472c8895e68e223ef8b3711d8d9"
+string(10) "haval160,3"
+string(40) "fabdf6905f3ba18a3c93d6a16b91e31f7222a7a4"
+string(40) "fabdf6905f3ba18a3c93d6a16b91e31f7222a7a4"
+string(10) "haval192,3"
+string(48) "e05d0ff5723028bd5494f32c0c2494cd0b9ccf7540af7b47"
+string(48) "e05d0ff5723028bd5494f32c0c2494cd0b9ccf7540af7b47"
+string(10) "haval224,3"
+string(56) "56b196289d8de8a22296588cf90e5b09cb6fa1b01ce8e92bca40cae2"
+string(56) "56b196289d8de8a22296588cf90e5b09cb6fa1b01ce8e92bca40cae2"
+string(10) "haval256,3"
+string(64) "ff4d7ab0fac2ca437b945461f9b62fd16e71e9103524d5d140445a00e3d49239"
+string(64) "ff4d7ab0fac2ca437b945461f9b62fd16e71e9103524d5d140445a00e3d49239"
+string(10) "haval128,4"
+string(32) "ee44418e0195a0c4a35d112722919a9c"
+string(32) "ee44418e0195a0c4a35d112722919a9c"
+string(10) "haval160,4"
+string(40) "f320cce982d5201a1ccacc1c5ff835a258a97eb1"
+string(40) "f320cce982d5201a1ccacc1c5ff835a258a97eb1"
+string(10) "haval192,4"
+string(48) "a96600107463e8e97a7fe6f260d9bf4f4587a281caafa6db"
+string(48) "a96600107463e8e97a7fe6f260d9bf4f4587a281caafa6db"
+string(10) "haval224,4"
+string(56) "7147c9e1c1e67b942da3229f59a1ab18f121f5d7f5765ca88bc9f200"
+string(56) "7147c9e1c1e67b942da3229f59a1ab18f121f5d7f5765ca88bc9f200"
+string(10) "haval256,4"
+string(64) "82fec42679ed5a77a841962827b88a9cddf7d677736e50bc81f1a14b99f06061"
+string(64) "82fec42679ed5a77a841962827b88a9cddf7d677736e50bc81f1a14b99f06061"
+string(10) "haval128,5"
+string(32) "8d0b157828328ae7d34d60b4b60c1dab"
+string(32) "8d0b157828328ae7d34d60b4b60c1dab"
+string(10) "haval160,5"
+string(40) "54dab5e10dc41503f9b8aa32ffe3bab7cf1da8a3"
+string(40) "54dab5e10dc41503f9b8aa32ffe3bab7cf1da8a3"
+string(10) "haval192,5"
+string(48) "7d91265a1b27698279d8d95a5ee0a20014528070bf6415e7"
+string(48) "7d91265a1b27698279d8d95a5ee0a20014528070bf6415e7"
+string(10) "haval224,5"
+string(56) "7772b2e22f2a3bce917e08cf57ebece46bb33168619a776c6f2f7234"
+string(56) "7772b2e22f2a3bce917e08cf57ebece46bb33168619a776c6f2f7234"
+string(10) "haval256,5"
+string(64) "438a602cb1a761f7bd0a633b7bd8b3ccd0577b524d05174ca1ae1f559b9a2c2a"
+string(64) "438a602cb1a761f7bd0a633b7bd8b3ccd0577b524d05174ca1ae1f559b9a2c2a"
+string(3) "md2"
+string(32) "d5ac4ffd08f6a57b9bd402b8068392ff"
+string(32) "5c36f61062d091a8324991132c5e8dbd"
+string(3) "md4"
+string(32) "302c45586b53a984bd3a1237cb81c15f"
+string(32) "1d4196526aada3506efb4c7425651584"
+string(3) "md5"
+string(32) "e35759f6ea35db254e415b5332269435"
+string(32) "f255c114bd6ce94aad092b5141c00d46"
+string(4) "sha1"
+string(40) "29f62a228f726cd728efa7a0ac6a2aba318baf15"
+string(40) "a273396f056554dcd491b5dea1e7baa3b89b802b"
+string(6) "sha224"
+string(56) "51fd0aa76a00b4a86103895cad5c7c2651ec7da9f4fc1e50c43ede29"
+string(56) "1aee028400c56ceb5539625dc2f395abf491409336ca0f3e177a50e2"
+string(6) "sha256"
+string(64) "d3a13cf52af8e9390caed78b77b6b1e06e102204e3555d111dfd149bc5d54dba"
+string(64) "268e7f4cf88504a53fd77136c4c4748169f46ff7150b376569ada9c374836944"
+string(6) "sha384"
+string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b4433d6e554e11e40a7cdcf510ea3"
+string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58997533fc99650b20049c6cb9a6cc"
+string(10) "sha512/224"
+string(56) "a2573d0e3f6c3e2d174c935a35a8ea31032f04e9e83499ac3ceda568"
+string(56) "cbc2bbf0028ed803af785b0f264962c84ec48d8ee0908322ef995ddb"
+string(10) "sha512/256"
+string(64) "fddacab80b3a610ba024c9d75a5fe0cafe5ae7c789f829b3c5fbea8ef11ccc1a"
+string(64) "2cec704878ffa7128e0c4a61eef87d1f3c823184d364dfa3fed73beb00499b00"
+string(6) "sha512"
+string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
+string(8) "sha3-224"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
+string(8) "sha3-256"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
+string(8) "sha3-384"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
+string(8) "sha3-512"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
+string(9) "ripemd128"
+string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
+string(32) "f95f5e22b8875ee0c48219ae97f0674b"
+string(9) "ripemd160"
+string(40) "02a2a535ee10404c6b5cf9acb178a04fbed67269"
+string(40) "900d615c1abe714e340f4ecd6a3d65599fd30ff4"
+string(9) "ripemd256"
+string(64) "547d2ed85ca0a0e3208b5ecf4fc6a7fc1e64db8ff13493e4beaf11e4d71648e2"
+string(64) "b9799db40d1af5614118c329169cdcd2c718db6af03bf945ea7f7ba72b8e14f4"
+string(9) "ripemd320"
+string(80) "785a7df56858f550966cddfd59ce14b13bf4b18e7892c4c1ad91bf23bf67639bd2c96749ba29cfa6"
+string(80) "d6d12c1fca7a9c4a59c1be4f40188e92a746a035219e0a6ca1ee53b36a8282527187f7dffaa57ecc"
+string(9) "whirlpool"
+string(128) "6e60597340640e621e25f975cef2b000b0c4c09a7af7d240a52d193002b0a8426fa7da7acc5b37ed9608016d4f396db834a0ea2f2c35f900461c9ac7e5604082"
+string(128) "e8c6a921e7d8eac2fd21d4df6054bb27a02321b2beb5b01b6f88c40706164e64d67ec97519bf76c8af8df896745478b78d42a0159f1a0db16777771fd9d420dc"
+string(10) "tiger128,3"
+string(32) "8d68e78bc5e62ba925a67aa48595cfc6"
+string(32) "a99d2c0348d480dc0f3c35852926e0f1"
+string(10) "tiger160,3"
+string(40) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e0"
+string(40) "a99d2c0348d480dc0f3c35852926e0f1e1825c16"
+string(10) "tiger192,3"
+string(48) "8d68e78bc5e62ba925a67aa48595cfc62cd1e5e08224fc35"
+string(48) "a99d2c0348d480dc0f3c35852926e0f1e1825c1651957ee3"
+string(10) "tiger128,4"
+string(32) "a26ca3f58e74fb32ee44b099cb1b5122"
+string(32) "66e2c0322421c4e5a9208e6aeed481e5"
+string(10) "tiger160,4"
+string(40) "a26ca3f58e74fb32ee44b099cb1b512203375900"
+string(40) "66e2c0322421c4e5a9208e6aeed481e5c4b00448"
+string(10) "tiger192,4"
+string(48) "a26ca3f58e74fb32ee44b099cb1b512203375900f30b741d"
+string(48) "66e2c0322421c4e5a9208e6aeed481e5c4b00448e344d9d0"
+string(6) "snefru"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(9) "snefru256"
+string(64) "fbe88daa74c89b9e29468fa3cd3a657d31845e21bb58dd3f8d806f5179a85c26"
+string(64) "614ca924864fa0e8fa309aa0944e047d5edbfd4964a35858f4d8ec66a0fb88b0"
+string(4) "gost"
+string(64) "5820c7c4a0650587538b30ef4099f2b5993069758d5c847a552e6ef7360766a5"
+string(64) "a00961e371287c71c527a41c14564f13b6ed12ac7cd9d5f5dfb3542a25e28d3b"
+string(11) "gost-crypto"
+string(64) "f7c4e35548d66aabe2b106f20515d289fde90969225d3d7b83f6dd12d694f043"
+string(64) "68ca9aea6729dc07d995fbe071a4b5c6490bb27fc4dc65ec0e96200d5e082996"
+string(7) "adler32"
+string(8) "6f7c0928"
+string(8) "d9141747"
+string(5) "crc32"
+string(8) "e5cfc160"
+string(8) "59f8d3d2"
+string(6) "crc32b"
+string(8) "69147a4e"
+string(8) "3ee63999"
+string(6) "fnv132"
+string(8) "98139504"
+string(8) "59ad036f"
+string(7) "fnv1a32"
+string(8) "aae4e042"
+string(8) "fadc2cef"
+string(6) "fnv164"
+string(16) "14522659f8138684"
+string(16) "5e8c64fba6a5ffcf"
+string(7) "fnv1a64"
+string(16) "bebc746a33b6ab62"
+string(16) "893899e4415a920f"
+string(5) "joaat"
+string(8) "aaebf370"
+string(8) "513479b4"
+string(10) "haval128,3"
+string(32) "86362472c8895e68e223ef8b3711d8d9"
+string(32) "ebeeeb05c18af1e53d2d127b561d5e0d"
+string(10) "haval160,3"
+string(40) "fabdf6905f3ba18a3c93d6a16b91e31f7222a7a4"
+string(40) "f1a2c9604fb40899ad502abe0dfcec65115c8a9a"
+string(10) "haval192,3"
+string(48) "e05d0ff5723028bd5494f32c0c2494cd0b9ccf7540af7b47"
+string(48) "d3a7315773a326678208650ed02510ed96cd488d74cd5231"
+string(10) "haval224,3"
+string(56) "56b196289d8de8a22296588cf90e5b09cb6fa1b01ce8e92bca40cae2"
+string(56) "6d7132fabc83c9ab7913748b79ecf10e25409569d3ed144177f46731"
+string(10) "haval256,3"
+string(64) "ff4d7ab0fac2ca437b945461f9b62fd16e71e9103524d5d140445a00e3d49239"
+string(64) "7a469868ad4b92891a3a44524c58a2b8d0f3bebb92b4cf47d19bc6aba973eb95"
+string(10) "haval128,4"
+string(32) "ee44418e0195a0c4a35d112722919a9c"
+string(32) "6ecddb39615f43fd211839287ff38461"
+string(10) "haval160,4"
+string(40) "f320cce982d5201a1ccacc1c5ff835a258a97eb1"
+string(40) "bcd2e7821723ac22e122b8b7cbbd2daaa9a862df"
+string(10) "haval192,4"
+string(48) "a96600107463e8e97a7fe6f260d9bf4f4587a281caafa6db"
+string(48) "ae74619a88dcec1fbecde28e27f009a65ecc12170824d2cd"
+string(10) "haval224,4"
+string(56) "7147c9e1c1e67b942da3229f59a1ab18f121f5d7f5765ca88bc9f200"
+string(56) "fdaba6563f1334d40de24e311f14b324577f97c3b78b9439c408cdca"
+string(10) "haval256,4"
+string(64) "82fec42679ed5a77a841962827b88a9cddf7d677736e50bc81f1a14b99f06061"
+string(64) "289a2ba4820218bdb25a6534fbdf693f9de101362584fdd41e32244c719caa37"
+string(10) "haval128,5"
+string(32) "8d0b157828328ae7d34d60b4b60c1dab"
+string(32) "ffa7993a4e183b245263fb1f63e27343"
+string(10) "haval160,5"
+string(40) "54dab5e10dc41503f9b8aa32ffe3bab7cf1da8a3"
+string(40) "375ee5ab3a9bd07a1dbe5d071e07b2afb3165e3b"
+string(10) "haval192,5"
+string(48) "7d91265a1b27698279d8d95a5ee0a20014528070bf6415e7"
+string(48) "c650585f93c6e041e835caedc621f8c42d8bc6829fb76789"
+string(10) "haval224,5"
+string(56) "7772b2e22f2a3bce917e08cf57ebece46bb33168619a776c6f2f7234"
+string(56) "bc674d465a822817d939f19b38edde083fe5668759836c203c56e3e4"
+string(10) "haval256,5"
+string(64) "438a602cb1a761f7bd0a633b7bd8b3ccd0577b524d05174ca1ae1f559b9a2c2a"
+string(64) "da70ad9bd09ed7c9675329ea2b5279d57761807c7aeac6340d94b5d494809457"
+Done
diff --git a/ext/hash/tests/hash_copy_002.phpt b/ext/hash/tests/hash_copy_002.phpt
index aac4c3b..5fbbf5b 100644
--- a/ext/hash/tests/hash_copy_002.phpt
+++ b/ext/hash/tests/hash_copy_002.phpt
@@ -15,7 +15,8 @@ echo "Done\n";
 --EXPECTF--	
 Warning: hash_copy() expects exactly 1 parameter, 0 given in %s on line %d
 NULL
-resource(%d) of type (Hash Context)
+object(HashContext)#%d (0) {
+}
 
 Warning: hash_copy() expects exactly 1 parameter, 2 given in %s on line %d
 NULL
diff --git a/ext/hash/tests/new-context.phpt b/ext/hash/tests/new-context.phpt
new file mode 100644
index 0000000..5b69115
--- /dev/null
+++ b/ext/hash/tests/new-context.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Attempt to instantiate a HashContext directly
+--SKIPIF--
+<?php if (!extension_loaded('hash')) echo 'skip';
+--FILE--
+<?php
+
+try {
+  new HashContext;
+} catch (Error $e) {
+  echo "Exception: {$e->getMessage()}\n";
+}
+--EXPECTF--
+Exception: Call to private HashContext::__construct() from invalid context
diff --git a/ext/hash/tests/reuse.phpt b/ext/hash/tests/reuse.phpt
new file mode 100644
index 0000000..acf901d
--- /dev/null
+++ b/ext/hash/tests/reuse.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Attempt to reuse a closed hash context
+--SKIPIF--
+<?php if (!extension_loaded('hash')) echo 'skip';
+--FILE--
+<?php
+
+$h = hash_init('md5');
+hash_final($h);
+hash_update($h, 'foo');
+--EXPECTF--
+Warning: hash_update(): supplied resource is not a valid Hash Context resource in %s/ext/hash/tests/reuse.php on line 5
diff --git a/ext/hash/tests/serialize-context.phpt b/ext/hash/tests/serialize-context.phpt
new file mode 100644
index 0000000..81b3a11
--- /dev/null
+++ b/ext/hash/tests/serialize-context.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Serialize a context
+--SKIPIF--
+<?php if (!extension_loaded('hash')) echo 'skip';
+--FILE--
+<?php
+
+$h = hash_init('md5');
+try {
+  var_dump(serialize($h));
+} catch (Exception $e) {
+  echo "Exception: {$e->getMessage()}\n";
+}
+--EXPECTF--
+Exception: Serialization of 'HashContext' is not allowed
\ No newline at end of file
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.