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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: bernd@php.net
New email:
PHP Version: OS:

 

 [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 Dec 04 08:01:29 2024 UTC