windows - El código de un tercero está modificando la palabra de control de FPU
delphi com (2)
Aunque la palabra de control FP es por subproceso, se invocan las funciones dllmain cuando se crean subprocesos nuevos, no creo que pueda evitar este corto proceso de ir a un nuevo proceso.
Sugiero que genere un nuevo proceso para ejecutar COM y chatear con el proceso con su método de comunicación entre procesos favorito (por ejemplo, mensaje de Windows, COM fuera de proc, canalización con nombre, socket, etc.). De esta forma, el servidor COM es libre de hacer todo tipo de daños (incluido el bloqueo) sin tener que bajar el proceso de host.
Otra idea es escribir una DLL cuyo único propósito es restablecer la FPU en su DllMain y cargarla inmediatamente después de la DLL ofensiva. Es probable que Windows esté usando la orden de carga para llamar a DllMain cuando se crean subprocesos nuevos, incluidos los subprocesos creados por el servidor COM. Tenga en cuenta que esto depende del comportamiento interno de Windows. Además, el servidor COM en realidad puede depender de las excepciones fp ya que las habilita. La desactivación de las excepciones FP puede provocar que el servidor COM se comporte de forma inesperada.
La introducción - la parte larga y aburrida
(La pregunta está al final)
Recibo dolores de cabeza severos sobre un componente COM de un tercero que sigue cambiando la palabra de control de FPU.
Mi entorno de desarrollo es Windows y Visual C ++ 2008. La palabra de control de FPU normal especifica que no se deben lanzar excepciones durante varias condiciones. Lo he verificado tanto con la macro _CW_DEFAULT
encontrada en float.h
, como con la palabra de control en el depurador al inicio.
Cada vez que realizo una llamada al objeto COM, la palabra de control se modifica al regresar. Esto es fácil de defenderse. Simplemente reinicié la palabra de control, y todo está bien. El problema es cuando el componente COM comienza a llamar a mi receptor de eventos. Puedo proteger mi código reiniciando la palabra de control tan pronto como reciba la llamada al evento, pero no puedo hacer nada tan pronto como regrese de la llamada al evento.
No tengo la fuente para este componente COM, pero estoy en contacto con el autor. Las respuestas que he recibido de él han sido "¿Eh?". No creo que tenga la menor idea de lo que estoy hablando, así que me temo que tengo que hacer algo al respecto. Creo que su tiempo de ejecución (creo que es Delphi o Borland C ++, porque la DLL está llena de nombres de símbolos, todos comenzando con T mayúscula) o algún otro código de terceros que esté usando, está causando el problema. No creo que su código modifique explícitamente la palabra de control FPU.
¿Entonces Que puedo hacer? Desde el punto de vista comercial, es imprescindible usar este componente de terceros. Desde un punto de vista técnico, podría abandonarlo e implementar el protocolo de comunicación yo mismo. Sin embargo, eso sería realmente costoso, ya que este protocolo implica el manejo de transacciones de tarjetas de crédito. No queremos asumir la responsabilidad.
Necesito desesperadamente un hack-around, o alguna información útil sobre la configuración de FPU en los productos de Borland que pueda pasar al autor del componente.
Las preguntas
¿Hay algo que pueda hacer? No creo que el autor del componente tenga lo que se necesita para solucionarlo (a juzgar por sus respuestas bastante despistadas).
He estado jugando con la idea de instalar mi propio manejador de excepciones, en el cual simplemente reinicié la palabra de control en el controlador, y le digo a Windows que continúe la ejecución. Intenté instalar el manejador con SetUnhandledExceptionFilter()
, pero por alguna razón, las excepciones no son atrapadas.
- ¿Por qué no estoy atrapando las excepciones?
- Si logro capturar las excepciones de FPU, restablecer la palabra de control de FPU y dejar que la ejecución continúe como no pasó nada, ¿todas las apuestas están desactivadas?
Actualizar
Me gustaría agradecer a todos por sus sugerencias. He enviado al autor instrucciones sobre lo que puede hacer para facilitar la vida no solo a mí, sino a muchos otros clientes de su código. Le sugerí que muestreara la palabra de control FPU en DllMain(DLL_PROCESS_ATTACH)
y guardara la palabra de control para más adelante, para que pueda reiniciar FPU CW antes de llamar a mis controladores de eventos y regresar de mis llamadas.
Por ahora, tengo un truco si alguien está interesado. El hack-around es potencialmente malo, porque no sé lo que hará con su código. He recibido confirmación antes de que no usa ningún número de coma flotante en su código, por lo que debería ser seguro, salvo que utilice un código de terceros que utilice, que se base en excepciones de FPU.
Las dos modificaciones que he hecho a mi aplicación:
- Ajustar mi mensaje bomba
- Instale un gancho de ventana (
WH_CALLWNDPROC
) para atrapar los casos de esquina donde se omite la bomba de mensajes
En ambos casos, verifico si el FPU CW ha cambiado. Si es así, lo _CW_DEFAULT
en _CW_DEFAULT
.
Creo que su diagnóstico de que el componente está escrito en un producto Embarcadero es muy probable que sea cierto. La biblioteca de tiempo de ejecución de Delphi sí habilita excepciones de coma flotante, lo mismo para C ++ Builder.
Una de las cosas buenas de las herramientas de Embarcaderos es que los errores de punto flotante se convierten en excepciones de idioma, lo que hace que la codificación numérica sea mucho más fácil. ¡Eso te servirá de poco consuelo!
Toda esta área es un PITA colosal. No hay reglas sobre la palabra de control de FP. Es un total gratis para todos.
No creo que atrapar excepciones no controladas no termine el trabajo porque el tiempo de ejecución de MS C ++ ya estará capturando estas excepciones, pero no soy experto en esa área y podría estar equivocado.
Creo que su única solución realista es configurar la FPU a lo que usted quiere que sea siempre que la ejecución llegue a su código y restaurarla cuando la ejecución abandona su código. No sé lo suficiente sobre los sumideros de eventos COM para entender por qué presentan un obstáculo para hacer esto.
Mi producto incluye una DLL implementada en Delphi y sufro el problema inverso. La mayoría de los clientes que llaman tienen una palabra de control FPU que desactiva las excepciones. La estrategia que adoptamos es recordar el 8087CW en la entrada, establecerlo en Delphi CW estándar antes de ejecutar el código, y luego restaurarlo en el punto de salida. También nos ocupamos de las devoluciones de llamadas restaurando el 8087CW de la persona que llama antes de realizar la devolución de llamada. Esta es una DLL simple en lugar de un objeto COM, por lo que probablemente sea un poco más simple.
Si decide intentar que el proveedor COM modifique su código, entonces deben llamar a la función Set8087CW()
.
Sin embargo, dado que no existen reglas para el juego, creo que el vendedor de objetos COM estaría justificado al negarse a cambiar su código y volver a cargarle la responsabilidad.
Lo siento si esta no es una respuesta 100% concluyente, ¡pero no pude convertir todos estos pensamientos en un comentario!