informatique , une variable non initialisée est une variable déclarée mais non initialisée avec une valeur précise et connue avant son utilisation. Elle aura une valeur, mais celle-ci sera imprévisible. De ce fait, il s'agit d'une erreur de programmation et d'une source fréquente de bogues dans les logiciels.
C utilisent l'espace de la pile pour les variables, et l'ensemble des variables allouées à une sous-routine est appelé cadre de pile . Bien que l'ordinateur réserve l'espace nécessaire au cadre de pile, il le fait généralement en ajustant simplement la valeur du pointeur de pile , sans modifier l' état de la mémoire elle-même (généralement par souci d'efficacité). Par conséquent, le contenu de cette mémoire à un instant donné apparaîtra comme valeur initiale des variables occupant ces adresses.Voici un exemple simple en C :
La valeur finale de la variable kest indéfinie. L'affirmation selon laquelle elle doit être égale à 10 suppose qu'elle a été initialisée à zéro, ce qui peut être faux. Notez que dans cet exemple, la variable iest initialisée à zéro par la première clause de l' forinstruction.
Un autre exemple concerne les structures . Dans l'extrait de code ci-dessous, nous avons une struct studentstructure contenant des variables décrivant les informations relatives à un étudiant. La fonction registerStudentprovoque une fuite de mémoire car elle n'initialise pas complètement les membres de cette structure struct Student newStudent. Si l'on examine le code de plus près, on constate qu'au début, les variables `a`, age`b` semesteret studentNumber`c` sont initialisées. Cependant, l'initialisation des membres `a` firstNameet `c` lastNameest incorrecte. En effet, si la longueur des tableaux de caractères `a` firstNameet `c` est inférieure à 16 octets, lors de l'appel à `input` , les 16 octets de mémoire réservés à chacun de ces membres ne sont pas entièrement initialisés. Par conséquent, après l'appel à `input` de la structure résultante , une fuite de mémoire de pile est provoquée au profit de l'appelant.lastNamestrcpymemcpy()output
Dans tous les cas, même lorsqu'une variable est initialisée implicitement à une valeur par défaut comme 0, il ne s'agit généralement pas de la valeur correcte . L'initialisation ne garantit pas la validité de la valeur si celle-ci est une valeur par défaut. (Toutefois, l'initialisation par défaut à NULL (ou ` null` nullptrdepuis C23 ou `undefined` en C++ ) est une bonne pratique pour les pointeurs et les tableaux de pointeurs, car elle les rend invalides avant même leur initialisation à leur valeur correcte.) En C, les variables à durée de vie statique non initialisées explicitement sont initialisées à zéro (ou NULL`undefined` pour les pointeurs).
Non seulement les variables non initialisées sont une cause fréquente de bogues, mais ce type de bogue est particulièrement grave car il peut ne pas être reproductible : par exemple, une variable peut rester non initialisée uniquement dans une partie du programme. Dans certains cas, des programmes comportant des variables non initialisées peuvent même réussir les tests logiciels .
Impacts
Les variables non initialisées constituent une faille de sécurité importante, car elles peuvent être exploitées pour obtenir une fuite de mémoire arbitraire, un écrasement de mémoire arbitraire ou l'exécution de code, selon le cas. Lors de l'exploitation d'un logiciel utilisant l'ASLR ( Address Space Layout Randomization ), il est souvent nécessaire de connaître l' adresse de base du logiciel en mémoire. Exploiter une variable non initialisée de manière à forcer le logiciel à divulguer un pointeur de son espace d'adressage permet de contourner l'ASLR.
Utilisation dans les langues
Les variables non initialisées constituent un problème particulier dans des langages tels que l'assembleur , le C et le C++ , conçus pour la programmation système . Le développement de ces langages reposait sur une philosophie de conception où les conflits entre performance et sécurité étaient généralement résolus au profit de la performance. Il incombait donc au programmeur d'être conscient des risques liés aux variables non initialisées.
Dans d'autres langages, les variables sont souvent initialisées à des valeurs connues lors de leur création. Par exemple :
- En VHDL, toutes les variables standard sont initialisées à la valeur spéciale « U ». Cette propriété est utilisée en simulation et pour le débogage, afin d'indiquer à l'utilisateur que des valeurs initiales indifférentes , via la logique multivaluée , peuvent affecter le résultat.
- En Java, les variables non initialisées ne sont pas autorisées. Les champs des classes et des objets qui ne possèdent pas d'initialiseur explicite, ainsi que les éléments des tableaux, sont automatiquement initialisés avec la valeur par défaut de leur type (
falsepar exempleboolean, `int` pour `int`,0`null` pour tous les types numériques et `int`nullpour tous les types référence). Les variables locales en Java doivent impérativement être initialisées avant d'être utilisées, sous peine de provoquer une erreur de compilation. - Python initialise les variables locales à
NULL(distinct deNone) et lève une exceptionUnboundLocalErrorlorsqu'une telle variable est accédée avant d'être (ré)initialisée à une valeur valide. - D initialise toutes les variables, sauf indication contraire explicite du programmeur.
Même dans les langages autorisant les variables non initialisées, de nombreux compilateurs tentent de détecter leur utilisation et de la signaler comme une erreur de compilation . Certains langages facilitent cette tâche en proposant des constructions permettant de gérer l'initialisation des variables ; par exemple, C# offre une variante des paramètres passés par référence aux sous-programmes (spécifiée par `reference` au lieu de `reference` ), indiquant que la variable peut être non initialisée à son entrée, mais qu'elle sera initialisée par la suite.outref