Wat is een busfout?

Wat betekent het bericht “busfout” en hoe verschilt het van een segfault?


Antwoord 1, autoriteit 100%

Busfouten zijn tegenwoordig zeldzaam op x86 en treden op wanneer uw processor niet eens de gevraagde geheugentoegang kan proberen, meestal:

  • een processorinstructie gebruiken met een adres dat niet voldoet aan de uitlijningsvereisten.

Segmentatiefouten treden op bij toegang tot geheugen dat niet tot uw proces behoort. Ze komen vaak voor en zijn meestal het gevolg van:

  • een verwijzing gebruiken naar iets waarvan de toewijzing ongedaan is gemaakt.
  • een niet-geïnitialiseerde en dus nep-aanwijzer gebruiken.
  • met een null-aanwijzer.
  • een buffer vollopen.

PS: Om preciezer te zijn, dit is niet het manipuleren van de aanwijzer zelf die problemen veroorzaakt, het is toegang tot het geheugen waarnaar het verwijst (dereferentie).


Antwoord 2, autoriteit 33%

Een segfout is toegang tot geheugen waartoe u geen toegang heeft. Het is alleen-lezen, je hebt geen toestemming, enz…

Een busfout probeert toegang te krijgen tot geheugen dat er onmogelijk kan zijn. Je hebt een adres gebruikt dat geen betekenis heeft voor het systeem, of het verkeerde soort adres voor die bewerking.


Antwoord 3, autoriteit 8%

mmapminimaal POSIX 7 voorbeeld

“Busfout” treedt op wanneer de kernel SIGBUSnaar een proces stuurt.

Een minimaal voorbeeld dat het produceert omdat ftruncatevergeten was:

#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */
int main() {
    int fd;
    int *map;
    int size = sizeof(int);
    char *name = "/a";
    shm_unlink(name);
    fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
    /* THIS is the cause of the problem. */
    /*ftruncate(fd, size);*/
    map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    /* This is what generates the SIGBUS. */
    *map = 0;
}

Uitvoeren met:

gcc -std=c99 main.c -lrt
./a.out

Getest in Ubuntu 14.04.

POSIX beschrijftSIGBUSals:

Toegang tot een ongedefinieerd deel van een geheugenobject.

De mmap-specificatiezegt dat:

Verwijzingen binnen het adresbereik beginnend bij pa en doorlopend voor len bytes tot hele pagina’s na het einde van een object zullen resulteren in de levering van een SIGBUS-signaal.

En shm_openzegt dathet genereert objecten van grootte 0:

Het gedeelde geheugenobject heeft een grootte van nul.

Dus bij *map = 0raken we voorbij het einde van het toegewezen object.

Niet-uitgelijnde toegang tot stapelgeheugen in ARMv8 aarch64

Dit werd vermeld op: Wat is een busfout?voor SPARC, maar hier zal ik een meer reproduceerbaar voorbeeld geven.

Alles wat je nodig hebt is een vrijstaand aarch64-programma:

.global _start
_start:
asm_main_after_prologue:
    /* misalign the stack out of 16-bit boundary */
    add sp, sp, #-4
    /* access the stack */
    ldr w0, [sp]
    /* exit syscall in case SIGBUS does not happen */
    mov x0, 0
    mov x8, 93
    svc 0

Dat programma verhoogt vervolgens SIGBUS op Ubuntu 18.04 aarch64, Linux-kernel 4.15.0 in een ThunderX2-servermachine.

Helaas kan ik het niet reproduceren in de gebruikersmodus QEMU v4.0.0, ik weet niet waarom.

De fout lijkt optioneel te zijn en wordt beheerd door de velden SCTLR_ELx.SAen SCTLR_EL1.SA0. Ik heb de gerelateerde documenten samengevat hier een beetje verder.


Antwoord 4, autoriteit 4%

Ik geloof dat de kernel SIGBUS verhoogt
wanneer een toepassing gegevens vertoont
verkeerde uitlijning op de databus. I denk
dat sinds de meeste[?] moderne compilers
voor de meeste processors pad / lijn de . uit
gegevens voor de programmeurs, de
uitlijnproblemen van vroeger (tenminste)
verzacht, en daarom ziet men niet
SIGBUS tegenwoordig te vaak (AFAIK).

Van: Hier


Antwoord 5, autoriteit 3%

Je kunt SIGBUS ook krijgen als een codepagina om de een of andere reden niet kan worden opgeroepen.


Antwoord 6, autoriteit 2%

Ik ben het eens met alle bovenstaande antwoorden. Hier zijn mijn 2 cent met betrekking tot de BUS-fout:

Een BUS-fout hoeft niet voort te komen uit de instructies in de programmacode. Dit kan gebeuren wanneer u een binair bestand uitvoert en tijdens de uitvoering wordt het binaire bestand gewijzigd (overschreven door een build of verwijderd, enz.).

Controleren of dit het geval is

Een eenvoudige manier om te controleren of dit de oorzaak is, is door een aantal instanties van hetzelfde binaire bestand te starten in een build-uitvoermap en een build uit te voeren nadat ze zijn gestart. Beide actieve instanties zouden crashen met een SIGBUS-fout kort nadat de build is voltooid en het binaire bestand vervangen (degene die beide instanties momenteel uitvoeren).

Onderliggende reden

Dit komt omdat het besturingssysteem geheugenpagina’s verwisselt en in sommige gevallen is het binaire bestand mogelijk niet volledig in het geheugen geladen. Deze crashes zouden optreden wanneer het besturingssysteem de volgende pagina van hetzelfde binaire bestand probeert op te halen, maar het binaire bestand is veranderd sinds de laatste keer dat het werd gelezen.


Antwoord 7

Een klassiek voorbeeld van een busfout is op bepaalde architecturen, zoals de SPARC( ten minste enkele SPARC’s, misschien is dit gewijzigd), is wanneer u een verkeerd uitgelijnde toegang doet. Bijvoorbeeld:

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

Dit fragment probeert de 32-bits integerwaarde 0xdeadf00dte schrijven naar een adres dat (waarschijnlijk) niet goed is uitgelijnd, en zal een busfout genereren op architecturen die hierin “kieskeurig” zijn groet. De Intel x86 is trouwens nietzo’n architectuur, hij zou de toegang toestaan (zij het langzamer uitvoeren).


Antwoord 8

Een specifiek voorbeeld van een busfout die ik net tegenkwam tijdens het programmeren van C op OS X:

#include <string.h>
#include <stdio.h>
int main(void)
{
    char buffer[120];
    fgets(buffer, sizeof buffer, stdin);
    strcat("foo", buffer);
    return 0;
}

In het geval dat je het niet meer weet, voegt strcathet tweede argument toe aan het eerste door het eerste argument te veranderen (draai de argumenten om en het werkt prima). Op linux geeft dit een segmentatiefout (zoals verwacht), maar op OS X geeft het een busfout. Waarom? Ik weet het echt niet.


Antwoord 9

Ik kreeg een busfout toen de hoofdmap op 100% stond.


Antwoord 10

Het hangt af van uw besturingssysteem, CPU, compiler en mogelijk andere factoren.

Over het algemeen betekent dit dat de CPU-bus een opdracht niet kon voltooien of een conflict had, maar dat kan een hele reeks dingen betekenen, afhankelijk van de omgeving en de code die wordt uitgevoerd.

-Adam


Antwoord 11

Normaal gesproken betekent dit een niet-uitgelijnde toegang.

Een poging om toegang te krijgen tot geheugen dat niet fysiek aanwezig is, zou ook een busfout opleveren, maar u zult dit niet zien als u een processor gebruikt met een MMU en een besturingssysteem dat geen fouten bevat, omdat u dat niet doet laat eventueel niet-bestaand geheugen toegewezen aan de adresruimte van uw proces.


Antwoord 12

Mijn reden voor de busfout op Mac OS X was dat ik probeerde ongeveer 1 MB aan de stapel toe te wijzen. Dit werkte goed in één thread, maar bij gebruik van openMP leidt dit tot busfouten, omdat Mac OS X zeer beperkte stapelgrootte voor niet-hoofdthreads.


Antwoord 13

Om toe te voegen aan wat blxtd hierboven antwoordde: busfouten treden ook op wanneer uw proces niet kan proberen toegang te krijgen tot het geheugen van een bepaalde ‘variabele’.

for (j = 0; i < n; j++) {
    for (i =0; i < m; i++) {
        a[n+1][j] += a[i][j];
    }
}

Let op het ‘onbedoelde‘ gebruik van variabele ‘i’in de first ‘for loop’?Dat is de oorzaak van de busfout in dit geval.


Antwoord 14

Ik ben er net op de harde manier achter gekomen dat je op een ARMv7-processor een code kunt schrijven die je een segmentatiefout geeft als deze niet is geoptimaliseerd, maar die je een busfout geeft als je hem compileert met -O2 (meer optimaliseren).

Ik gebruik de GCC ARM gnueabihf cross-compiler van Ubuntu 64 bit.


Antwoord 15

Bij mij veroorzaakte ik per ongeluk een “Bus Error” door niet te verklaren dat mijn assembly terugging naar de sectie .text. Het lijkt misschien voor de hand liggend, maar het hield me een tijdje tegen.

Bijvoorbeeld

.globl _myGlobal # Allocate a 64-bit global with the value 2
.data
.align 3
_myGlobal:
.quad 2
.globl _main # Main function code
_main:
push %rbp

Er ontbrak een tekstinstructie bij het terugkeren naar code uit gegevens:

_myGlobal:
.quad 2
.text # <- This
.globl _main
_main:

Ik hoop dat dit iemand van pas komt


Antwoord 16

Ten eerste zijn SIGBUS en SIGSEGV geen specifiek type fouten, maar groepen of families van fouten. Dit is de reden waarom je meestal een signaalnummer (si_no) en een signaalcode (si_code) ziet.

Ze zijn ook afhankelijk van het besturingssysteem en de architectuur wat ze precies kunnen veroorzaken.

Over het algemeen kunnen we dat wel zeggen.
Een SIGSEGV is gerelateerd aan geheugentoewijzingen (machtigingen, geen toewijzing), d.w.z. een mmu-fout.

Een SIGBUS is wanneer het in kaart brengen van het geheugen slaagt en je een probleem hebt met het onderliggende geheugensysteem (geen geheugen, geen geheugen op die locatie, uitlijning, smmu verhindert toegang, enz.), dwz een busfout..

Een Sigbus kan ook met mmapped bestanden zijn, als het bestand verdwijnt van het systeem, b.v. U mmt een bestand op een verwijderbare media en wordt losgekoppeld.

Een goede plek om op een platform te kijken, is de header Siginfo.h, om een ​​idee te krijgen van de signaal-subtypen.
b.v. Voor Linux biedt deze pagina een overzicht.
https: //elixir.bootlin. com / linux / laatste / bron / omvatten / uapi / ASM-generieke / siginfo.h # L245

/*
 * SIGSEGV si_codes
 */
#define SEGV_MAPERR 1   /* address not mapped to object */
#define SEGV_ACCERR 2   /* invalid permissions for mapped object */
#define SEGV_BNDERR 3   /* failed address bound checks */
#ifdef __ia64__
# define __SEGV_PSTKOVF 4   /* paragraph stack overflow */
#else
# define SEGV_PKUERR    4   /* failed protection key checks */
#endif
#define SEGV_ACCADI 5   /* ADI not enabled for mapped object */
#define SEGV_ADIDERR    6   /* Disrupting MCD error */
#define SEGV_ADIPERR    7   /* Precise MCD exception */
#define SEGV_MTEAERR    8   /* Asynchronous ARM MTE error */
#define SEGV_MTESERR    9   /* Synchronous ARM MTE exception */
#define NSIGSEGV    9
/*
 * SIGBUS si_codes
 */
#define BUS_ADRALN  1   /* invalid address alignment */
#define BUS_ADRERR  2   /* non-existent physical address */
#define BUS_OBJERR  3   /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR   4
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO   5
#define NSIGBUS     5

Een laatste noot is dat alle signalen ook gebruiker kunnen zijn, b.v. doden.
Als het door de gebruiker is gegenereerd, is de si_code SI_USER. Speciale bronnen krijgen dus negatieve si_codes.

/*
 * si_code values
 * Digital reserves positive values for kernel-generated signals.
 */
#define SI_USER     0       /* sent by kill, sigsend, raise */
#define SI_KERNEL   0x80        /* sent by the kernel from somewhere */
#define SI_QUEUE    -1      /* sent by sigqueue */
#define SI_TIMER    -2      /* sent by timer expiration */
#define SI_MESGQ    -3      /* sent by real time mesq state change */
#define SI_ASYNCIO  -4      /* sent by AIO completion */
#define SI_SIGIO    -5      /* sent by queued SIGIO */
#define SI_TKILL    -6      /* sent by tkill system call */
#define SI_DETHREAD -7      /* sent by execve() killing subsidiary threads */
#define SI_ASYNCNL  -60     /* sent by glibc async name lookup completion */
#define SI_FROMUSER(siptr)  ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr)    ((siptr)->si_code > 0)

Antwoord 17

Een typische bufferoverloop die resulteert in een busfout is,

{
    char buf[255];
    sprintf(buf,"%s:%s\n", ifname, message);
}

Als de grootte van de tekenreeks tussen dubbele aanhalingstekens (“”) hier groter is dan de buf-grootte, geeft dit een busfout.

Other episodes