Que se passe-t-il en cas d'erreur d'exécution?

17

Que se passe-t-il s'il y a une erreur d'exécution dans un programme? L'exécution du programme va-t-elle simplement s'arrêter? Existe-t-il un moyen d'obtenir l'Arduino pour me dire quelle est l'erreur?

Le gars avec le chapeau
la source

Réponses:

21

Voyons d'abord quelques exemples de ce qui peut mal tourner.

Variables locales non initialisées

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

Comme l'a souligné Edgar Bonet dans les commentaires, les variables locales comme statusdans le code ci-dessus ne sont pas implicitement initialisées par le compilateur C ++. Ainsi, le résultat du code ci-dessus est indéterminé. Pour éviter cela, assurez-vous d'attribuer toujours des valeurs à vos variables locales.

Les choses sont un peu différentes avec les variables globales et statiques:

Les variables globales et statiques sont garanties d'être initialisées à 0 par la norme C.

Source: AVR Libc Reference Manual - Foire aux questions - Ne devrais-je pas initialiser toutes mes variables?

Cela signifie que vous ne devriez pas vous soucier de les initialiser à 0 dans votre code. En fait, vous devriez vraiment l'éviter, car l'initialisation peut gaspiller de la mémoire. Les initialiser uniquement à des valeurs autres que 0.

Débordement de mémoire

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

Le premier problème ici est que vous ne savez pas ce qui sera attribué à v, mais pire, vous ne savez pas ce que vous avez gâché avec l'affectation au poste -100 de array.

Aller à une instruction illégale

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
}

Le premier appel à funcPtr()sera en fait un appel à doSomething(). Des appels comme le second peuvent conduire à un comportement indéfini.

D'autres mauvaises choses qui peuvent arriver

Eh bien, vous pouvez manquer de RAM, par exemple. Quoi d'autre. Dans tous les cas, je pense que votre programme continuera de fonctionner, probablement pas comme vous le souhaitiez.

Types de protection

Dans les systèmes informatiques, de tels problèmes sont généralement traités à différents niveaux:

  1. Par le compilateur
  2. Par le runtime du langage de programmation (comme en Java par exemple).
  3. Par le système d'exploitation ou le processeur (si votre mémoire accède à une position en dehors des limites de l'espace d'adressage réservé à votre programme, le système d'exploitation ou le processeur peut avoir des mécanismes de sécurité pour empêcher cela)

Les Arduinos n'ont qu'une protection limitée du compilateur, et probablement rien d'autre. La bonne nouvelle est qu'ils ne sont pas polyvalents, donc le seul programme affecté est le vôtre. Dans tous les cas, l'un de ces bogues entraînera un comportement erratique.

Les réponses

Les hypothèses sont tous les problèmes que j'ai indiqués ci-dessus sont des problèmes d'exécution.

Que se passe-t-il s'il y a une erreur d'exécution dans un programme?

Le programme continuera et ce qui se passera dépendra des effets secondaires de l'erreur d'exécution. Un appel au pointeur de fonction null fera probablement sauter le programme vers un emplacement inconnu.

L'exécution du programme va-t-elle simplement s'arrêter?

Non, cela continuera comme si rien d'extraordinaire ne s'était produit, faisant probablement ce que vous n'aviez pas l'intention de faire. Il peut se réinitialiser ou agir de manière erratique. Il peut transformer certaines entrées en sorties et graver un ou deux capteurs (mais c'est très peu probable ).

Existe-t-il un moyen d'obtenir l'Arduino pour me dire quelle est l'erreur?

Je ne pense pas. Comme je l'ai dit plus tôt, les mécanismes de protection ne sont pas là. Il n'y a pas de support d'exécution de la langue, pas de système d'exploitation, pas de vérifications matérielles pour l'accès à la mémoire hors des limites (le chargeur de démarrage ne compte pas non plus). Vous devez juste être prudent avec votre programme et probablement définir vos propres filets de sécurité.

La raison du manque de protection est probablement parce que les contrôleurs Arduino sont trop bon marché, ont trop peu de mémoire et ne devraient pas exécuter quelque chose de trop important (oui, il semble y avoir un avertissement par AVR quelque part pour que vous n'utilisiez pas les MCU normalement utilisés par Arduino dans les systèmes de survie).

Ricardo
la source
1
Génial! La meilleure réponse que j'ai vue sur Arduino.SE jusqu'à présent!
The Guy with The Hat
1
Merci!! Je pense que nous devons nous efforcer de donner autant de réponses que possible. Mais cela m'inquiète un peu du fait que nous n'avons pas autant d'experts REAL EE qui pourraient examiner des réponses comme les miennes et trouver des erreurs flagrantes. En fait, c'est la raison pour laquelle j'ai posté la réponse même si je ne sais pas grand-chose sur les microcontrôleurs AVR. C'est pour voir si nous obtenons quelqu'un pour le corriger. Nous ne voulons certainement pas que des pents intelligents comme moi disent des choses qui ne vont pas et s'en sortent. Mais c'est probablement une discussion pour le site Meta.
Ricardo
5
@Ricardo - Un commentaire que je ferais est que les variables initialisées de manière non explicite ne sont pas nécessairement non initialisées. Les variables définies en dehors des fonctions ont généralement ce qu'on appelle la «durée de stockage automatique», qui est ensuite initialisée par défaut à zéro. Voir en.cppreference.com/w/cpp/language/default_initialization pour plus d'informations. Le comportement d'initialisation est suffisamment complexe pour qu'il soit probablement dangereux de s'y fier, mais faire des déclarations générales n'est probablement pas une excellente idée.
Connor Wolf
1
De plus, la SRAM est initialisée à 0 lors de la réinitialisation ou du démarrage, vous pouvez donc faire des suppositions éclairées sur les variables non initialisées, si vous voulez vivre dangereusement. Vous ne devriez pas vous fier à ce comportement, mais c'est intéressant.
Connor Wolf
1
Voici un exemple intéressant de ce qui se passe lorsque vous manquez de SRAM: electronics.stackexchange.com/questions/42049/… . Fondamentalement, la pile encombre une partie du tas, ou vice versa. Cela peut faire des choses intéressantes comme corrompre une partie du cadre de pile (retour des fonctions de rupture, etc.) ou écrire des données invalides dans des variables.
Connor Wolf
9

Il n'y a aucune exception d'exécution. Il n'y a qu'un comportement indéfini.

Vraiment, il n'y a aucune exception à tous . Si vous essayez d'effectuer une opération non valide, ses résultats seront inconnus.

Il n'y a aucune vérification d'exécution, sauf ce que vous implémentez. Votre programme fonctionne sur du matériel nu. C'est l'équivalent du bureau de fonctionner en ring-0 tout le temps, car l'ATmega n'a pas de ring .

Connor Wolf
la source
6

Il existe un mécanisme qui peut obtenir le MCU d'un état erratique et c'est le temporisateur de surveillance . Si vous implémentez un code qui s'exécutera à plusieurs reprises dans une boucle, qui ne s'exécutera pas plus longtemps qu'une heure fixe, vous pouvez définir cette heure comme période de surveillance et activer le minuteur.

Ensuite, vous devez réinitialiser à plusieurs reprises le minuteur dans la boucle. Si votre code se bloque à une boucle de condition qui ne se terminera jamais, le chien de garde comptera jusqu'à zéro et réinitialisera éventuellement le MCU.

De cette façon, vous perdez des données, mais si vous exécutez l'AVR WDT en mode interruption, vous pouvez stocker certaines données avant de réinitialiser le MCU.

Ainsi, la minuterie de surveillance peut protéger votre code contre les boucles sans fin occasionnelles et involontaires.

Documentation: AVR132: Utilisation de la minuterie de surveillance améliorée

nio
la source
5

Vous auriez besoin d'un débogueur matériel pour quelque chose comme ça. Mais généralement, vous verrez que le programme ne se comporte pas comme vous vous y attendez et devrez regarder cette section du code pour identifier le problème.

Une façon courante / rapide / facile de le faire consiste à ajouter des instructions print pour imprimer les valeurs des variables ou tout simplement pour que vous sachiez que le programme arrive à ce point dans le code sans problème. Cela vous aidera à isoler davantage le problème.

Je crois que VisualMicro a une fonctionnalité de débogage intégrée.

sachleen
la source
3

Je suppose que le processeur AVR n'a pas d'outils de détection ou de récupération d'erreur. Il peut simplement s'arrêter ou continuer à ignorer l'erreur et les conséquences. Comme l'a dit Sachleen, vous devez ajouter des instructions de débogage dans votre programme qui impriment des données au milieu d'une opération, pour tester si cela fonctionne. Si vous utilisez un émulateur ou définissez des points d'arrêt, vous pouvez facilement trouver un problème.

Le docteur
la source
-2

L'Arduino redémarrera (c'est-à-dire qu'il redémarrera setup()et loop()).

user28739
la source
1
Pas nécessairement. Une erreur d'exécution peut faire entrer le programme dans une boucle sans redémarrer.
Nick Gammon