ID: 43450 Updated by: [EMAIL PROTECTED] Reported By: [EMAIL PROTECTED] -Status: Open +Status: Closed Bug Type: Scripting Engine problem Operating System: Any PHP Version: 5.2.5 New Comment:
This bug has been fixed in CVS. Snapshots of the sources are packaged every three hours; this change will be in the next snapshot. You can grab the snapshot at http://snaps.php.net/. Thank you for the report, and for helping us make PHP better. Previous Comments: ------------------------------------------------------------------------ [2007-12-21 16:37:44] [EMAIL PROTECTED] Patches are added for 5_2, 5_3 and HEAD there: http://dev.agoraproduction.com/php/Zend/ Thanks, ------------------------------------------------------------------------ [2007-12-20 11:47:59] [EMAIL PROTECTED] It appears that zend_std_cast_object_tostring() does not check whether it has to dref readobj prior writing to writeobj in case they are the same zval. That said the code needs to be refactored to: - if (readobj==writeobj) { zval_dtor(readobj); } // not zval_ptr_dtor - call INIT_PZVAL(writeobj) always - set Z_TYPE_P(writeobj) = IS_NULL; for the default case ------------------------------------------------------------------------ [2007-11-30 01:34:56] [EMAIL PROTECTED] I'm still not sure if this has anything to do with the new Zend parsing API, but I've tested the md5 function with the zend_get_parameters_ex (the old API) and the leak didn't occur. See the two version for a comparison. -------------------- currently -------------------- PHP_NAMED_FUNCTION(php_if_md5) { char *arg; int arg_len; zend_bool raw_output = 0; char md5str[33]; PHP_MD5_CTX context; unsigned char digest[16]; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { return; } md5str[0] = '\0'; PHP_MD5Init(&context); PHP_MD5Update(&context, arg, arg_len); PHP_MD5Final(digest, &context); if (raw_output) { RETURN_STRINGL(digest, 16, 1); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str, 1); } } ----------- hacked rewrite ------------------------ PHP_NAMED_FUNCTION(php_if_md5) { zval **zarg; zend_bool raw_output = 0; char md5str[33]; PHP_MD5_CTX context; unsigned char digest[16]; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zarg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_string_ex(zarg); md5str[0] = '\0'; PHP_MD5Init(&context); PHP_MD5Update(&context, Z_STRVAL_PP(zarg), Z_STRLEN_PP(zarg)); PHP_MD5Final(digest, &context); if (raw_output) { RETURN_STRINGL(digest, 16, 1); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str, 1); } } ------------------------------------------------------------------------ [2007-11-29 14:59:48] [EMAIL PROTECTED] Description: ------------ Under certain circumenstances, the implicit call to __toString() on an object may lead to memory leaks. In the reproducable example, the following line leaks ($o is a simply object): md5($o); But this line doesn't: md5($o->__toString()); This only applies to certain functions, I've identifier md5, sha1 and crc32. If I try other examples like strstr or strlen, there's no leak at all. A wild guess is that this maybe has to do whether the function internally uses zend_parse_parameters() or zend_get_parameters_ex(). The function which leak use zend_parse_parameters(), the others don't. But this may completely accidental. It seems very related to bug#38591. However I don't see how bug#38604 is related to this issue (mentioned in bug#38591). This leak was most notable found in an application which is supposed to run for a long time, even hours. So usually within web application this is not an issue. Reproduce code: --------------- <?php class Foo { function __toString() { return 'foo'; } } for ($i = 0; $i < 1e5; $i++) { $o = new Foo; # leaks md5($o); # does not leak #md5($o->__toString()); # does not leak either way # strstr($o, 'f'); #strstr($o->__toString(), 'f'); if ($i % 1e3 == 0) { printf("%u: %1.2f KB\n", $i, memory_get_usage(true) / 1024); } } Expected result: ---------------- Constant memory usage. Actual result: -------------- Memory grows and grows. ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=43450&edit=1