5

HtmlAgilityPackを使用して、約200,000のHTMLドキュメントを解析しています。

これらのドキュメントの内容を予測することはできませんが、そのようなドキュメントの1つが原因で、アプリケーションが。で失敗しますStackOverflowException。ドキュメントには次のHTMLが含まれています。

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

<li>そのようにネストされた要素は約10,000個あります。HtmlAgilityPackがHTMLを解析する方法が原因で、が発生しStackOverflowExceptionます。

残念ながら、StackOverflowExceptionは.NET2.0以降ではキャッチできません。

スレッドのスタックに大きなサイズを設定することについて疑問に思いましたが、大きなスタックサイズを設定すると、ハックになります。プログラムがより多くのメモリを使用することになります(私のプログラムは、HTMLを処理するために約50スレッドを開始するため、これらのスレッドはすべてスタックサイズが大きくなります)、同様の状況が再び発生した場合は、手動で調整する必要があります。

他に採用できる回避策はありますか?

4

3 に答える 3

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を追加しました。「ドキュメントにX個を超えるネストされたタグがあります。これは、ページがタグを適切に閉じていないことが原因である可能性があります。」というメッセージとともにApplicationExceptionがスローされます。

パッチ後のHapの使用方法...

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);
}
于 2013-03-08T20:55:18.807 に答える
2

理想的には、長期的な解決策は、HtmlAgilityPackにパッチを適用して、コールスタックの代わりにヒープスタックを使用することですが、それは私には大きすぎる作業になります。CodePlexアカウントの詳細を一時的に失いましたが、戻ってきたら、問題に関する問題レポートを送信します。また、この問題により、HtmlAgilityPackを使用してユーザーが送信したHTMLをサニタイズするサイトにサービス拒否攻撃の脆弱性が存在する可能性があることにも注意してください。

それまでの間、スレッドスタックの最大サイズを手動で上書きするのが最善の方法だと思いました。以前のステートメントでは、スタックサイズが大きいということは、すべてのスレッドがそのメモリを自動的に消費することを意味するというのは間違っていました(メモリページは、スレッドスタックが大きくなるにつれて、一度にではなく、スレッドスタックに割り当てられるようです)。

ページのコピーを作成し、<ol><li>いくつかの実験を実行しました。スタックサイズがバイト(2MB)未満の場合、プログラムが失敗することがわかりました2^21が、最大サイズの2^22バイト(4MB)は成功しました。そして、私の本の4MBは、今のところ「許容できる」ハックとして渡されます。

于 2012-10-01T01:00:28.917 に答える
-1

これは機能するはずです:


HtmlDocument.MaxDepthLevel = 10000;
var doc = new HtmlDocument();
try
{
    doc.LoadHtml(document);
}
catch(Exception ex)
{
    Console.WriteLine("Exception while loading html: " + ex);
    yield break;
}

于 2022-01-11T10:31:59.117 に答える