2012-10-01 139 views
5

我使用HtmlAgilityPack来解析大约200,000个HTML文档。解决方法StackOverflowException

我无法预测这些文档的内容,但是一个这样的文档导致我的应用程序失败,出现StackOverflowException。该文档包含以下HTML:

<ol> 
    <li><li><li><li><li><li>... 
</ol> 

大致有10,000个<li>这样的嵌套元素。由于HtmlAgilityPack解析HTML的方式,导致StackOverflowException

不幸的是,StackOverflowException在.NET 2.0及更高版本中不可捕捉。我想知道为线程的堆栈设置一个更大的大小,但是设置一个更大的堆栈大小是一个骇客:它会导致我的程序使用更多的内存(我的程序启动大约50个线程来处理HTML,所以所有这些线程都会增加堆栈大小),并且如果它再次遇到类似情况,则需要手动调整。

有没有其他解决方法可以使用?

+0

不是真的。除非您想切换到不同的库,否则我看不到增加堆栈大小的更好方法。也许有一种方法只为需要的线程设置堆栈大小? –

回答

2

理想情况下,长期的解决方案是修补HtmlAgilityPack以使用堆栈而不是调用堆栈,但这对我来说太大了。我暂时失去了我的CodePlex帐户详细信息,但是当我将它们还给他人时,我会提交问题报告。我还注意到,这个问题可能会给任何使用HtmlAgilityPack来清理用户提交的HTML的站点带来拒绝服务攻击漏洞 - 一个精心制作的嵌套HTML文档会导致w3wp.exe进程死亡。

与此同时,我认为最好的方法是手动覆盖最大线程堆栈大小。我在之前的声明中错误地认为,更大的堆栈大小意味着所有线程都会自动消耗该内存(看起来内存页面随着它增长而分配给线程堆栈,而不是一次全部分配)。

我制作了<ol><li>页面的副本并进行了一些实验。当堆栈大小小于2^21字节时,我发现程序失败,但最大大小为2^22成功 - 这是4MB,并且在我的书中作为“可接受的”黑客入侵......现在。

5

我只是修补了一个错误,我相信这与您的描述相同。上传补丁到HAP项目现场......

http://www.codeplex.com/site/users/view/sjdirect(见2012/3/8补丁)

还是看到了问题的更多的文档,并导致这里....

https://code.google.com/p/abot/issues/detail?id=77

实际修复是......可以设置以防止由吨嵌套标签造成StackOverflowExceptions 新增HtmlDocument.OptionMaxNestedChildNodes。它会抛出一个ApplicationException消息“Document有多个X嵌套标签,这可能是由于页面没有正确关闭标签。”

我如何使用厦门补丁后...

HtmlDocument hapDoc = new HtmlDocument(); 
hapDoc.OptionMaxNestedChildNodes = 5000;//This is what was added 
string rawContent = GETTHECONTENTHERE 
try 
{ 
    hapDoc.LoadHtml(RawContent);  
} 
catch (Exception e) 
{ 
    //Instead of a stackoverflow exception you should end up here now 
    hapDoc.LoadHtml(""); 
    _logger.Error(e); 
}