TP-1 — Séance 0 — Mise en place de l’environnement
Docker, conteneur du cours, éditeur, gcc, gdb, valgrind, AddressSanitizer, make
Installer l’environnement de travail de tout le cours et vérifier chacun de ses outils : Docker, l’image du cours, le conteneur lancé sur le dossier de travail, l’édition d’un fichier, la compilation avec les options du cours, gdb, valgrind, AddressSanitizer et make. Le TP compte sept étapes (2 à 3 heures). Le dossier TP_S00_code_depart/ fournit verifie_env.sh (contrôle de l’environnement), adresse.c, test_env.c, un Makefile à compléter et, pour VS Code, .devcontainer/devcontainer.json ; hello.c et calcul.c s’écrivent pendant le TP. Les questions demandent d’observer une sortie, de l’expliquer, puis de modifier un fichier ; les réponses se notent dans reponses.txt, avec les sorties copiées. Machine : processeur 64 bits (Intel, AMD ou Apple), virtualisation activée, 4 Gio de mémoire au moins (8 Gio sous Windows, valeur demandée par Docker Desktop), quelques Gio libres sur le disque (l’image occupe environ 1,1 Gio).
Décompresser TP_S00_code_depart.zip, se placer dans le dossier TP_S00_code_depart/ qu’il crée, puis lancer le conteneur depuis ce dossier :
docker run -it --rm --security-opt seccomp=unconfined \
-v "$(pwd)":/workspace elbachirtoure/c-advanced-course:v2.0 # lancer le conteneurWindows, PowerShell : -v "${PWD}:/workspace" à la place de -v "$(pwd)":/workspace ; Git Bash et autres cas : étape 2 ci-dessous. Dans le conteneur, ce dossier est /workspace :
gcc -std=c17 -Wall -Wextra -O0 -g prog.c -o prog # options du cours
gdb ./prog # break, run, next, print, continue, quit
valgrind --leak-check=full ./prog # erreurs memoire et fuites
gcc -std=c17 -Wall -Wextra -O0 -g -fsanitize=address prog.c -o prog_asan
setarch -R ./prog # sans alea des adresses
make ; make clean # compilation automatiseeÉtape 1 : installer Docker
Docker exécute des conteneurs : des systèmes Linux isolés, construits à partir d’une image. Sous Windows et macOS, Docker Desktop fait tourner ces conteneurs dans une machine virtuelle Linux légère ; sous Linux, Docker Engine les exécute directement. Les versions et les menus évoluent : en cas de doute, la référence est la page d’installation de docs.docker.com.
Windows
Système : Windows 11, 64 bits, version 23H2 (build 22631) ou plus récente (Windows 10 n’est plus maintenu par Microsoft) ; WSL en version 2.1.5 ou plus récente ; virtualisation matérielle activée dans le BIOS ou l’UEFI (VT-x chez Intel, AMD-V chez AMD).
Ouvrir PowerShell en administrateur, installer WSL 2, puis redémarrer :
wsl --installSi WSL est déjà installé :
wsl --update, puiswsl --set-default-version 2.Télécharger
Docker Desktop Installer.exedepuis docs.docker.com (Docker Desktop pour Windows), l’exécuter, et laisser cochée l’option Use WSL 2 instead of Hyper-V.Lancer Docker Desktop depuis le menu Démarrer (il ne démarre pas seul après l’installation) et accepter les conditions d’utilisation.
macOS
Docker Desktop accepte la version courante de macOS et les deux précédentes, avec 4 Gio de mémoire au moins.
- Télécharger
Docker.dmgdepuis docs.docker.com, dans la version qui correspond au processeur : Apple silicon (puces M1, M2, M3…) ou Intel (menu Pomme, À propos de ce Mac). - Sur un Mac à puce Apple, installer Rosetta 2, recommandé par Docker :
softwareupdate --install-rosetta. - Ouvrir
Docker.dmg, glisser Docker dans Applications, lancerDocker.appet accepter les conditions d’utilisation.
Linux (Ubuntu 22.04, 24.04 ou 26.04)
# 1. retirer les paquets non officiels qui entreraient en conflit
sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)
# 2. ajouter le depot de Docker
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
# 3. installer Docker Engine
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 4. utiliser docker sans sudo (prend effet a la prochaine connexion, ou tout de suite avec newgrp)
sudo usermod -aG docker $USER
newgrp dockerSous Debian, remplacer ubuntu par debian dans les deux adresses et ${UBUNTU_CODENAME:-$VERSION_CODENAME} par $VERSION_CODENAME. Pour les autres distributions (Fedora, Arch…), suivre la page d’installation de Docker Engine.
Vérification (les trois systèmes)
docker --version
docker run hello-world- Observer. Quelle version de Docker est installée ? Le message de
hello-worldcommence par « Hello from Docker! » : quelles étapes y sont décrites, et quelles lignes précèdent ce message lors de la première exécution ? - Expliquer. Pourquoi Docker a-t-il besoin de WSL 2 sous Windows, ou d’une machine virtuelle sous macOS, pour exécuter un conteneur Linux ?
Étape 2 : récupérer l’image et lancer le conteneur
docker pull elbachirtoure/c-advanced-course:v2.0
docker imagesCréer sur l’hôte un dossier de travail (par exemple tp_c), y décompresser TP_S00_code_depart.zip, qui crée tp_c/TP_S00_code_depart/, se placer dans ce dossier (cd tp_c/TP_S00_code_depart), puis lancer le conteneur depuis ce dossier :
| terminal | commande |
|---|---|
| Linux, macOS, WSL | docker run -it --rm --security-opt seccomp=unconfined -v "$(pwd)":/workspace elbachirtoure/c-advanced-course:v2.0 |
| Windows, PowerShell | docker run -it --rm --security-opt seccomp=unconfined -v "${PWD}:/workspace" elbachirtoure/c-advanced-course:v2.0 |
| Windows, Git Bash | docker run -it --rm --security-opt seccomp=unconfined -v "/${PWD}":/workspace elbachirtoure/c-advanced-course:v2.0 |
-it ouvre un terminal interactif ; --rm supprime le conteneur quand son shell se termine ; -v monte le dossier courant de l’hôte sous /workspace ; --security-opt seccomp=unconfined autorise la désactivation de l’aléa des adresses (setarch -R, gdb), dont les séances suivantes ont besoin. Les guillemets protègent un chemin qui contient des espaces. Sous Windows, PowerShell (ou le Terminal Windows) convient ; dans un terminal Ubuntu de WSL, la commande Linux convient. Sous Git Bash, la barre oblique placée devant ${PWD} empêche la conversion automatique des chemins (sans elle, /workspace reste vide) ; si le message « the input device is not a TTY » apparaît, préfixer la commande par winpty.
Dans le conteneur :
pwd
ls
./verifie_env.sh
help-tp- Observer. Dans quel dossier le shell démarre-t-il ? Quels fichiers voit
ls? Que ditverifie_env.sh: versions de gcc, gdb, valgrind et make, norme par défaut de gcc,setarch -R,-fsanitize=address? - Observer. Dans le conteneur, écrire
echo essai > /workspace/essai.txtetecho essai > /root/essai.txt. Le premier fichier est-il visible sur l’hôte ? Quitter (exit), relancer le conteneur, et chercher les deux fichiers. Expliquer ce qui reste et ce qui disparaît. - Expliquer. Relancer le conteneur sans
--security-opt seccomp=unconfinedet exécuter./verifie_env.sh. Quelle ligne change ? - Observer (Linux). Sur l’hôte,
ls -l essai.txt: à qui appartient le fichier créé depuis le conteneur, et quelle conséquence pour le modifier ou le supprimer sur l’hôte ?
Étape 3 : éditer un fichier
L’éditeur de référence du cours est Vim : il est présent dans le conteneur et sur tout système Unix, y compris un serveur sans interface graphique. Vim a des modes : le mode NORMAL (commandes), dans lequel il s’ouvre, et le mode INSERT (saisie), qu’ouvre la touche i ; Échap revient toujours au mode NORMAL. Le dossier étant monté, les fichiers peuvent aussi être édités sur l’hôte (VS Code, par exemple) puis compilés dans le conteneur ; avec l’extension Dev Containers, VS Code ouvert sur le dossier TP_S00_code_depart y trouve .devcontainer/devcontainer.json et propose de s’ouvrir directement dans le conteneur (Reopen in Container).
3.1 Premiers pas
vim hello.c, puis i, saisir le programme ci-dessous, Échap, puis :wq et Entrée (enregistrer et quitter) ; vérifier avec cat hello.c.
#include <stdio.h>
int main(void)
{
printf("Hello World\n");
return 0;
}3.3 Recherche et remplacement
Créer calcul.c :
#include <stdio.h>
int main(void)
{
int x = 10;
int y = 10;
int z = x + y;
printf("Result: %d\n", z);
return 0;
}Rouvrir le fichier : /int puis Entrée cherche « int », n et N passent à l’occurrence suivante ou précédente ; :%s/10/20/g remplace tous les 10 par 20. Enregistrer.
i, a, o, O |
insérer avant, après, ligne dessous, dessus | /motif, ?motif |
chercher vers le bas, vers le haut |
|---|---|---|---|
Échap |
retour au mode NORMAL | n, N |
occurrence suivante, précédente |
h j k l, w, b |
gauche, bas, haut, droite ; mot suivant, précédent | :s/a/b/, :%s/a/b/g |
remplacer sur la ligne, dans le fichier |
gg, G, :42 |
début, fin, ligne 42 | :w, :q, :wq |
enregistrer, quitter, les deux |
x, dd, dw |
supprimer caractère, ligne, mot | :q! |
quitter sans enregistrer |
yy, p, P |
copier la ligne, coller après, avant | >>, <<, gg=G |
indenter, désindenter, tout réindenter |
u, Ctrl+r |
annuler, refaire | % |
accolade ou parenthèse correspondante |
En cas de blocage : Échap plusieurs fois, puis :q!. Le tutoriel vimtutor (25 à 30 minutes) reprend ces commandes.
- Observer. Copier dans
reponses.txtle contenu final dehello.c(deuxprintf) et celui decalcul.c. - Observer. Vim n’affiche rien après
:%s/10/20/g: il n’annonce un changement qu’au-delà de deux lignes modifiées (optionreport). Annuler (u), taper:set report=0, refaire le remplacement : que dit Vim ?
Étape 4 : compiler et exécuter
gcc -std=c17 -Wall -Wextra -O0 -g hello.c -o hello
./hello
echo $?
gcc -std=c17 -Wall -Wextra -O0 -g calcul.c -o calcul && ./calcul
gcc hello.c
ls- Observer. Que contient la sortie de
helloet decalcul? Que vaut$?après./hello? Quel fichiergcc hello.ca-t-il produit ? - Expliquer. Le rôle de chacune des options
-std=c17,-Wall,-Wextra,-O0,-get-o. - Modifier. Remplacer
return 0;parreturn 3;danshello.c, recompiler, exécuter, et relire$?, puis remettrereturn 0;. Que représente cette valeur ? - Modifier. Ajouter
int inutile;au début demainet recompiler avec les options du cours : quel message apparaît ? Le retirer ensuite.
Étape 5 : gdb, valgrind, adresses
gcc -g hello.c -o hello_debug
gdb ./hello_debug
(gdb) break main
(gdb) run
(gdb) next
(gdb) print "GDB works!"
(gdb) quitDans l’image du cours, gdb affiche à chaque arrêt le tableau de bord de gdb-dashboard (sections Assembly, Registers, Source, Stack, Variables) ; dashboard -enabled off le masque, dashboard -enabled on le rétablit.
valgrind ./hello
gcc -std=c17 -Wall -Wextra -O0 -g adresse.c -o adresse
./adresse
./adresse
setarch -R ./adresse
setarch -R ./adresse/* adresse.c -- adresse d'une variable locale (TP-1, etape 5) */
#include <stdio.h>
int main(void)
{
int x = 2026;
printf("x = %d, adresse de x : %p\n", x, (void *)&x);
return 0;
}- Observer. Sur quelle ligne gdb s’arrête-t-il après
break mainetrun, puis aprèsnext? Qu’afficheprint "GDB works!"? - Observer. Dans le rapport de valgrind, que disent les lignes
HEAP SUMMARY,total heap usageetERROR SUMMARY? D’où vient le bloc alloué, alors quehello.cn’appelle pasmalloc? - Expliquer. Pourquoi l’adresse de
xchange-t-elle d’une exécution à l’autre, et pas soussetarch -R?
Étape 6 : automatiser avec make
# Makefile -- TP-1 : compilation de hello et de test_env avec les options du cours
CC = gcc
CFLAGS = -std=c17 -Wall -Wextra -O0 -g
LDFLAGS =
# Cibles
TARGETS = hello test_env
# Regle par defaut
all: $(TARGETS)
# Compilation de hello
hello: hello.c
$(CC) $(CFLAGS) -o hello hello.c $(LDFLAGS)
# TODO 6.1 : regle pour test_env, sur le modele de hello
# Nettoyage
clean:
rm -f $(TARGETS) *.o
# Recompilation complete
rebuild: clean all
# Cibles qui ne sont pas des fichiers
.PHONY: all clean rebuild- Observer. Avant de compléter le TODO, lancer
make:test_envest compilé quand même. Quelle commande make a-t-il lancée pour lui, et d’où vient-elle ? - Modifier. Compléter le TODO 6.1 par une règle sur le modèle de celle de
hello, puismake cleanetmake. - Observer. Lancer
makeune seconde fois, puistouch hello.cetmake, enfinmake cleanetmake rebuild. Qu’est-ce qui est recompilé à chaque fois, et pourquoi ? - Observer. Remplacer la tabulation de la commande de
hellopar des espaces et relancermake. Quel message apparaît ? Remettre la tabulation.
Étape 7 : valider l’installation
/* test_env.c -- verification de l'environnement du cours (TP-1, etape 7) */
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("=== Test de l'environnement ===\n");
/* Test 1 : compilation */
printf("[OK] Compilation reussie\n");
/* Test 2 : allocation dynamique */
int *ptr = malloc(10 * sizeof(int));
if (ptr != NULL) {
printf("[OK] malloc fonctionne\n");
free(ptr);
}
/* Test 3 : arithmetique */
int result = 42 + 27;
if (result == 69) {
printf("[OK] Arithmetique correcte\n");
}
printf("\nEnvironnement pret pour le cours !\n");
return 0;
}gcc -std=c17 -Wall -Wextra -O0 -g test_env.c -o test_env
./test_env
valgrind --leak-check=full ./test_env- Observer. Les trois tests affichent-ils
[OK]? valgrind signale-t-il une fuite ? - Modifier. Copier
test_env.cdanstest_env_fuite.cet y supprimer la lignefree(ptr);. Compiler, puis lancer valgrind avec--leak-check=full: combien d’octets sont perdus, dans combien de blocs, alloués à quelle ligne ? - Observer. Compiler
test_env_fuite.cavec-fsanitize=address(exécutablefuite_asan) et l’exécuter : que signale AddressSanitizer, et avec quel statut le programme se termine-t-il (echo $?) ? - Expliquer. Lancer
valgrind ./fuite_asan, puisgdb ./fuite_asanetrun. Que se passe-t-il dans chaque cas, et qu’en conclure sur l’usage de ces outils ?
- Lancer le conteneur depuis le dossier de travail, avec
-v "$(pwd)":/workspaceet--security-opt seccomp=unconfined; seuls les fichiers de/workspacesurvivent àexit. - Éditer avec Vim dans le conteneur, ou sur l’hôte ; compiler dans le conteneur avec
-std=c17 -Wall -Wextra -O0 -g. makerecompile ce qui a changé ; gdb arrête et inspecte ; valgrind et AddressSanitizer surveillent la mémoire, un outil à la fois.
Pour cette séance
Le cours
Les slides
À télécharger
- Code de départ du TP (ZIP, 3 Ko)