Er dereferencing nullpeker gyldig i sizeof drift

stemmer
19

Jeg har kommet over en kodebit det til meg skal krasje med en segmentering feil , og likevel det fungerer uten problemer. Koden aktuelle pluss relevante datastruktur er som følger (med tilhørende kommentar funnet rett ovenfor):

typedef struct {
  double length;
  unsigned char nPlaced;
  unsigned char path[0];
}


RouteDefinition* Alloc_RouteDefinition()
{
  // NB: The +nBags*sizeof.. trick expands the path[0] array in RouteDefinition
  // to the path[nBags] array
  RouteDefinition *def = NULL;
  return (RouteDefinition*) malloc(sizeof(RouteDefinition) + nBags * sizeof(def->path[0]));
}

Hvorfor virker dette? Jeg samle at den sizeof den char * løses til størrelsen på pekeren på den gitte arkitektur, men det bør ikke krasje og brenne mens dereferencing en NULL-pointer?

Publisert på 05/11/2013 klokken 06:25
kilden bruker
På andre språk...                            


3 svar

stemmer
9

Den sizeofoperator er en ren samle-tidsoperasjon. Ingenting er gjort runtime, noe som er grunnen til at det fungerer fint.

Forresten, det pather medlemmet ikke egentlig en peker, så det kan ikke teknisk være NULL.

Svarte 05/11/2013 kl. 06:26
kilden bruker

stemmer
14

Hvorfor virker dette?

Dette fungerer fordi sizeof er en kompilering konstruere, med unntak av variabel lengde arrays evalueres ikke i det hele tatt. Hvis vi ser på C99 utkast standard seksjon 6.5.3.4 The sizeof operatør paragraf 2 sier ( min uthevelse ):

[...] Størrelsen bestemmes av typen av den operand. Resultatet er et helt tall. Dersom typen av operand er en variabel lengde matrise-type, blir operand evaluert; I motsatt fall blir operanden ikke undersøkt og resultatet er et heltall konstant.

ser vi også følgende eksempel i punkt 5 som bekrefter dette:

double *dp = alloc(sizeof *dp);
       ^^^                ^
                          |                                 
                          This is not the use of uninitialized pointer 

Ved kompilering av typen av uttrykket med bestemmes for å beregne resultatet. Vi kan videre demonstrere dette med følgende eksempel:

int x = 0 ;
printf("%zu\n", sizeof( x++ ));

som ikke vil øke x, noe som er ganske ryddig.

Oppdater

Som jeg oppmerksom på i mitt svar til Hvorfor sizeof (x ++) ikke øke x? Det er et unntak til sizeofå være en kompilering operasjon, og det er når det er operand er en variabel lengde array ( VLA ). Selv om jeg ikke tidligere peke det ut sitatet fra 6.5.3.4ovenfor gjør det sier dette.

Selv i C11 i motsetning til C99 det er uspesifisert om sizeofevalueres eller ikke i dette tilfellet.

Også oppmerksom på at det er et C ++ versjon av denne quesiton: Ikke evaluere uttrykket som sizeof er brukt gjør det lovlig å dereference en null eller ugyldig pekeren i sizeof i C ++? .

Svarte 05/11/2013 kl. 07:28
kilden bruker

stemmer
2

Som sier at sizeofer et rent kompilere-tid konstruksjon (som for tiden eksisterende svar gjør) er ikke helt nøyaktig. Siden C99, sizeofer ikke et rent kompilering konstruere. Operanden sizeofevalueres ved kjøring av operanden type er en VLA. Svarene postet så langt ser ut til å ignorere den muligheten.

Koden er greit, siden det ikke innebære noen VLA. Imidlertid kan noe som dette være en annen historie

unsigned n = 10;
int (*a)[n] = NULL; // `a` is a pointer to a VLA 

unsigned i = 0;
sizeof a[i++];      // applying `sizeof` to a VLA

Ifølge C99 standard, argumentet sizeofer ment å bli vurdert (dvs. ier ment å bli økes, se https://ideone.com/9Fv6xC ). Men jeg er ikke helt sikker på at null-punktet dereferanse i a[0]er ment å produsere udefinert oppførsel her.

Svarte 10/06/2015 kl. 20:52
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more