php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #43838 variant_set with IE leads to hang
Submitted: 2008-01-14 12:58 UTC Modified: -
Votes:3
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: csaba at alum dot mit dot edu Assigned:
Status: Open Package: COM related
PHP Version: 5.2.5 OS: Win XP Pro
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: csaba at alum dot mit dot edu
New email:
PHP Version: OS:

 

 [2008-01-14 12:58 UTC] csaba at alum dot mit dot edu
Description:
------------
If an event sink is set on IE, and then a new window is created by that IE (by clicking on a link with target=_blank, say), then NewWindow2 fires.  By replacing the first argument to NewWindow2 (via set_variant) it is possible to identify the pending new ie and to assign a sink, $sink2, to it).
The problem is that the $sink2->ie is somehow corrupted to such an extent that trying to access anything on it hangs ie badly.

There is a 2nd less severe but still significant problem:  If the bug causing 2 lines just above the print "\n"; in BeforeNavigate2 are commented out, then the PHP code will terminate if either instance of IE is closed.  However, there is also an error genereated at the same time (the specific error varies, but I suspect that it has to do with cleanup of the COM objects).

Reproduce code:
---------------
<?php
// set_variant bug testing
$aES = array();	     // global array of IE event sinks
$newIEpage = "<body " .
        "onload='document.links[0].click()'>" .
        "<a target=_blank " .
        "href='http://google.com'>Goog</a></body>";

$ie = new COM("InternetExplorer.Application");
sink_ie($ie);
$ie->visible = true;
$ie->Navigate2("about:blank");
while ($ie->ReadyState<4) com_message_pump(200);
$ie->Navigate2("javascript:\"$newIEpage\"");
$ie->document->title = "variant_set Launcher";

$keepLooping = true;
while ($keepLooping) com_message_pump(200);
print "Exiting";

class mysink {
  public $ie = null;  // reqd for evt sink to function
  function __construct($ie) { $this->ie = $ie; }

  public function BeforeNavigate2 (
      $ie, $url, $flags, $targetFrameName,
      $postData, $headers, &$cancel) {
    print __FUNCTION__ . ": " . typename($ie) . ", ";
    print $ie->hwnd . ", rs: " . $ie->ReadyState;
    print "; " . $url . "\n";
    global $aES;
    print "  Sink count: " . sizeof($aES);
    print ", this->ie: ";
    print typename($this->ie) . ", ";  // produces bug
    print $this->ie->hwnd;             // produces bug
    print "\n";
  }

  public function NewWindow2 (&$newIe, $cancel) {
    $ie = new COM("InternetExplorer.Application");
    print "NewWindow2: ";
    variant_set($newIe, $ie);
    $sink2 = sink_ie($ie);
    print $sink2->ie->hwnd . "\n";
  }

  public function DownloadComplete() {
    print __FUNCTION__ . "\n"; }
  public function DocumentComplete($dom, $url) {
    print __FUNCTION__ . ": $url\n"; }
  public function onQuit() { print "Quitting\n";
    $GLOBALS['keepLooping'] = false; }
}

function typename($objCOM) {
  // similar to typename in vbscript
  if (empty($objCOM)) return "no COM object";
  if (gettype($objCOM)!="object")
    return "not a COM object";
  ob_start();
  com_print_typeinfo($objCOM);
  $typeInfo = ob_get_contents();
  ob_end_clean();
  $pattern = "/^\\s*class (.*) \\{/";
  if (!($matchCnt = preg_match($pattern,
                       $typeInfo, $aMatch)))
    return "Not found";
  return "COM:" . $aMatch[1];
}

function sink_ie($ie) {
  // sink $ie, and add to global array of sinks
  global $aES;
  com_event_sink ($ie, $aES[] = $sink = 
       new mysink($ie),
       "DWebBrowserEvents2");
  return $sink;
}
?>

Expected result:
----------------
This is PHP CLI code.  When run from the cmd prompt, I expect two instances of IE to come up (they do), and for the cmd prompt to display the navigation progress.

Now I could see that $sink2->ie becomes obsolete somehow (even though its hwnd is the same as the hwnd that comes into BeforeNavigate2), but what seems really wrong is to get a hang upon trying to do anything with that variable in BeforeNavigate2 (either $this->ie or $aES[sizeof($aES)-1]->ie)

Actual result:
--------------
If the included script is run as is, then typename($this->ie) causes a hang.  If it is commented out, $this->ie->hwnd causes a hang.  If both of these statements (the two lines before the last print statement in BeforeNavigate2) are commented out, then both IE pages will load OK (ie. the main bug goes away), and there will only be issues when the php code shuts down on account of one of the two IE's being closed.

A note about the code: While it may appear somewhat convoluted, the point of the original code was to track navigation progress within ie, and this works fine.  However, when (simulated) clicking on a link causes the browser to open a new window, then navigation tracking must continue with a new ie, and the way to get ahold of that ie is with the NewWindow2 or NewWindow3 event, and I used the former.

Two things need to happen in NewWindow2.  The first is that the first argument to the event handler needs to be set to an uninitiated, fresh IE.  The second is that this new IE needs to be sinked.  Because we're in an event handler, globals are not so good, but since event sinks require a reference to their COM object, the sink gets an IE variable.  The variable is not superfluous: if you make NewWindow2's final line be $sink2->ie = null; the 2nd event handler won't function.  $aES is not required in the script, but it is useful in broader schemes where one cannot be sure whether the particular IE is already sunk (and hence one iterates through it, looking at the handles of the associated IEs.

Csaba Gabor from Vienna

Patches

Add a Patch

Pull Requests

Add a Pull Request

 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Sat Jan 25 06:01:24 2020 UTC