I Quelques pieges du langage C
I.1 Fautes de frappe fatales
I.1.1 Mélange entre = et ==
I.1.2 Tableaux a plusieurs dimensions
I.1.3 Oubli du break dans les switch
I.1.4 Passage des parametres par adresse
I.2 Problèmes de calcul sur les nombres reels
I.2.1Egalite de reels
I.2.2 Problemes d’arrondis
I.2.3 Absence de d´eclaration des fonctions retournant des doubles .
I.3 Style des declarations de fonctions
I.4 Variables non initialisees
I.5 Ordre d’évaluation indefini
I.6 Allocation dynamique de la memoire
I.6.1 Référence a une zone mémoire non allouée
I.6.2 Référence a une zone mémoire libérée
I.6.3 Liberation d’une zone invalide
I.6.4 Fuites
I.7 Chaines de caract`eres
I.7.1 Débordement d’une chaˆine de caractères
I.7.2 Ecriture dans une chaˆine en mémoire statique .
I.8 Pointeurs et tableaux
I.8.1 Assimilation d’un pointeur et d’un tableau statique
I.8.2 Appel de free() sur un tableau
I.9 Entrées/sorties standard
I.9.1 Controle des paramètres de printf et scanf
I.9.2 Lecture de chaˆines de caractères
I.9.3 Lecture de données binaires
I.10 Gestion des signaux
I.11 Processeurs 64 bits
I.11.1 Absence de déclarations des fonctions
I.11.2 Manipulation de pointeurs
I.12 Pré-processeur
II Un peu d’algorithmique
II.1 Introduction
II.2 Allocation dynamique de la memoire
II.3 Pointeurs
II.4 Listes
II.5 Ensembles
II.6 Tris et recherches
II.7 Chaines de caractères
III Créer des programmes surs
III.1 Quelques rappels sur la sécurité informatique
III.1.1 Vol de mot de passe
III.1.2 Chevaux de Troie
III.1.3 Déni de service
III.2 Comment exploiter les bugs d’un programme
III.3 Règles pour une programmation sure
III.3.1 Eviter les débordements
III.3.2 Débordements arithmétiques
III.3.3 Se méfier des données
III.3.4 Traiter toutes les erreurs
III.3.5 Limiter les fonctionnalités
III.3.6 Se méfier des bibliothèques
III.3.7 Bannir les fonctions dangereuses
III.4 Pour aller plus loin
IV Questions de style
IV.1 Commentaires et documentation
IV.1.1 Commentaires
IV.1.2 Documentation .
IV.2 Typologie des noms
IV.3 Déclarations
IV.4 Indentation
IV.5 Boucles
IV.6 Expressions complexes
IV.7 Conversion de types
IV.8 Assertions Références bibliographiques
Introduction
Ce document a pour but de rappeler certaines règles et techniques que tout le monde connait pour développer une application de taille « sérieuse » en langage C.
Les audits menés sur des gros logiciels libres, en particulier, ceux menés par Theo De Raadt et les autres développeurs du projet OpenBSD montrent que de nombreux programmeurs,meme renommés, ont tendance `a oublier ces règles, ce qui créée des bugs. Certaines de ces erreurs peuvent ouvrir une brèche dans la sécurité du système qui héberge le programme.
Les sources d’informations sur le sujet sont nombreuses et aucune n’a empèché les bugs connus d’exister ; c’est pourquoi je pense que ce document est superflu. En particulier, La Foire Aux Questions (FAQ) du forum Usenet comp.lang.c constitue une source d’information beaucoup plus riche, mais en anglais. Elle est accessible par l’URL : http://www.eskimo.com/~scs/C-faq/top.html
Quelques pieges du langage C
Le but de ce document n’est pas de faire un cours de langage C. Il y a des livres pour ca.
Mais entre les bases du langage et la mise en œuvre concrète de ses fonctionnalités, il y a parfois quelques difficultés.
La plupart des erreurs décrites ici ne sont pas détectées `a la compilation.
Certaines de ces erreurs conduisent systématiquement `a un plantage du programme en cours d’exécution ou `a un résultat faux, alors que d’autres conduisent `a des situations que la norme du langage C définit comme « comportements indéterminés », c’est-`a-dire que n’importe quoi peut se produire, selon les choix de programmation du compilateur ou du système.
Parfois, dans ce cas, le programme en question `a l’air de fonctionner correctement. Une erreur ne se produira que dans certaines conditions, ou bien lorsque l’on tentera de porter le programme en question vers un autre type de machine.
Fautes de frappe fatales
Cette section commence par attirer l’attention du lecteur sur quelques erreurs d’inattention qui peuvent ˆetre commises lors de la saisie d’un programme et qui ne seront pas détectées par la compilation mais produiront nécessairement des erreurs plus ou moins faciles `a détecter `a
l’exécution.
Mélange entre = et ==
Cette erreur est l’une des plus fréquentes, elle provient de la syntaxe du langage combinée `a l’inattention du programmeur. Elle peut ˆetre très difficile `a détecter. C’est pourquoi, il est indispensable d’avoir le problème `a l’esprit en permanence.
= est l’opérateur d’affectation, alors que == est un opérateur de comparaison, mais en maths et dans d’autres languages de programmation on a l’habitude d’écrire x = y pour désigner la comparaison.
Tableaux `a plusieurs dimensions
En C les indices d’un tableau `a plusieurs dimensions s’écrivent avec autant de paires de crochets qu’il y a d’indices. Par exemple pour une matrice `a deux dimensions on écrit :
double mat[4][4];
x = mat[i][j];
Le risque d’erreur provient du fait que la notation mat[i,j] (qui est employée dans d’autres langages) est également une expression valide en langage C.
Oubli du break dans les switch
N’oubliez pas le break `a la fin de chaque case dans une instruction switch. Si le break est absent, l’exécution se poursuit dans le case suivant, ce qui n’est en général pas le comportement voulu. Par exemple :
void
print_chiffre(int i)
{
switch (i) {
case 1:
printf(« un »);
case 2:
printf(« deux »);
case 3:
printf(« trois »);
case 4:
printf(« quatre »);
case 5:
printf(« cinq »);
case 6:
printf(« six »);
case 7:
printf(« sept »);
case 8:
printf(« huit »);
case 9:
printf(« neuf »);
}
}
Dans cette fonction tous les break ont ete oublies. Par consequent, l’appel print_chiffre(7);
affichera :
septhuitneuf
Ce qui n’est peut-etre pas le résultat escompté.
Passage des parametres par adresse
En langage C, les parametrs des fonctions sont toujours passés par valeur : il sont copies localement dans la fonction. Ainsi, une modification d’un paramètre dans la fonction reste localisée a cette fonction, et la variable de l’appelant n’est pas modifiée.
Pour pouvoir modifier une variable de la fonction appelante, il faut réaliser un passage par adresse explicite. Par exemple, une fonction qui permute deux nombres réels aura le prototype : void swapf(float *x, float *y);
Problemes de calcul sur les nombres reels
Avant d’attaquer un programme quelconque utilisant des nombres reels, il est indispensable d’avoir pris conscience des problemes fondamentaux induits par la représentation approchée des nombres réels sur toute machine informatique [2].
Dans de nombreux cas, la prise en compte de ces difficult´es se fait simplement, mais il peut s’avérer nécessaire d’avoir recours a des algorithmes relativement lourds, dans le cas par exemple ou la précision de la représentation des réels par la machine n’est pas suffisante [3].
Egalite de reels
Sauf coup de chance, l’egalite parfaite ne peut etre obtenue dans le monde réel, il faut donc toujours tester l’égalite a pres. Mais il faut faire attention de choisir un qui soit en rapport avec les valeurs `a tester.
……….
Programmation en langage C (392 KO) (Cours PDF)