2010-02-10 12 views
25

Sé cómo crear un archivo .map para rastrear los errores de violación de acceso cuando el mensaje de error incluye una dirección real.Cómo rastrear la infracción de acceso "en la dirección 00000000"

Pero ¿y si el mensaje de error dice

Access violation at address 00000000. Read of address 00000000. 

¿Por dónde empezar a buscar la causa de este problema ...?

+1

Eso me recuerda a bajo Turbo C, "Asignación de puntero nulo" cuando se maneja de manera incorrecta ... – t0mm13b

+3

¿Es reproducible? De lo contrario, agregue una herramienta como madExcept y espere informes de error, use el depurador y observe el rastreo de la pila. –

+0

Esto es de los días anteriores de Turbo C, debajo del depurador, agregue un reloj a la variable puntero apuntando a la ubicación 0, la línea recién ejecutada al entrar en ella, que provocó que la variable apuntando a la ubicación 0 cambie el valor es la línea que hecho un desastre. Principalmente un error de puntero ... – t0mm13b

Respuesta

27

Una infracción de acceso en cualquier lugar cerca de la dirección '00000000' indica un acceso de puntero nulo. Está utilizando algo antes de que se haya creado, lo más probable, o después de que haya sido FreeAndNil() 'd.

Muchas veces esto se debe al acceso a un componente en el lugar incorrecto durante la creación del formulario, o al hacer que su forma principal intente y acceda a algo en un módulo de datos que aún no se ha creado.

MadExcept hace que sea muy fácil rastrear estas cosas, y es gratis para uso no comercial. (En realidad, una licencia de uso comercial también es bastante económica y vale la pena el dinero.)

+4

Estoy marcando esto como la respuesta "correcta" ya que la sugerencia sobre MadExcept fue muy útil. Sin embargo, parece que en mi caso específico, el error ocurre en una biblioteca de terceros (y con suerte se puede solucionar mediante la aplicación de un parche de proveedor), por lo que esta vez no tuve que investigar más. – ObiWanKenobi

+0

Significa que el objeto al que está aplicando ya se ha destruido o aún no se ha creado – Kutsoff

1

Probablemente sea porque está directa o indirectamente a través de una llamada a la biblioteca accediendo a un puntero NULL. En este caso particular, parece que saltó a una dirección NULL, que es un poco más peluda.

En mi experiencia, la manera más fácil de seguir estos pasos es ejecutarlo con un depurador y volcar un seguimiento de la pila.

Como alternativa, puede hacerlo "a mano" y añadir un montón de registro hasta que se pueda rastrear exactamente qué función (y posiblemente LOC) esta violación se produjo en.

Tome un vistazo a Stack Tracer, lo que podría ayudar Mejoras tu depuración.

7

de empezar a buscar cerca de ese código que se sabe corrieron, y dejas de buscar cuando llegue el código que sabe no corrieron.

Lo que está buscando es probablemente un lugar donde su programa llama a una función a través de un puntero de función, pero ese puntero es nulo.

También es posible que tenga daños en la pila. Es posible que haya sobrescrito la dirección de retorno de una función con cero, y la excepción se produce al final de la función. Compruebe si hay posibles desbordamientos de búfer, y si llama a cualquier función de DLL, asegúrese de haber utilizado la convención de llamadas correcta y el recuento de parámetros.

Este no es un caso ordinario de uso de un puntero nulo, como una referencia de objeto no asignado o PChar. En esos casos, tendrá un valor distinto de cero "en la dirección x". Como la instrucción se produjo en la dirección cero, sabe que el puntero de instrucción de la CPU no apuntaba a ninguna instrucción válida. Es por eso que el depurador no puede mostrarle qué línea de código causó el problema; allí es sin línea de código. Debe encontrarlo buscando el código que conduce al lugar donde la CPU saltó a la dirección no válida.

La pila de llamadas aún puede estar intacta, lo que al menos te acercará bastante a tu objetivo. Sin embargo, si tiene daños en la pila, es posible que no pueda confiar en la pila de llamadas.

2

Cuando me encuentro con este problema, suelo empezar a buscar en los lugares donde FreeAndNil() o simplemente xxx: = NIL; variables y el código después de eso.

Cuando nada más ha ayudado, he agregado una función Log() para enviar mensajes de varios lugares sospechosos durante la ejecución, y luego miré ese registro para rastrear en qué parte del código aparece la infracción de acceso.

Por supuesto, hay muchas más soluciones elegantes disponibles para rastrear estas infracciones, pero si no las tiene a su disposición, el método de prueba antiguo & funciona bien.

1

Usar MadExcept. O JclDebug.

1

Voy a estar en segundo lugar con herramientas ExExcept y similares, como Eurekalog, pero creo que también puedes hacer un buen trabajo con FastMM. Con el modo de depuración completo habilitado, debería darle algunas pistas de lo que está mal.

De todos modos, aunque Delphi usa FastMM como valor predeterminado, vale la pena obtener el FastMM completo por su control adicional sobre el registro.

29

La respuesta aceptada no cuenta la historia completa.

Sí, siempre que vea ceros, un puntero NULL está involucrado. Eso es porque NULL es por definición cero. Así que llamar a cero NULL puede no decir mucho.

Qué es interesante acerca del mensaje que aparece es el hecho de que NULL se menciona dos veces . De hecho, el mensaje que informa se parece un poco a los mensajes que los sistemas operativos de la marca Windows muestran al usuario.

El mensaje dice la dirección NULL trataron de leer NULL. ¿Entonces que significa eso? Específicamente, ¿cómo se lee una dirección?

Normalmente pensamos en las instrucciones de una dirección de lectura y escritura de la memoria en ciertas direcciones. Sabiendo eso nos permite analizar el mensaje de error. El mensaje está tratando de articular que la instrucción en direcciónNULL intentó leerNULL.

Por supuesto, no hay instrucciones en la dirección NULL, es por eso que consideramos NULL como especiales en nuestro código. Pero se puede pensar que cada instrucción comienza con el intento de leerse a sí mismo. Si el registro de las CPU EIP está en la dirección NULL, la CPU intentará leer el código de operación para obtener una instrucción de la dirección 0x00000000 (NULL). Este intento de leer NULL fallará y generará el mensaje que ha recibido.

En el depurador, observe que EIP es igual a 0x00000000 cuando recibe este mensaje. Esto confirma la descripción que te he dado.

La pregunta entonces es: "¿Por qué mi programa intenta ejecutar la dirección NULL?"Hay tres posibilidades que vienen a la mente:.

  • Tienes intento de hacer una llamada de función a través de un puntero de función que se ha declarado, asignado a NULL, no inicializado contrario, y están dereferencing
  • Del mismo modo, puede estar llamando a un método C++ "abstracto" que tiene una entrada NULL en el vtable del objeto. Estos se crean en su código con la sintaxis virtual function_name()=0.
  • En su código, un buffer de pila se ha desbordado al escribir ceros. se han escrito más allá del final del almacenamiento intermedio de la pila, sobre la dirección de retorno conservada. Cuando la función más tarde ejecuta su ret instrucción, el valor 0x00000000 (NULL) se carga desde el punto de memoria sobrescrita. Este tipo de error, desbordamiento de pila, es el epónimo de nuestro foro.

Puesto que usted menciona que usted está llamando a una biblioteca de terceros, voy a señalar que puede ser una situación de la biblioteca esperando que proporcione un puntero no NULL función como entrada a algunos API. A veces se conocen como funciones de "devolución de llamada".

Deberá utilizar el depurador para reducir aún más la causa de su problema, pero las posibilidades anteriores le ayudarán a resolver el enigma.

3

Si obtiene 'Infracción de acceso en la dirección 00000000.', está invocando un puntero de función que no se ha asignado, posiblemente un controlador de eventos o una función de devolución de llamada.

por ejemplo

type 
TTest = class(TForm); 
protected 
    procedure DoCustomEvent; 
public 
    property OnCustomEvent : TNotifyEvent read FOnCustomEvent write FOnCustomEvent; 
end; 

procedure TTest.DoCustomEvent; 
begin 
    FOnCustomEvent(Self); 
end; 

En lugar de

procedure TTest.DoCustomEvent; 
begin 
    if Assigned(FOnCustomEvent) then // need to check event handler is assigned! 
    FOnCustomEvent(Self); 
end; 

Si el error se encuentra en un componente de terceros, y se puede realizar el seguimiento del código erróneo abajo, utilice un controlador de eventos vacío para evitar que el AV .

-1

Aquí hay una solución temporal realmente rápida, al menos hasta que reinicie de nuevo, pero se deshará de un acceso persistente. Instalé un programa que funciona bien pero, por alguna razón, hay un punto que no se instaló correctamente en el archivo correcto. Entonces, cuando no puede acceder al archivo, aparece el acceso denegado, pero en lugar de uno solo, intenta iniciarlo, por lo que incluso buscando la ubicación para detenerlo permanentemente, seguirá apareciendo cada vez más cada 3 segundos. Para evitar que eso suceda, al menos temporalmente, haga lo siguiente ...

  1. Ctl +Alt +Del
  2. Abra el Administrador de tareas
  3. Anote el nombre del programa que es solicitud de acceso (puede verlo en la pestaña de la aplicación)
  4. Haga clic en la pestaña Procesos
  5. Desplácese hasta encontrar el Proceso correspondiente el nombre del programa y haga clic en él
  6. clic en Finalizar proceso

que evitará la ventana de forma persistente a aparecer, al menos hasta que se reinicie.Sé que eso no resuelve el problema, pero como todo, hay un proceso de eliminación y este paso aquí al menos lo hará un poco menos molesto.

Cuestiones relacionadas