|
|
|
date: Wed, 22 Feb 2006 15:33:07 -0600,
group: microsoft.public.inetsdk.programming.urlmonikers
back
Access Violation in Passthru Internet protocol Sink APP
We have implemented an IE toolbar that installs a pluggable protocol
handler
for http and https requests. Most of the time it works great, but on
occasions we are getting an access violation error when IE is unloading.
I've
tried to summarize why we are doing this and what is happening below. If
anyone has run into this before or has any suggestions, we would greatly
appreciate it.
Summary of Crash Situation
Purpose of the Code
Our code implements an IE toolbar object running under IE6. The toolbar
obtains an event sink from the web browser to monitor various browser
navigation events, document completion events, and browser shutdown
events).
In order to implement a critical feature in the toolbar, we need to
capture
information about any interim redirections that occur when IE is
navigating
to a new site. This information is not sent by the web browser; the
BeginNavigate2 event tells the initial navigation URL while the
NavigateComplete2 event returns the final URL. We discovered that this
information is not provided by any other existing IE event sink or
interface.
In order to capture this information we chose to implement a pass-thru
pluggable internet protocol and install it to handle http and https
requests.
The pluggable protocol object handles all HTTP(S) moniker requests that
are
made process-wide. As an efficiency, we keep a list of the (very few)
URLs
that we are interested in and only retain redirection information for
them.
The project is built using VC++6.0 and is using UNICODE strings. The
target
platform is IE6 running on Windows XP SP2.
Implementation
The protocol handler is installed by calling the
IInternetSession::RegisterNamespace() method . The object implements and
supports the IHttpNegotiate , IInternetProtocol, IInternetProtocolInfo,
IInternetPriority, IInternetThreadSwitch, and, for XPSP2,
IWinInetHttpInfo.
All calls into these interfaces are passed through to the underlying
default
implementation. We track and capture URL redirection information in our
implementation of the IHttpNegotiate interface. The code tracks the
navigation process by monitoring the BeginTransaction event (to get the
initial URL), any ReportProgress reports that have a
BINDSTATUS_REDIRECTING
status code for any interim redirections, and the OnResponse to determine
the
status of the download.
The timeline of a sink object is:
0. URLMon.dll code calls our factorys CreateInstance method. We
create a
sink object, initialize the tracking URL to NULL , and initialize the
Event
sink to NULL. (at this point, the monikers URL is not known)
1. BeginTransaction is called with the requested URL . The URL is
stored in
a STL string object. The URL is checked against a list of URLs of
Interest;
if we are interested in it, we have the sink object send events to a
collection object when:
a. URLMon calls ReportProgress with a BINDSTATUS_REDIRECTING status.
The
collection object stores these in an STL vector of STL string objects.
Access
to the collection object is controlled by a mutex.
b. URLMon calls OnResponse with the HTTP response code.
2. URLMon.dll releases the sink object
The basic implementation of our pass-thru object is based on a sample
written by Igor Tandetnik. It is an ATL-based object. With the exception
of
the tracking described above, everything just gets passed thru to the
default
implementation with no modification or additional processing.
Crash Problem
For 99 44/100% of the cases, the life cycle of the object is correct
URLMon creates the sink, calls BeginTransaction, makes calls to
ReportProgress & OnResponse, and then Releases its reference to the
object.Our problem is that, on random occasions, there is an access
violation
when IE is being unloaded. Ive tracked this down to a specific
situation:
Our DllCanUnloadNow() entrypoint is called several times. Since there are
still outstanding objects for the DLL, S_FALSE is returned.
Our DllMain() entrypoint is called with DLL_PROCESS_DETACH as a
parameter.
At this point, there are still many threads running and we still have
object
locks. Note, at no point prior did we return S_OK when DllCanUnloadNow()
was
called.
I observe that there is an outstanding Sink object that URLMon has
created,
but for which it has not yet called BeginTransaction(). There is nothing
I
know of that I can do at this point to prevent the subsequent access
violation - URLMon has created this object and retains a reference to
it. It
appears that Windows does not recognize that URLMon.dll is dependent on
the
object in my DLL and is unloading my DLL before it does URLMon. Again,
this
is occurring even though I have not yet returned S_OK from
DllCanUnloadNow().
Here is my debugging output:
LOG> DllCanUnLoadNow Locks 28 returning S_FALSE
LOG> DllCanUnLoadNow Locks 28 returning S_FALSE
LOG> DllCanUnLoadNow Locks 28 returning S_FALSE
LOG> DllCanUnLoadNow Locks 28 returning S_FALSE
LOG> SinkObjectDump This 0x177e2bc Url EventSink 0x0 <<- sink object
address
LOG> ERROR!! Detaching Process with objects still active !!
LOG> --- INITLOG REASON 0 HINSTANCE 0x1550000 RESERVED 0x0
(DLL_PROCESS_DETACH)
The thread 0xB08 has exited with code 0 (0x0).
The thread 0xFC4 has exited with code 0 (0x0).
The thread 0x684 has exited with code 0 (0x0).
The thread 0xBD4 has exited with code 0 (0x0).
The thread 0xFA8 has exited with code 0 (0x0).
The thread 0x968 has exited with code 0 (0x0).
The thread 0x530 has exited with code 0 (0x0).
The thread 0x5C0 has exited with code 0 (0x0).
The thread 0xC9C has exited with code 0 (0x0).
The thread 0xB04 has exited with code 0 (0x0).
The thread 0xC8C has exited with code 0 (0x0).
The thread 0xB18 has exited with code 0 (0x0).
The thread 0x850 has exited with code 0 (0x0).
The thread 0xEAC has exited with code 0 (0x0).
The thread 0xBF0 has exited with code 0 (0x0).
The thread 0xC6C has exited with code 0 (0x0).
The thread 0xE84 has exited with code 0 (0x0).
The thread 0x4EC has exited with code 0 (0x0).
The thread 0xA90 has exited with code 0 (0x0).
First-chance exception in IEXPLORE.EXE (URLMON.DLL): 0xC0000005: Access
Violation.
My DLL unloads and, as the final thread is finishing up I get an access
violation when urlmon.dll is trying to access that object in now-freed
memory. At this point, the call stack for the thread is:
URLMON! 77279a88()
WININET! 771d6f4f()
WININET! 771d77ac()
WININET! 771c51fb()
WININET! 771c4b96()
WININET! 771c4ee1()
WININET! 771c4e43()
WININET! 771ca603()
WININET! 771ca603()
URLMON! 772796cb()
URLMON! 77261845()
URLMON! 772617bf()
NTDLL! 7c9011a7()
NTDLL! 7c923f31()
KERNEL32! 7c81ca3e()
KERNEL32! 7c81cab6()
SHDOCVW! 777e80d5()
IEXPLORE! 00402372()
IEXPLORE! 00402444()
KERNEL32! 7c816d4f()
At this point, the code around the crash is:
Code in UrlMon.dll
77279A6C nop
77279A6D mov edi,edi
77279A6F push edi
77279A70 mov edi,ecx
77279A72 cmp dword ptr [edi+110h],0
77279A79 jne 77279A9E
77279A7B push esi
77279A7C lea esi,[edi+98h]
77279A82 mov eax,dword ptr [esi]
77279A84 test eax,eax
77279A86 je 77279A91
77279A88 mov ecx,dword ptr [eax] <<<------ Current IP, EAX
contains address of Sink Object
77279A8A push eax
77279A8B call dword ptr [ecx+8]
77279A8E and dword ptr [esi],0
77279A91 add edi,140h
77279A97 push edi
77279A98 call 7726D79F
77279A9D pop esi
77279A9E pop edi
77279A9F ret
EAX = 0177E2BC EBX = 00000000
ECX = 037DEE30 EDX = 77239718
ESI = 037DEEC8 EDI = 037DEE30
EIP = 77279A88 ESP = 0013FA30
EBP = 0013FA48 EFL = 00000202
date: Wed, 22 Feb 2006 15:33:07 -0600
author: C_Bar
Re: Access Violation in Passthru Internet protocol Sink APP
"C_Bar" wrote in message
news:Xns9772A861C10A51313MockingbirdHeigh@216.196.97.136
> Crash Problem
> For 99 44/100% of the cases, the life cycle of the object is correct
> URLMon creates the sink, calls BeginTransaction, makes calls to
> ReportProgress & OnResponse, and then Releases its reference to the
> object.Our problem is that, on random occasions, there is an access
> violation
> when IE is being unloaded. Ive tracked this down to a specific
> situation:
>
> Our DllCanUnloadNow() entrypoint is called several times. Since there
> are still outstanding objects for the DLL, S_FALSE is returned.
>
> Our DllMain() entrypoint is called with DLL_PROCESS_DETACH as a
> parameter.
> At this point, there are still many threads running and we still have
> object
> locks. Note, at no point prior did we return S_OK when
> DllCanUnloadNow() was
> called.
Can you produce a reasonably small sample that reproduces the problem at
least somewhat reliably? If you can, could you email it to me at
itandetnik@mvps.org? I'd like to look at it.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
date: Thu, 23 Feb 2006 08:54:06 -0500
author: Igor Tandetnik
Re: Access Violation in Passthru Internet protocol Sink APP
C_Bar wrote:
>> Can you produce a reasonably small sample that reproduces the problem
>> at least somewhat reliably? If you can, could you email it to me at
>> itandetnik@mvps.org? I'd like to look at it.
>
> Thanks for your reply. I am working on segregating this functionality
> into its own dll. This should facilitate coding a smaller scale test
> case as well as isolating the problem. I'll let you know when i have
> one.
>
> Our biggest frustration/question is why DllMain() is being called
> with a DLL_PROCESS_DETACH when we have always returned S_FALSE when
> DllCanUnloadNow() was called.
When the whole process shuts down, all DLLs get unloaded, naturally,
whether they want to or not. They get unloaded in essentially random
order.
The real question is, why does not IE stop all activity and make
everybody release all resources before shutting down.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
date: Thu, 23 Feb 2006 12:22:55 -0500
author: Igor Tandetnik
|
|