$ cat segfault.c int fun() { int *p; p = 0; *p = 42; } int main() { fun(); }Si nous l'ÈxÈcutons, le systËme nous envoie un
SIGSEGV
:
$ ./segfault Segmentation faultNotes:
core
car nous
avons fixÈ la limite coredumpsize
ý zÈro.
Pour dÈboguer correctement, il faut dire au systËme que nous avons
besoin des fichiers core
:
En tcsh(1):
$ unlimit coredumpsizeEn bash(1):
$ ulimit -c unlimitedLes fichiers
core
contiennent l'image mÈmoire du
processus au moment ou l'erreur s'est produite.
Il nous faut aussi compiler les fichiers sources avec l'option
-g
.
$ cc -g -c segfault.c $ cc -o segfault segfault.o $ ./segfault Segmentation fault (core dumped) $ gdb ./segfault segfault.core GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as Ô386--netbsd"... Core was generated by `segfault'. Program terminated with signal 11, Segmentation fault. Reading symbols from /usr/libexec/ld.elf_so...done. Reading symbols from /usr/lib/libc.so.12...done. #0 0x80487d4 in fun () at segfault.c:6 6 *p = 42; (gdb) where #0 0x80487d4 in fun () at segfault.c:6 #1 0x80487e4 in main () at segfault.c:11 #2 0x8048585 in ___start () (gdb) print p $1 = (int *) 0x0 (gdb)Nous lanÁons gdb(1) avec en paramËtre le fichier ÈxÈcutable suivi de l'image mÈmoire. Le programme nous propose une invite o˜ nous pouvons taper des commandes:
Commande | Description |
---|---|
where | Montre la pile des fonctions ý l'instant ou le core a ÈtÈ gÈnÈrÈ. |
print var | Affiche la variable passÈe en paramËtre. |
quit | Quitte le programme.
|
$ gdb ./segfault GNU gdb 4.17 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as Ô386--netbsd"... (gdb) break fun Breakpoint 1 at 0x80487ca: file segfault.c, line 5. (gdb) run Starting program: /space/wd0e/root/work/cunix_a1/cours8-12/./segfault Breakpoint 1, fun () at segfault.c:5 5 p = 0; (gdb) next 6 *p = 42; (gdb) next Program received signal SIGSEGV, Segmentation fault. 0x80487d4 in fun () at segfault.c:6 6 *p = 42; (gdb) quit The program is running. Exit anyway? (y or n) y
Commande gdb(1) | Commande dbx(1) | Description |
---|---|---|
break fun | stop fun | Positionne
un point d'arrÍt ý la fonction fun .
|
run | idem | DÈmarre le programme. |
next | idem | ŠxÈcute la fonction ou l'instruction suivante. |
step | idem | Rentre dans la fonction suivante suivante.
|
Il existe des centaines d'autres commandes aux dÈbuggers qui permettent de faire des arrÍts conditionnels, etc.
$ cat align.c int main() { long *p; p = xmalloc(2 * sizeof (*p)); p = (char *)p + 1; *p = 42; }Sur alpha:
$ ./align Unaligned access pid=5251De tels problËmes d'alignement peuvent causer des bus error sur certaines architectures (par exemple mips). Le PC apparement ne tient pas compte de tels problËmes (voir Sebc pour l'explication).va=0x140000901 pc=0x120001230 ra=0x12000115c inst=0xb0200001
Dans tous les cas, on ne doit pas utiliser une adresse non divisible
par la taille des registres du processeur (32 bits soit 4 pour R3000 et x86,
64 bits soit 8 pour alpha) pour faire une opÈration LOAD ou STORE d'un entier
supÈrieur ý 1 octet (mov ax, [adress]
ou mov eax,
[address]
et vis-versa sur x86, LHx, SHx, LWx,
SWx
dans la famille R[36]000).
Note: La configuration de droite est impossible.
$ cat badaddr.c int main() { long *p, *n; p = xmalloc(sizeof (*p)); n = p + 1; *n = 42; } $ ./badaddr $Nous remarquons qu'il ne gÈnËre pas obligatoirement un segmentation fault.
Quand nous linkons avec la libefence
(_resources/libefence.tgz), le
segmentation fault est mis en Èvidence:
$ ./badaddr Electric Fence 2.0.5 Copyright (C) 1987-1995 Bruce Perens. Segmentation fault (core dumped)Explication: La mÈmoire est allouÈe par page de 4096, 8192 ou plus selon les architectures (voir a1_cunix9.html). Lorsque nous utilisons une adresse non thÈoriquement allouÈe, il se peut qu'elle soit contenue dans la page allouÈe. Dans l'exemple prÈcÈdent, l'adresse
n
a de fortes chances d'Ítre dans la page allouÈe pour
p
.
La librairie libefence
alloue les buffers ý la fin des
pages mÈmoire quand elle le peut ce qui a pour effet de gÈnÈrer des
segmentation fault lorsque nous Ècrivons aprËs les buffers.
Note: La libefence ne rÈsout pas tous les problËmes mais peut aider ý mieux identifier l'origine des erreurs mÈmoire.