我创建了一个 ISAPI 过滤器。它在开发服务器和 SIT 服务器上运行良好。
但是在生产服务器中它不起作用。
在事件查看器中,以下日志:
报告排队错误:错误应用程序 w3wp.exe,版本 6.0.3790.2825,错误模块 msvcr80.dll,版本 8.0.50727.3053,错误地址 0x00046039。
遇到这个问题时,我从 CodeProject 中 获取了Jochen Klambach 的 StackWalker 。更新: StackWalker 现在已经毕业到 Codeplex。一定要拿到 codeplex 版本;它包括几个更新和修复。
当过滤器崩溃时,它将为您的代码打印堆栈。
我这样做的方式是:在我的过滤器中的 OnAuthComplete 中,这是我的过滤器完成所有工作的地方,我用 try 包围了逻辑......除了:
__try
{
dwRetval = DoRewrites(...);
}
__except ( ExcFilter(GetExceptionInformation()) )
{
}
然后,ExcFilter 是这样定义的:
extern "C" int ExcFilter(EXCEPTION_POINTERS *pExp)
{
MyLoggingStackWalker *sw = new MyLoggingStackWalker();
sw->ShowCallstack(GetCurrentThread(), pExp->ContextRecord);
return EXCEPTION_CONTINUE_SEARCH; // allow the process to crash
}
LoggingStackWalker 派生自 StackWalker,并覆盖 OnOutput 方法以将该输出发送到日志文件。它还将 PDB 文件的搜索路径设置为包含找到 DLL 的目录。
class MyLoggingStackWalker : public StackWalker
{
public:
MyLoggingStackWalker() : StackWalker()
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
// add the directory for the ISAPI DLL, to the search path for PDB files
this->m_szSymPath = (LPSTR) malloc(_MAX_PATH);
_splitpath_s(DllLocation, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
_makepath_s(this->m_szSymPath, _MAX_PATH, drive, dir, NULL, NULL);
}
virtual void OnOutput(LPCSTR szText)
{
LogMessage((char*)szText);
StackWalker::OnOutput(szText);
}
};
为了演示它,我在代码中将一个错误的指针传递给 vscprintf。这就是 IIS7 上生成的堆栈跟踪的样子。您可以看到前几帧在 C 运行时中,也带有行号。(如果您使用默认设置,StackWalker 实际上会从 MS 符号服务器下载符号文件。如果您愿意,可以将其关闭。)然后下一组帧来自我的代码。它指出了问题的位置。我的堆栈帧 - 这些都是 IIS 模块。这是 Vista 上的 IIS7;我猜符号服务器没有这些模块的符号。无论如何,正如您所看到的,stacktrace 毫无疑问地确定了问题出在哪里。
f:\dd\vctools\crt_bld\self_x86\crt\src\output.c (1068): _output_l
f:\dd\vctools\crt_bld\self_x86\crt\src\vsprintf.c (405): _vscprintf_helper
f:\dd\vctools\crt_bld\self_x86\crt\src\vsprintf.c (414): _vscprintf
c:\dev\isapi\filter\logger.c (193): LogMessage
c:\dev\isapi\filter\rewriter.c (2036): EvaluateRewrites
c:\dev\isapi\filter\rewriter.c (789): DoRewrites
c:\dev\isapi\filter\rewriter.c (955): OnAuthComplete
c:\dev\isapi\filter\rewriter.c (1139): HttpFilterProc
60531896 module(filter): (filename not available): (function-name not available)
60531FAB module(filter): (filename not available): (function-name not available)
605314E3 module(filter): (filename not available): (function-name not available)
60531276 module(filter): (filename not available): (function-name not available)
6D122EA0 module(iiscore): (filename not available): (function-name not available)
6D123696 module(iiscore): (filename not available): (function-name not available)
6D12AA4C module(iiscore): (filename not available): (function-name not available)
6D125D3B module(iiscore): (filename not available): (function-name not available)
6D1220F4 module(iiscore): (filename not available): (function-name not available)
6D124EEF module(iiscore): (filename not available): (function-name not available)
6D12C6B8 module(iiscore): (filename not available): (function-name not available)
70CB13B3 module(w3dt): (filename not available): UlAtqGetContextProperty
70CB11DA module(w3dt): (filename not available): (function-name not available)
71A42611 module(W3TP): (filename not available): THREAD_POOL::PostCompletion
71A42812 module(W3TP): (filename not available): OverrideThreadPoolConfigWithRegistry
71A41E85 module(W3TP): (filename not available): (function-name not available)
76A54911 module(kernel32): (filename not available): BaseThreadInitThunk
7727E4B6 module(ntdll): (filename not available): __RtlUserThreadStart
7727E489 module(ntdll): (filename not available): _RtlUserThreadStart
7727E489 module(ntdll): (filename not available): _RtlUserThreadStart
好吧,这里没有足够的信息来说明发生了什么。您真正需要了解的是导致问题的条件。旧的 Windows 调试工具是您的朋友。如果您不熟悉使用调试器,那么ADPlus和Debug Diag等工具将对您有用。如果您正在寻找在 IIS 中调试的建议,您可能还想查看Tess Ferrandez 的博客,这是一个很好的资源。
一个即兴的猜测可能是某些东西正在将无效指针传递给 C 运行时函数之一。使用调试器,您应该能够识别该函数是什么以及传递的参数是什么。希望有了这些信息,您将能够弄清楚发生了什么。
您应该能够附加到该进程并使用 Visual Studio 对其进行调试。您可以使用进程资源管理器来确定哪个 w3wp.exe 进程正在运行您的 dll,并使用远程调试工具来调试另一台机器上的代码。