Microsoft publie un document décrivant les progrès réalisés dans le cadre du projet Checked C
Visant à rendre le développement sous C plus sûr

Le , par Christian Olivier, Chroniqueur Actualités
Une bonne partie de l’environnement logiciel existant (navigateurs, bases de données, interprètes de langage de programmation ou systèmes d’exploitation pour ne citer que ceux-là) repose toujours sur le C, un langage de programmation qui a fait son apparition dans les années 70 et qui est à la base de nombreux autres langages tels que le C++ et le C #.

En 2016, Microsoft a lancé une initiative qui, à terme, devait permettre de rendre le développement sous C plus fiable et plus sûr. Baptisé Checked C, cette initiative visait l’introduction d’une nouvelle extension du langage C qui serait rétro compatible et intègrerait des outils de vérifications et des garde-fous afin de limiter la survenue d’erreurs durant les phases de développement et l’apparition ultérieure de bogues et/ou de vulnérabilités au sein des logiciels codés en C.

Microsoft a récemment publié un document décrivant les progrès réalisés par ses équipes dans le cadre de son projet visant à rendre le développement sous C plus fiable et plus sûr. Il sera présenté lors de la conférence sur le développent et la cybersécurité de l’IEEE (IEEE SecDev) qui sera organisé du 30 septembre au 2 octobre 2018 à Cambridge, aux États-Unis.

Ce document confirme que Checked C permettra aux développeurs d’ajouter un contrôle statique et dynamique à leurs programmes pour les aider à déceler plus rapidement ou à éviter les erreurs de programmation courantes telles que le « buffer overflow » (les dépassements de mémoire tampon) ou les erreurs de conversion de type d’objets.

Il révèle ainsi qu’afin de garantir un meilleur contrôle sur les pointeurs, Checked C utilise une forme de pointeur vérifié, dont les accès peuvent être vérifiés statiquement ou dynamiquement. Checked C a été conçu comme une extension du compilateur Clang/LLVM et devrait introduire les notions de « checked region » et « bounds-safe interfaces ». Signalons au passage que les programmes codés en C pourront être convertis vers Checked C de manière progressive, fonction par fonction, grâce à la conversion incrémentielle.

Checked C proposera aussi des outils permettant de procéder à des vérifications durant l’écriture du code source, avant que celui-ci ne soit compilé et exécuté.

Source : Checked C (PDF)

Et vous ?

Qu’en pensez-vous ?


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse Signaler un problème

Avatar de pboulanger pboulanger - Membre actif https://www.developpez.com
le 10/09/2018 à 14:54
Une bonne façon de résoudre une grande partie des problèmes serait de:
- ajouter un typage "array of" comme il y avait en pascal pour retirer l'ambiguïté entre pointeur sur un élément et pointeur sur tableau
- rajouter les références pour diminuer les pointeurs nuls
- retirer tous les 'cast' implicites
Avatar de sergio_is_back sergio_is_back - Membre expérimenté https://www.developpez.com
le 10/09/2018 à 16:11
Citation Envoyé par pboulanger Voir le message
Une bonne façon de résoudre une grande partie des problèmes serait de:
- ajouter un typage "array of" comme il y avait en pascal pour retirer l'ambiguïté entre pointeur sur un élément et pointeur sur tableau
- rajouter les références pour diminuer les pointeurs nuls
- retirer tous les 'cast' implicites
En gros rapprocher le C du Pascal... Typage fort, Pointeurs typés, etc...
Avatar de transgohan transgohan - Expert éminent https://www.developpez.com
le 10/09/2018 à 17:00
J'en pense que ce n'est pas forcément utile.
On trouve tout le confort nécessaire avec des outils d'analyse statique ou dynamique.
Un coup de Valgrind et de Sonar suffit par exemple à détecter toutes les erreurs citées par Uther.
Dans une chaîne de développement je ne vois pas pourquoi on aurait l'absence de ce genre d'outil (ce serait comme dire qu'on n'utilise pas de gestion de conf), du coup pourquoi vouloir combler un trou qui est déjà comblé ?
Avatar de AoCannaille AoCannaille - Membre émérite https://www.developpez.com
le 10/09/2018 à 18:07
Citation Envoyé par transgohan Voir le message
Un coup de Valgrind et de Sonar suffit par exemple à détecter toutes les erreurs citées par Uther.
Dans une chaîne de développement je ne vois pas pourquoi on aurait l'absence de ce genre d'outil (ce serait comme dire qu'on n'utilise pas de gestion de conf), du coup pourquoi vouloir combler un trou qui est déjà comblé ?
Bien que je sois d'accord avec la necessité de ces outils, le fait est qu'ils restent des rustines correctives nécessaires pour éviter des erreurs dues, selons les points de vues, soit à des défauts du langages, soit à l'incompétence du développeur.

Selon moi la performance du C vient en partie grâce à ces défauts et utiliser ces outils est selon moi la bonne solution.

Il n’empêche qu'ils ne corrigent pas les problèmes cités.

Pour moi si vous voulez éviter ce genre de problème à la compilation, il ne faut pas choisir le C, mais plus l'ADA par exemple...
Avatar de transgohan transgohan - Expert éminent https://www.developpez.com
le 10/09/2018 à 18:53
Citation Envoyé par AoCannaille Voir le message
Pour moi si vous voulez éviter ce genre de problème à la compilation, il ne faut pas choisir le C, mais plus l'ADA par exemple...
Pour moi l'intérêt n'est pas d'éviter ce genre de problème à la compilation mais à la livraison.
Après toutes les méthodes sont bonnes avec certaines plus coûteuses que d'autres.
Mais introduire un nouveau langage ne supprimera pas les outils que j'ai cité, donc c'est redondant pour moi.
Avatar de Pyramidev Pyramidev - Membre expert https://www.developpez.com
le 10/09/2018 à 20:14
Aujourd'hui, les intérêts du langage C sont qu'il est performant, interopérable, portable et stable. Si le langage C n'évolue quasiment pas, c'est pour rester portable et stable.

Si on veut un langage rétrocompatible avec le C, performant et qui évolue, ce langage existe déjà : c'est le C++.
À quelques rares incompatibilités près (par exemple, en C, void* est implicitement convertible en tout type de pointeur), du code écrit en C compile en C++. Donc il n'y a pas beaucoup d'efforts à fournir pour que du code C compile à la fois en C et en C++.
Il existe bien quelques rares fonctionnalités du C qui n'existent pas en C++ officiel, par exemple le mot-clef restrict de C99. Mais, si on utilise un compilateur comme GCC, on peut choisir d'écrire dans un C++ étendu avec les quelques fonctionnalités spécifiques au C.
Toujours avec GCC, on peut supprimer l'overhead ajouté par le C++, par exemple avec des options comme -fno-exceptions (pour désactiver la gestion des exceptions).
Une fois qu'on a un code qui compile à la fois en C et en C++, on peut migrer progressivement vers le C++.

Sur la page Extension overview du Wiki sur le Checked C, j'ai regardé rapidement les liens donnés par la section More information et je ne vois pas de vrai intérêt du Checked C par rapport au C++ : parmi ce que j'ai lu, toutes les fonctionnalités présentées en Checked C peuvent être implémentées sous la forme d'une simple bibliothèque C++ grâce aux templates et à la surchage d'opérateurs.

Donc j'ai l'impression que le seul intérêt du Checked C est de ne pas avoir à apprendre le C++.

À part ça, si on veut faire de la programmation bas niveau avec de bons contrôles à la compilation, il faut se tourner vers Rust. Mais du code écrit en C ne compilera pas en Rust. Il faudra alors interfacer du Rust et du C.

Citation Envoyé par AoCannaille Voir le message
Selon moi la performance du C vient en partie grâce à ces défauts et utiliser ces outils est selon moi la bonne solution.
Je t'invite à jeter un œil au langage Rust. Tu constateras que la majorité des défauts du C viennent plus d'un problème de conception que d'un besoin de performance.
Pour être honnête, il y a bien des cas en Rust où il faut choisir entre la performance et la robustesse. Mais il y a beaucoup de cas où on peut bénéficier des deux à la fois.
Avatar de archqt archqt - Membre actif https://www.developpez.com
le 10/09/2018 à 22:12
Y a t il une option de compilation, comme il y avait en Turbo Pascal (eh oui ça date ) qui permette de forcer lors de l'accès à un tableau si l'indice est bien dans le tableau ? de base, si ma mémoire est bonne, le pascal faisait une vérification que l'on pouvait ensuite supprimer via une option.
Mais en C je n'ai pas trouvé cela.

Après c'est sûr qu'il faudrait peut être passer tout simplement en C++
Avatar de Pyramidev Pyramidev - Membre expert https://www.developpez.com
le 10/09/2018 à 23:12
Citation Envoyé par archqt Voir le message
Y a t il une option de compilation, comme il y avait en Turbo Pascal (eh oui ça date ) qui permette de forcer lors de l'accès à un tableau si l'indice est bien dans le tableau ?
En C, avec GCC tout seul, je ne pense pas.
Par contre, si on travaille avec des fonctions personnalisées, on peut faire de la compilation conditionnelle pour décider si les contrôles de ces fonctions sont actifs.

En complément de mon message précédent, en C++, on peut bricoler ceci :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <cassert>
#include <exception> // std::terminate

#if defined(NDEBUG) && defined(CHECK)
# define MY_ASSERT(cond)\
	if(cond)\
		static_cast<void>(0);\
	else\
		std::terminate() // code bourrin pour l'exemple
#elif defined(NDEBUG)
# define MY_ASSERT(cond) static_cast<void>(0)
#else
# define MY_ASSERT(cond) assert(cond)
#endif

template<class T, size_t Size>
class MyArray
{
public:
	T& operator[](size_t index) {
		MY_ASSERT(index < Size);
		return m_values[index];
	}

	T const& operator[](size_t index) const {
		MY_ASSERT(index < Size);
		return m_values[index];
	}

	template<size_t Index>
	T& get() {
		static_assert(Index < Size);
		return m_values[Index];
	}

	template<size_t Index>
	T const& get() const {
		static_assert(Index < Size);
		return m_values[Index];
	}

private:
	T m_values[Size];
};

int main()
{
	MyArray<int, 2> myArray; // tableau de 2 éléments de type int
	myArray.get<0>() = 10; // contrôle l'indice à la compilation : OK
	myArray[1] = 11; // contrôle OK à l'exécution (si les contrôles sont actifs)
//	myArray.get<2>() = 12; // erreur de compilation
	myArray[2] = 12; // signale une erreur à l'exécution (si les contrôles sont actifs)
	return 0;
}
Dans mon exemple, le modèle de fonction get prend en argument de modèle un indice qui doit être connu à la compilation et signale une erreur de compilation si cet indice est en dehors des bornes.
L'opérateur avec des crochets, lui, prend en argument un indice qui peut être inconnu à la compilation. Il effectue un contrôle à l'exécution, ou pas, selon le comportement de la macro MY_ASSERT.
Le comportement de la macro MY_ASSERT dépend si les macros NDEBUG et CHECK sont définies. C'est dans les options de compilation que l'on choisit si on définit NDEBUG et si on définit CHECK.

Remarque 1 : à la place de ma macro illustrative MY_ASSERT, il existe déjà BOOST_ASSERT (de la bibliothèque Boost) qui est meilleure, mais un peu plus compliquée à expliquer.

Remarque 2 : en C++20, MY_ASSERT et BOOST_ASSERT seront obsolètes, car on aura enfin une manière standardisée de faire de la programmation par contrats. Par exemple, les préconditions seront exprimées avec un attribut expects.
Le comportement adopté par le programme en cas de violation de contrat devrait être personnalisable.
Avatar de Uther Uther - Expert éminent https://www.developpez.com
le 13/09/2018 à 7:55
Citation Envoyé par Christian Olivier Voir le message
Qu’en pensez-vous ?
J'ai regardé l'article en lien, visiblement ils ne se sont penché que sur le problème des buffer overflow, ce qui est très très loin d'être suffisant. Au niveau de la sécurité, ça reste a des année lumière de ce que proposent Rust et Ada. Le soucis, c'est que C est un langage conçu sans aucune idée de sécurité, vouloir le sécuriser en restant compatible ressemble pour moi a une mission impossible.
L’intérêt de sécuriser un langage est de fournir des garanties, si les anciens mécanisme pas sûrs sont gardés à l'identique, ils vont juste se retrouver dans la situation de C++.

Citation Envoyé par transgohan Voir le message
Un coup de Valgrind et de Sonar suffit par exemple à détecter toutes les erreurs citées par Uther.
Dans une chaîne de développement je ne vois pas pourquoi on aurait l'absence de ce genre d'outil (ce serait comme dire qu'on n'utilise pas de gestion de conf), du coup pourquoi vouloir combler un trou qui est déjà comblé ?
Les outils d'analyse dynamique sont très utiles mais c'est loin d'être aussi complet que ce que permet l'analyse statique d'un langage qui s'y prête bien comme Rust (Ada aussi, mais je vais plutôt parler de Rust que je connais mieux).
Ces outils se contentent de détecter les cas d'erreurs quand ils se produisent. C'est un grand progrès par rapport a pas d'analyse du tout, mais ils ne peuvent pas garantir que tous les cas d'utilisation ont été couverts.

Citation Envoyé par AoCannaille Voir le message
Selon moi la performance du C vient en partie grâce à ces défauts
C'est pas tout a fait vrai si on regarde du coté de Rust qui arrive a lier performance et sécurité.

Citation Envoyé par transgohan Voir le message
Pour moi l'intérêt n'est pas d'éviter ce genre de problème à la compilation mais à la livraison.
Après toutes les méthodes sont bonnes avec certaines plus coûteuses que d'autres.
Mais introduire un nouveau langage ne supprimera pas les outils que j'ai cité, donc c'est redondant pour moi.
Non toute les méthodes ne sont pas "aussi" bonnes que les autres. Une bonne analyse dynamique n'est pas parfaite et peut laisser passer des cas d'erreur. Avec une bonne analyse statique sur un langage qui s'y prete bien, on peut garantir que certaines erreurs n'arrivent jamais.
Les outils que tu as cité restent utiles en Rust principalement parce qu'il permet de s'interfacer avec du code C et qu'il existe un mécanisme qui permet d'ignorer localement certaines sécurités. Mais le langage de base garantit que les erreurs de sécurité mémoire ne peuvent arriver.
Avatar de transgohan transgohan - Expert éminent https://www.developpez.com
le 13/09/2018 à 8:51
Citation Envoyé par Uther Voir le message
Les outils d'analyse dynamique sont très utiles mais c'est loin d'être aussi complet que ce que permet l'analyse statique d'un langage qui s'y prête bien comme Rust (Ada aussi, mais je vais plutôt parler de Rust que je connais mieux).
Ces outils se contentent de détecter les cas d'erreurs quand ils se produisent. C'est un grand progrès par rapport a pas d'analyse du tout, mais ils ne peuvent pas garantir que tous les cas d'utilisation ont été couverts.
Sonar est un outil d'analyse statique.
Contacter le responsable de la rubrique Accueil