Trabajar alrededor de una excepción StackOverflowException

html-agility-pack stack-overflow

Pregunta

Estoy usando HtmlAgilityPack para analizar aproximadamente 200,000 documentos HTML.

No puedo predecir el contenido de estos documentos, sin embargo, uno de esos documentos hace que mi aplicación falle con una StackOverflowException . El documento contiene este HTML:

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

Hay aproximadamente 10,000 elementos <li> anidados de esa manera. Debido a la forma en que HtmlAgilityPack analiza HTML, causa una StackOverflowException .

Desafortunadamente, una excepción StackOverflowException no se puede capturar en .NET 2.0 y versiones posteriores.

Me pregunto acerca de establecer un tamaño más grande para la pila del hilo, pero establecer un tamaño más grande es un truco: haría que mi programa usara mucha más memoria (mi programa comienza con unos 50 hilos para procesar HTML, por lo que todos estos hilos tendría el mayor tamaño de pila) y necesitaría un ajuste manual si alguna vez se encontrara con una situación similar nuevamente.

¿Hay otras soluciones que podría emplear?

Respuesta aceptada

Idealmente, la solución a largo plazo es parchear HtmlAgilityPack para usar una pila de pila en lugar de la pila de llamadas, pero eso sería una empresa demasiado grande para mí. Perdí temporalmente los detalles de mi cuenta de CodePlex, pero cuando los recupere, enviaré un informe de problemas sobre el problema. También tengo en cuenta que este problema podría presentar una vulnerabilidad de ataque de denegación de servicio a cualquier sitio que use HtmlAgilityPack para sanear el HTML enviado por el usuario: un documento HTML creado excesivamente anidado causaría la muerte del proceso w3wp.exe.

Mientras tanto, pensé que la mejor manera de avanzar es anular manualmente el tamaño máximo de pila de hilos. Me equivoqué en mi declaración anterior de que un tamaño de pila mayor significa que todos los subprocesos consumen automáticamente esa memoria (parece que las páginas de memoria se asignan a una pila de subprocesos a medida que crece, no todo de una vez).

Hice una copia de la página <ol><li> y realicé algunos experimentos. Descubrí que mi programa falló cuando el tamaño de la pila tenía menos de 2^21 bytes de tamaño, pero un tamaño máximo de 2^22 exitoso, eso es 4MB y en mi libro pasa como un hack "aceptable" ... por ahora.


Respuesta popular

Acabo de corregir un error que creo que es el mismo que usted describe. Subido el parche al sitio del proyecto hap ...

http://www.codeplex.com/site/users/view/sjdirect (vea el parche el 3/8/2012)

O ver más documentación del problema y el resultado aquí ...

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

La solución real fue ... Se agregó HtmlDocument.OptionMaxNestedChildNodes que se puede configurar para evitar StackOverflowExceptions causadas por toneladas de etiquetas anidadas. Lanzará una excepción de aplicación con el mensaje "El documento tiene más de X etiquetas anidadas. Esto se debe probablemente a que la página no cierra las etiquetas correctamente".

Cómo estoy usando Hap After Patch ...

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);
}


Related

Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow