Sur les systèmes x86, nous ne voyons pas beaucoup d'erreurs de bus. J'ai enquêté lorsqu'une erreur de bus (SIGBUS) se produit. J'ai écrit x86 dans le titre, mais j'ai également vérifié SPARC.
L'erreur de bus (SIGBUS) est, comme son nom l'indique, une erreur qui se produit sur un bus. Se produit lorsqu'une erreur se produit lorsque la CPU fait une demande d'accès à la mémoire physique (elle est censée l'être). Normalement, ce qui est visible pour le programme utilisateur est l'adresse logique, et comme l'adresse physique n'est pas directement touchée, il est difficile pour le programme utilisateur de provoquer une erreur de bus. Il est également connu que cela se produit en raison d'erreurs d'alignement, mais cela ne se produit pas avec x86 car la vérification d'alignement est normalement désactivée. D'après mes recherches, il a été constaté que l'erreur de bus peut être causée de deux manières, "Appeler un appel système qui provoque SIGBUS" et "Faire une erreur d'alignement après avoir activé le contrôle d'alignement".
Un exemple dans StackOverflow. SIGBUS apparaît lorsque vous touchez la zone en dehors de la zone sécurisée par mmap.
bus.c
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main() {
FILE *f = tmpfile();
int *m = (int*)mmap(0, 4, PROT_WRITE, MAP_PRIVATE, fileno(f), 0);
*m = 0;
return 0;
}
$ gcc bus.c
$ ./a.out
[1] 16871 bus error ./bus
Il y a une description à cet effet dans man mmap.
The system shall always zero-fill any partial page at the end of an object. Further, the system shall never write out any modified portions of the last page of an object which are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.
De plus, la [Source] de mMap (http://lxr.free-electrons.com/source/mm/mmap.c#L3063) renvoie explicitement VM_FAULT_SIGBUS.
Un exemple trouvé dans here qui est sécurisé par char et accessible par int.
bus2.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *p = (char*)malloc(sizeof(int) + 1);
memset(p, 0, sizeof(int) + 1);
p++;
printf("%d\n", *(int *)p);
return 0;
}
Cela se termine normalement malgré l'incohérence d'alignement. Cela est dû au fait que l'indicateur de vérification d'alignement (AC) EFLAGS x86 est désactivé. S'il est activé, une erreur de bus se produira.
bus2p.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
asm( "pushf\n\torl $0x40000,(%rsp)\n\tpopf");
char *p = (char*)malloc(sizeof(int) + 1);
memset(p, 0, sizeof(int) + 1);
p++;
printf("%d\n", *(int *)p);
return 0;
}
Même si l'indicateur AC est activé, l'erreur de bus ne se produit pas sous Mac OS X et se termine normalement.
Essayez d'accéder à la zone de chaîne de caractères.
bus3.c
#include <stdio.h>
#include <stdlib.h>
int
main(void){
char *s = "test";
s[0] = '0';
printf("%s\n",s);
}
Il s'agit d'une erreur de segmentation (SIGSEGV) sur Linux, mais donne une erreur de bus sur Mac.
$ clang bus3.c
$ ./a.out
Bus error: 10
En résumé, ça ressemble à ça. J'ai également inclus les résultats de Cygwin. J'avais aussi un système SPARC Linux, donc je l'ai recherché (sauf pour bus2p.c, qui utilise des assemblages en ligne).
bus.c | bus2.c | bus2p.c | bus3.c | |
---|---|---|---|---|
Linux | SIGBUS | Réussite | SIGBUS | SIGSEGV |
Mac OS X | SIGBUS | Réussite | Réussite | SIGBUS |
Cygwin | SIGBUS | Réussite | Réussite | SIGSEGV |
SPARC | SIGSEGV | SIGBUS | ---- | SIGSEGV |
Dans le système x86 actuel, l'erreur de bus n'apparaît pas dans le programme utilisateur à moins que vous n'activiez explicitement la vérification d'alignement pour accéder à l'alignement incohérent ou que vous utilisiez un appel système qui émet SIGBUS. L'exception est Mac, qui a été signalé comme la distinction entre SIGBUS et SIGSEGV est ambiguë, et une erreur de bus se produit simplement en accédant à une chaîne de caractères. Même avec le même Linux, le comportement est assez différent avec SPARC. Je pense que c'est vrai que SIGBUS est émis en raison d'un alignement incorrect, mais je ne sais pas pourquoi il est émis SIGSEGV en raison d'un mMap incorrect (n'est-ce pas décidé par POSIX?).
Je n'aime pas le fait que tous les systèmes que j'ai vérifiés soient différents.
Recommended Posts