php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #18800 PHP crashes on cleaning up COM objects
Submitted: 2002-08-08 05:45 UTC Modified: 2002-08-12 11:05 UTC
From: mlorenz at novadys dot de Assigned:
Status: Closed Package: COM related
PHP Version: 4.2.2 OS: Windows2000 Professional
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: mlorenz at novadys dot de
New email:
PHP Version: OS:

 

 [2002-08-08 05:45 UTC] mlorenz at novadys dot de
It seems that php has a problem cleaning up COM object references. I wrote a litte COM server and the following script that demonstrates the problem.

<?php
  $myA = new COM("PHPTest.A.1") or die("Cannot create A");
  $myB = $myA->GetB();
   // myA creates a B object and returns a pointer to it.
   // It does not store the pointer itself.
  $myA->Release();
  $myC = new COM("PHPTest.C.1") or die("Cannot create C");
  $myC->B = $myB;
   // myC stores the pointer to the B object and AddRefs it.
   // It releases the pointer on destruction.
  $myC->Release();
  $myB->Release();
?>

After executing the script PHP crashes on cleanup.
I did a little debugging and found the following.

There is a function php_COM_release in ext/com/COM.c
that is called on every ...->Release call.
During execution of the script all objects are deleted
as expected. A look at the watch window shows me a 
structure called 'obj' that contains a field named 'resourceindex' the values are
1 for the A object
3 for the C object
2 for the B object
After destroying these objects the COM server is going down as expected because there are no more living objects.
When PHP is cleaning up, it crashes in the same function
trying to realease an object with the 'resourceindex' 4.
Here is the call stack:

php_COM_release(comval_ * 0x00dbd1f8, void * * * 0x00da2ad0) line 231 + 17 bytes
php_COM_destruct(comval_ * 0x00dbd1f8, void * * * 0x00da2ad0) line 363 + 13 bytes
php_comval_destructor(_zend_rsrc_list_entry * 0x00dbd3b0, void * * * 0x00da2ad0) line 373 + 15 bytes
list_entry_destructor(void * 0x00dbd3b0) line 177 + 16 bytes
zend_hash_apply_deleter(_hashtable * 0x00da8a34, bucket * 0x00dbd340) line 596 + 15 bytes
zend_hash_graceful_reverse_destroy(_hashtable * 0x00da8a34) line 662 + 13 bytes
zend_destroy_rsrc_list(_hashtable * 0x00da8a34, void * * * 0x00da2ad0) line 233 + 9 bytes
shutdown_executor(void * * * 0x00da2ad0) line 196 + 30 bytes
zend_deactivate(void * * * 0x00da2ad0) line 596 + 9 bytes
php_request_shutdown(void * 0x00000000) line 787 + 9 bytes
main(int 0x00000002, char * * 0x00da25d0) line 827 + 8 bytes
mainCRTStartup() line 338 + 17 bytes
KERNEL32! 77e87d08()

The line where the crash happens is:

		hr = C_DISPATCH_VT(obj)->Release(C_DISPATCH(obj));

Best regards
Michael


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-08-09 07:38 UTC] mlorenz at novadys dot de
It seems that the line

$myC->B = $myB 

is responsible for the crash, because it does not crash when I put // in front of the line.
 [2002-08-09 08:03 UTC] mlorenz at novadys dot de
This problem did not occur in PHP 4.0.6
 [2002-08-09 21:48 UTC] phanto@php.net
wow, this is indeed an exemplary bugreport :)

can you also tell me on which line in the php code the object with the resource index 4 is created ? or can you mail me your sample com server, this would save me a bit of work.
implicit objects should only be created in two cases, either if they are a return value of a function or property or if you dereference a member (e.g. $obj->foo->bar(), then an unnamed object for foo will be created), but these should be released again immediately if the were not assigned to a phpspace variable.
as i don't see any of the two cases i'm a bit confused and pondering where the 4th object instance comes from.

harald
 [2002-08-12 03:57 UTC] mlorenz at novadys dot de
I have simplified the script slightly for easier debugging but it still produces the same problem. 

1.  $myA = new COM("PHPTest.A.1") or die("Cannot create A");
2.  $myC = new COM("PHPTest.C.1") or die("Cannot create C");
3.  $myC->B = $myA;
4.  $myA->Release();
5.  $myC->Release();

Now only three objects are created and the one that causes the crash has the resourceindex '3'. It is created in line 3. I found the following additional information:

There is a function do_COM_propput in ext/com/COM.c

static void do_COM_propput(pval *return_value, comval *obj, pval *arg_property, pval *value TSRMLS_DC)
{
  ...
  hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYPUT, 
    &dispparams, NULL, &ErrString TSRMLS_CC);
  ...
  hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYGET,
    &dispparams, var_result, &ErrString TSRMLS_CC);
  if (SUCCEEDED(hr)) 
  {
    php_variant_to_pval(var_result, return_value, 
      codepage TSRMLS_CC);
  } 
  else 
  {
    *return_value = *value;
    zval_copy_ctor(return_value);
  }
  ...
}

The object is created by php_variant_to_pval. I do not understand why PHP is making a PROPERTYGET on the object on a put request, because it is possible for some COM object to have write only properties that do not implement the get_... method. But that's another story.

I will send the zipped COM example server sources to your e-mail.

Best regards,
Michael
 [2002-08-12 10:18 UTC] mlorenz at novadys dot de
Maybe i have found the problem.

I tracked down reference counts in the debugger. Because it is a little difficult with an out of process server, I turned my server into an inproc server. Please send me a mail if you want to have these sources too.
I found the following problem in do_COM_propput:
There is a VARIANT allocated with

  ALLOC_VARIANT(new_value);

Some lines later it is filled with the Dispatch pointer to the A object with

  php_pval_to_variant(value, new_value, codepage TSRMLS_CC);

As far as i have seen, this function does not AddRef the pointer. At the end of the function the VARIANT is cleared
by

  FREE_VARIANT(new_value);

This internally calls the COM API VariantFree that calls Release on the stored Dispatch pointer.
Can you please verify this ?

Best regards,
Michael
 [2002-08-12 11:05 UTC] phanto@php.net
thanks for your great work, but i'm sorry to have to inform you that this is fixed in cvs for quite a while now (since 31.5.2002), the fix came after 4.2.1 and didn't get into 4.2.2 as it was only a security update and didn't contain all the patches. try a cvs snapshot after this date and reopen this report if you still have problems.

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 05:01:29 2024 UTC