¿Qué sucede si hay un error de tiempo de ejecución?

17

¿Qué sucede si hay un error de tiempo de ejecución en un programa? ¿Se detendrá la ejecución del programa? ¿Hay alguna forma de obtener el Arduino para decirme cuál es el error?

El chico con el sombrero
fuente

Respuestas:

21

Primero, veamos algunos ejemplos de lo que puede salir mal.

Variables locales no inicializadas

void setup() {
  int status;
  pinMode(13, OUTPUT);
  digitalWrite(13, status);
} 

Como señaló Edgar Bonet en los comentarios, el statuscompilador de C ++ no inicializa implícitamente las variables locales como en el código anterior. Entonces, el resultado del código anterior es indeterminado. Para evitar eso, asegúrese de asignar siempre valores a sus variables locales.

Las cosas son un poco diferentes con las variables globales y estáticas:

El estándar C garantiza que las variables globales y estáticas se inicializarán a 0.

Fuente: Manual de referencia de AVR Libc - Preguntas frecuentes - ¿No debería inicializar todas mis variables?

Eso significa que no debe preocuparse por inicializarlos a 0 en su código. De hecho, realmente debería evitarlo, ya que la inicialización puede desperdiciar memoria. Solo inicialícelos a valores distintos de 0.

Desbordamiento de memoria

int array[10];
int v = array[100];
array[-100] = 10;

El primer problema aquí es que no sabes qué se asignará a v, pero lo peor es que no sabes lo que arruinaste con la asignación a la posición -100 array.

Saltar a una instrucción ilegal

void doSomething( void ) { 
    for (int i = 0; i < 1000; i++); 
}

void setup () 
{
    void (*funcPtr)( void );

    funcPtr = &doSomething;
    funcPtr(); // calls doSomething();

    funcPtr = NULL;
    funcPtr(); // undefined behavior
}

La primera llamada a funcPtr()será realmente una llamada a doSomething(). Las llamadas como la segunda pueden conducir a un comportamiento indefinido.

Otras cosas malas que pueden pasar

Bueno, puedes quedarte sin RAM, por ejemplo. Qué más. En cualquier caso, creo que su programa seguirá ejecutándose, probablemente no de la manera que lo pretendía.

Tipos de protección

En los sistemas informáticos, problemas como estos generalmente se tratan en varios niveles:

  1. Por el compilador
  2. Por el tiempo de ejecución del lenguaje de programación (como en Java, por ejemplo).
  3. Por el sistema operativo o el procesador (si su memoria accede a una posición fuera de los límites del espacio de direcciones reservado para su programa, el sistema operativo o el procesador pueden tener mecanismos de seguridad para evitar eso)

Los arduinos solo tienen una protección limitada del compilador, y probablemente nada más. La buena noticia es que no son multitarea, por lo que el único programa afectado es el suyo. En cualquier caso, cualquiera de esos errores dará lugar a un comportamiento errático.

Las respuestas

Las suposiciones son todos los problemas que mencioné anteriormente son problemas de tiempo de ejecución.

¿Qué sucede si hay un error de tiempo de ejecución en un programa?

El programa continuará y lo que ocurra dependerá de los efectos secundarios del error de tiempo de ejecución. Una llamada al puntero de función nula probablemente hará que el programa salte a una ubicación desconocida.

¿Se detendrá la ejecución del programa?

No, continuará como si nada extraordinario sucediera, probablemente haciendo lo que no tenía la intención de hacer. Se puede restablecer o actuar de forma errática. Puede convertir algunas entradas en salidas y quemar un sensor o dos (pero eso es muy poco probable ).

¿Hay alguna forma de que el Arduino me diga cuál es el error?

No lo creo. Como dije antes, los mecanismos de protección no están ahí. No hay soporte de tiempo de ejecución del idioma, no hay sistema operativo, no hay comprobaciones de hardware para acceso de memoria fuera de los límites (el gestor de arranque tampoco cuenta). Solo debe tener cuidado con su programa y probablemente establecer sus propias redes de seguridad.

La razón de la falta de protección probablemente se deba a que los controladores Arduino son demasiado baratos, tienen muy poca memoria y no deben ejecutar nada demasiado importante (sí, AVR parece haber un descargo de responsabilidad en algún lugar para que no use las MCU que normalmente usa Arduino en sistemas de soporte vital).

Ricardo
fuente
1
¡Excelente! La mejor respuesta que he visto en Arduino. ¡Hasta ahora!
The Guy with The Hat
1
¡¡Gracias!! Creo que deberíamos esforzarnos por dar grandes respuestas tanto como sea posible. Pero me preocupa un poco el hecho de que no tenemos tantos EXPERTOS REAL EE que puedan mirar respuestas como la mía y encontrar errores evidentes. En realidad, esa es la razón por la que publiqué la respuesta, aunque no sé mucho acerca de las MCU AVR. Eso es para ver si conseguimos que alguien lo corrija. Seguro que no queremos personas inteligentes como yo que digan cosas que no están bien y que se salgan con la suya. Pero esa es probablemente una discusión para el sitio Meta.
Ricardo
55
@Ricardo: un comentario que haría es que las variables inicializadas no explícitamente no están necesariamente sin inicializar. Las variables definidas fuera de las funciones generalmente tienen lo que se denomina "duración de almacenamiento automático", que luego se inicializa por defecto a cero. Consulte en.cppreference.com/w/cpp/language/default_initialization para obtener más información. El comportamiento de inicialización es lo suficientemente complejo como para que sea peligroso confiar en él, pero hacer declaraciones generales probablemente no sea una gran idea.
Connor Wolf
1
Además, la SRAM se inicializa a 0 en el reinicio o inicio, por lo que puede hacer algunas suposiciones informadas sobre las variables no inicializadas, si desea vivir peligrosamente. No debe confiar en este comportamiento, pero es interesante.
Connor Wolf
1
Hay un ejemplo interesante de lo que sucede cuando te quedas sin SRAM aquí: electronics.stackexchange.com/questions/42049/… . Básicamente, la pila aprieta parte del montón, o viceversa. Esto puede hacer cosas interesantes como corromper alguna parte del marco de la pila (retornos de funciones de ruptura, etc.) o escribir datos no válidos en variables.
Connor Wolf
9

No hay excepciones de tiempo de ejecución. Solo hay un comportamiento indefinido.

Realmente, no hay excepciones en absoluto . Si intenta realizar una operación no válida, sus resultados serán desconocidos.

No hay comprobación de tiempo de ejecución, excepto lo que implemente. Su programa se ejecuta en hardware de metal desnudo. Es el equivalente de escritorio de correr en ring-0 todo el tiempo, porque el ATmega no tiene anillos .

Connor Wolf
fuente
6

Hay un mecanismo que puede obtener MCU desde un estado errático y es el temporizador de vigilancia . Si está implementando algún código que se ejecutará repetidamente en un bucle, que no se ejecutará en ningún momento más de un tiempo fijo, puede establecer este tiempo como período de vigilancia y habilitar el temporizador.

Luego, debe restablecer repetidamente el temporizador en el bucle. Si su código se congela en algún bucle de condición que nunca terminará, entonces el perro guardián contará hasta cero y eventualmente reiniciará la MCU.

De esta forma está perdiendo datos, pero si ejecuta el AVR WDT en modo de interrupción, puede almacenar algunos datos antes de restablecer la MCU.

Por lo tanto, el temporizador de vigilancia puede proteger su código de bucles interminables no deseados ocasionales.

Documentation: AVR132: Uso del temporizador de vigilancia mejorado

nio
fuente
5

Necesitaría un depurador de hardware para algo como esto. Pero, por lo general, verá que el programa no se comporta como espera y tendrá que mirar esa sección del código para identificar el problema.

Una forma común / rápida / fácil de hacer esto es agregar declaraciones de impresión para imprimir los valores de las variables o simplemente cualquier cosa para que sepa que el programa llega a ese punto en el código sin ningún problema. Esto lo ayudará a aislar aún más el problema.

Creo que VisualMicro tiene alguna funcionalidad de depuración incorporada.

Sachleen
fuente
3

Supongo que la CPU AVR no tiene ninguna herramienta de detección o recuperación de errores. Puede detenerse o seguir ignorando el error y las consecuencias. Como dijo sachleen, debe agregar algunas declaraciones de depuración en su programa que impriman datos en el medio de una operación, para probar si está funcionando. Si usa un emulador y establece puntos de interrupción, podría encontrar fácilmente un problema.

TheDoctor
fuente
-2

Arduino se reiniciará (es decir, se reiniciará setup()y loop()).

usuario28739
fuente
1
No necesariamente. Un error en tiempo de ejecución puede hacer que el programa entre en un bucle sin reiniciar.
Nick Gammon