Pro: Profils

Idéalement, nous suivrions toutes les directives.
Cela permettrait d’obtenir le code le plus propre, le plus régulier, le moins sujet aux erreurs et souvent le plus rapide.
Malheureusement, cela est généralement impossible, car nous devons adapter notre code à de grandes bases de code existantes et utiliser des bibliothèques déjà en place.
Souvent, ce code a été écrit pendant des décennies et ne suit pas ces directives.
Nous devons viser une adoption progressive.

Quelle que soit la stratégie d’adoption progressive que nous choisissons, nous devons pouvoir appliquer des ensembles de directives connexes afin de résoudre d’abord un groupe de problèmes et de laisser le reste pour plus tard.
Une idée similaire d’« directives liées » devient importante lorsqu’une partie, mais pas toutes, les directives sont jugées pertinentes pour une base de code ou lorsqu’un ensemble de directives spécialisées doit être appliqué à un domaine d’application particulier.
Nous appelons cet ensemble de directives liées un « profil ».
Nous visons à ce que cet ensemble de directives soit cohérent afin qu’il nous aide à atteindre un objectif précis, tel que « absence d’erreurs de débordement » ou « sécurité statique du type ».
Chaque profil est conçu pour éliminer une catégorie d’erreurs.
L’application de règles « aléatoires » isolément est plus susceptible de perturber une base de code que d’apporter une amélioration tangible.

Un « profil » est un ensemble déterministe et applicables de façon portable d’un sous‑ensemble de règles (c’est‑à‑dire de restrictions) conçues pour obtenir une garantie spécifique.
« Déterministe » signifie qu’elles ne nécessitent qu’une analyse locale et pourraient être implémentées dans un compilateur (sans que cela soit obligatoire).
« Portable » signifie qu’elles se comportent comme des règles du langage, de sorte que les programmeurs peuvent s’attendre à ce que différents outils d’application donnent la même réponse pour le même code.

Le code écrit pour être exempt d’avertissements en utilisant un tel profil de langage est considéré comme conforme au profil.
Un code conforme est considéré comme sûr par construction par rapport aux propriétés de sécurité ciblées par ce profil.
Le code conforme ne sera pas la cause principale d’erreurs pour cette propriété, bien que de telles erreurs puissent être introduites dans un programme par d’autres codes, bibliothèques ou par l’environnement externe.
Un profil peut également introduire des types de bibliothèque supplémentaires afin de faciliter la conformité et d’encourager un code correct.

Résumé des profils :

À l’avenir, nous prévoyons de définir de nombreux autres profils et d’ajouter davantage de vérifications aux profils existants.
Les candidats comprennent :

L’activation d’un profil est définie par l’implémentation ; généralement, elle se fait dans l’outil d’analyse utilisé.

Pour supprimer l’application d’une vérification de profil, placez une annotation suppress sur un contrat de langage. Par exemple :

[[suppress("bounds")]] char* raw_find(char* p, int n, char x)    // find x in p[0]..p[n - 1]
{
    // ...
}

Maintenant, raw_find() peut bousculer la mémoire à sa guise.
Évidemment, la suppression devrait être très rare.

Pro.safety: Profil de sécurité de type

Ce profil facilite la construction de code qui utilise les types correctement et évite les conversions de type involontaires.
Il le fait en ciblant les sources principales de violations de type, notamment les usages dangereux de casts et les unions.

Aux fins de cette section, la sécurité de type est définie comme la propriété selon laquelle une variable n’est pas utilisée d’une manière qui ne respecte pas les règles du type de sa définition.
Une mémoire accédée comme un type T ne doit pas être une mémoire valide contenant réellement un objet d’un type sans rapport U.
Notez que la sécurité est censée être complète lorsqu’elle est combinée avec la sécurité des limites et la sécurité de la durée de vie.

Une implémentation de ce profil doit reconnaître les modèles suivants dans le code source comme non conformes et émettre un diagnostic.

Résumé du profil de sécurité de type :

Impact

Avec le profil de sécurité de type, vous pouvez faire confiance au fait que chaque opération s’applique à un objet valide.
Une exception peut être levée pour indiquer des erreurs qui ne peuvent pas être détectées statiquement (à la compilation).
Notez que cette sécurité de type ne peut être complète que si nous disposons également de la sécurité des limites et de la sécurité de la durée de vie.
Sans ces garanties, une région de mémoire pourrait être accédée sans tenir compte de quel objet, quels objets ou quelles parties d’objets y sont stockés.

Pro.bounds: Profil de sécurité des limites

Ce profil facilite la construction de code qui opère à l’intérieur des limites des blocs de mémoire alloués.
Il le fait en ciblant les sources principales de violations de limites : l’arithmétique de pointeurs et l’indexation de tableaux.
L’une des caractéristiques essentielles de ce profil est de restreindre les pointeurs afin qu’ils ne référencent que des objets uniques, pas des tableaux.

Nous définissons la sécurité des limites comme la propriété selon laquelle un programme n’utilise pas un objet pour accéder à de la mémoire hors de la plage qui a été allouée pour cet objet.
La sécurité des limites est censée être complète lorsqu’elle est combinée à la sécurité de type et à la sécurité de la durée de vie, qui couvrent d’autres opérations dangereuses pouvant engendrer des violations de limites.

Résumé du profil de sécurité des limites :

Impact

La sécurité des limites implique que l’accès à un objet — notamment les tableaux — ne dépasse pas la zone mémoire allouée à cet objet.
Cela élimine une large classe d’erreurs insidieuses et difficiles à repérer, notamment les fameuses « débordements de tampon ».
Cela comble des failles de sécurité ainsi qu’une source importante de corruption mémoire (lors d’écritures hors limites).
Même si un accès hors limites n’est « qu’une lecture », il peut entraîner des violations d’invariants (lorsque l’accès n’est pas du type supposé) et des « valeurs mystérieuses ».

Pro.lifetime: Profil de sécurité de la durée de vie

L’accès via un pointeur qui ne pointe sur rien est une source majeure d’erreurs, et très difficile à éviter dans de nombreux styles de programmation C ou C++ traditionnels.
Par exemple, un pointeur peut être non initialisé, être nullptr, pointer au‑delà d’un tableau, ou vers un objet supprimé.

Voir la spécification de conception actuelle ici.

Résumé du profil de sécurité de la durée de vie :

Impact

Une fois appliqué complètement grâce à une combinaison de règles de style, d’analyse statique et de support bibliothécaire, ce profil :