php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #14293 serializer & __sleep()
Submitted: 2001-11-29 20:29 UTC Modified: 2001-12-02 02:06 UTC
From: bernd@php.net Assigned:
Status: Closed Package: Session related
PHP Version: 4.2.0 OS: linux
Private report: No CVE-ID: None
 [2001-11-29 20:29 UTC] bernd@php.net
hi...

i found a bug in the serializer-function (current cvs 4.2.0-dev) which results in invalid serialised-strings. if you serialize an object which uses __sleep() to define the classnamevariables should be serialized, and some of this variables aren't initialized (isset()==flase), 
the serializer won't serialize these vars (OK). BUT he produces invalid strings because he doesn't use the correct value for the "number of object-attributes".

O:1:"a":3:{s:5:"value";s:1:"a";}
        ^  ^
3 parts are predicted.. but only 1 is provided. :(

an example-script:
<?php
  class a {

    function a() {
      $this->value="a";
    }

    function __sleep() {
      return(array('a','b','value'));
    }
  }

  $a=new a();
  echo serialize($a);
?>

ok.. now.. i found two differend patches:
the first (not my favourite) simply serializes uninitialized variables if they had bool(false) as value.
-----------------------------------------------------------
--- ../../php4/ext/standard/var.c	Sat Nov 10 22:18:34 2001
+++ ext/standard/var.c	Fri Nov 30 01:22:05 2001
@@ -198,27 +198,34 @@
 	int count = zend_hash_num_elements(HASH_OF(retval_ptr));
 
 	php_var_serialize_class_name(buf, struc TSRMLS_CC);
 
-	smart_str_append_long(buf, count);
-	smart_str_appendl(buf, ":{", 2);
+
 
 	if (count > 0) {
 		char *key;
 		zval **d, **name;
 		ulong index;
 		HashPosition pos;
 		int i;
+		int cundef;
 
+		smart_str_append_long(buf, count);
+    smart_str_appendl(buf, ":{", 2);
+		
+		cundef=0;
 		zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
-	
 		for (;; zend_hash_move_forward_ex(HASH_OF(retval_ptr), &pos)) {
 			i = zend_hash_get_current_key_ex(HASH_OF(retval_ptr), &key, NULL, 
 					&index, 0, &pos);
 			
-			if (i == HASH_KEY_NON_EXISTANT)
+			if (i == HASH_KEY_NON_EXISTANT) {	
+				php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
+				smart_str_appendl(buf, "b:0;", 4);
+				cundef++;
 				break;
-
+			}
+			
 			zend_hash_get_current_data_ex(HASH_OF(retval_ptr), 
 					(void **) &name, &pos);
 
 			if (Z_TYPE_PP(name) != IS_STRING) {
@@ -234,9 +241,13 @@
 						Z_STRLEN_PP(name));
 				php_var_serialize_intern(buf, d, var_hash TSRMLS_CC);	
 			}
 		}
+		if (cundef>0)
+			php_error(E_WARNING,"__sleep returned %d attributes, but some (%d) were unset",count,cundef);		
 	}
+
+
 	smart_str_appendc(buf, '}');
 }
 

the second (my favourite) just puts the correct value for number of psrts in the result:
-----------------------------------------------------------
--- ../../php4/ext/standard/var.c	Sat Nov 10 22:18:34 2001
+++ ext/standard/var.c	Fri Nov 30 01:31:50 2001
@@ -198,27 +198,33 @@
 	int count = zend_hash_num_elements(HASH_OF(retval_ptr));
 
 	php_var_serialize_class_name(buf, struc TSRMLS_CC);
 
-	smart_str_append_long(buf, count);
-	smart_str_appendl(buf, ":{", 2);
+
 
 	if (count > 0) {
 		char *key;
 		zval **d, **name;
 		ulong index;
 		HashPosition pos;
 		int i;
-
-		zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
+		int cundef;
+		
+		smart_str buf2={0};
 	
+		cundef=0;
+		zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
 		for (;; zend_hash_move_forward_ex(HASH_OF(retval_ptr), &pos)) {
 			i = zend_hash_get_current_key_ex(HASH_OF(retval_ptr), &key, NULL, 
 					&index, 0, &pos);
 			
-			if (i == HASH_KEY_NON_EXISTANT)
+			if (i == HASH_KEY_NON_EXISTANT) {	
+//				php_var_serialize_string(&buf2, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
+//				smart_str_appendl(&buf2, "b:0;", 4);
+				cundef++;
 				break;
-
+			}
+			
 			zend_hash_get_current_data_ex(HASH_OF(retval_ptr), 
 					(void **) &name, &pos);
 
 			if (Z_TYPE_PP(name) != IS_STRING) {
@@ -229,14 +235,22 @@
 			}
 
 			if (zend_hash_find(Z_OBJPROP_PP(struc), Z_STRVAL_PP(name), 
 						Z_STRLEN_PP(name) + 1, (void *) &d) == SUCCESS) {
-				php_var_serialize_string(buf, Z_STRVAL_PP(name), 
+				php_var_serialize_string(&buf2, Z_STRVAL_PP(name), 
 						Z_STRLEN_PP(name));
-				php_var_serialize_intern(buf, d, var_hash TSRMLS_CC);	
+				php_var_serialize_intern(&buf2, d, var_hash TSRMLS_CC);	
 			}
 		}
+		if (cundef>0)
+			php_error(E_WARNING,"__sleep returned %d attributes, but some (%d) were unset",count,cundef);		
+		smart_str_append_long(buf, count-cundef);
+    smart_str_appendl(buf, ":{", 2);			
+    smart_str_appendl(buf,buf2.c,buf2.len);
+    smart_str_free(&buf2);
 	}
+	
+
 	smart_str_appendc(buf, '}');
 }

regards
   ---bernd roemer--- (fumanchi)


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-11-29 21:37 UTC] bernd@php.net
oops...

sorry... i patches i posted aren't working :(
here is (as i hope) the correct one:

--- ../../php4/ext/standard/var.c	Sat Nov 10 22:18:34 2001
+++ ext/standard/var.c	Fri Nov 30 03:33:49 2001
@@ -198,27 +198,29 @@
 	int count = zend_hash_num_elements(HASH_OF(retval_ptr));
 
 	php_var_serialize_class_name(buf, struc TSRMLS_CC);
 
-	smart_str_append_long(buf, count);
-	smart_str_appendl(buf, ":{", 2);
+
 
 	if (count > 0) {
 		char *key;
 		zval **d, **name;
 		ulong index;
 		HashPosition pos;
 		int i;
-
-		zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
+		int cundef;
+		
+		smart_str buf2={0};
 	
+		cundef=0;
+		zend_hash_internal_pointer_reset_ex(HASH_OF(retval_ptr), &pos);
 		for (;; zend_hash_move_forward_ex(HASH_OF(retval_ptr), &pos)) {
 			i = zend_hash_get_current_key_ex(HASH_OF(retval_ptr), &key, NULL, 
 					&index, 0, &pos);
 			
 			if (i == HASH_KEY_NON_EXISTANT)
 				break;
-
+			
 			zend_hash_get_current_data_ex(HASH_OF(retval_ptr), 
 					(void **) &name, &pos);
 
 			if (Z_TYPE_PP(name) != IS_STRING) {
@@ -229,14 +231,24 @@
 			}
 
 			if (zend_hash_find(Z_OBJPROP_PP(struc), Z_STRVAL_PP(name), 
 						Z_STRLEN_PP(name) + 1, (void *) &d) == SUCCESS) {
-				php_var_serialize_string(buf, Z_STRVAL_PP(name), 
+				php_var_serialize_string(&buf2, Z_STRVAL_PP(name), 
 						Z_STRLEN_PP(name));
-				php_var_serialize_intern(buf, d, var_hash TSRMLS_CC);	
+				php_var_serialize_intern(&buf2, d, var_hash TSRMLS_CC);	
+			} else {
+				cundef++;	
 			}
 		}
+		// if (cundef>0)
+		// 	php_error(E_WARNING,"__sleep returned %d attributes, but some (%d) were unset",count,cundef);		
+		smart_str_append_long(buf, count-cundef);
+    smart_str_appendl(buf, ":{", 2);			
+    smart_str_appendl(buf,buf2.c,buf2.len);
+    smart_str_free(&buf2);
 	}
+	
+
 	smart_str_appendc(buf, '}');
 }


that seems to work... but sascha may fix it his way...

cu
   ---bernd roemer--- (fumanchi)
 [2001-12-02 02:06 UTC] zak@php.net
It looks like this was corrected yesterday - closing. 
Please re-open if you have any concerns (or I am wrong) :)

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Oct 09 07:01:28 2024 UTC