L'indirizzo 0000000C è un indirizzo speciale?

32

Quando si programmano a volte le cose si rompono. Hai fatto un errore e il tuo programma prova a leggere da un indirizzo sbagliato.

Una cosa che mi colpisce è che spesso queste eccezioni sono come:

Access violation at address 012D37BC in module 'myprog.exe'. Read of address 0000000C.

Ora vedo molti log di errori e ciò che mi colpisce è il: 0000000C. È un indirizzo "speciale"? Vedo altre violazioni di accesso con cattive letture ma gli indirizzi sembrano casuali, ma questo continua a tornare in situazioni totalmente diverse.

    
posta Pieter B 20.01.2015 - 09:38
fonte

3 risposte

58

00000000 è un indirizzo speciale (il puntatore nullo). 0000000C è proprio quello che ottieni quando aggiungi un offset di 12 al puntatore nullo, molto probabilmente perché qualcuno ha cercato di ottenere il membro z di una struttura come quella sottostante tramite un puntatore che era effettivamente nullo.

struct Foo {
    int w, x, y; // or anything else that takes 12 bytes including padding
    // such as: uint64_t w; char x;
    // or: void *w; char padding[8];
    // all assuming an ordinary 32 bit x86 system
    int z;
}
    
risposta data 20.01.2015 - 09:44
fonte
11

In Windows è illegale dereferenziare la intera prima e ultima pagina , in altre parole il primo o l'ultimo 64 KiB della memoria di processo (gli intervalli 0x00000000 a 0x0000ffff e 0xffff0000 a 0xffffffff in un'applicazione a 32 bit).

Si tratta di intercettare il comportamento indefinito del dereferenziamento di un puntatore o indice nullo in un array nullo. E la dimensione della pagina è di 64 KiB, quindi Windows deve solo impedire che alla prima o all'ultima pagina venga assegnato un intervallo valido.

Questo non proteggerà i puntatori non inizializzati che potrebbero avere qualsiasi valore (inclusi gli indirizzi validi).

    
risposta data 20.01.2015 - 11:56
fonte
2

Per quanto riguarda perché 0x0C sembra più comune di 0x08 (è davvero? Non so, e in quali tipi di applicazioni?), questo potrebbe avere a che fare con i puntatori di tabella dei metodi virtuali. Questo è davvero più di un commento (ipotesi di massa selvaggia :), ma è un po 'più grande, quindi ecco qui ... Se hai una classe con metodi virtuali, i suoi campi saranno spostati da 0x04 . Ad esempio, una classe che eredita da un'altra classe virtuale potrebbe avere un layout di memoria come questo:

0x00 - VMT pointer for parent
0x04 - Field 1 in parent
0x08 - VMT pointer for child
0x0C - Field 1 in child

Questo è uno scenario comune o addirittura vicino? Non ne sono sicuro. Tuttavia, tieni presente che in un'applicazione a 64 bit, questo potrebbe essere spostato in modo ancora più interessante verso il valore 0x0C :

0x00 - VMT parent
0x08 - Field 1 parent
0x0C - VMT child
0x14 - Field 2 child

Quindi in realtà ci sono molti casi in cui le applicazioni potrebbero avere una sovrapposizione significativa negli offset del puntatore nullo. Potrebbe essere il primo campo di una classe figlio o il puntatore della tabella del metodo virtuale, necessario ogni volta che si chiama un metodo virtuale su un'istanza, quindi se si chiama un metodo virtuale su un puntatore null , si otterrà l'accesso violazione sul suo offset VMT. La prevalenza di questo particolare valore potrebbe quindi avere qualcosa a che fare con alcune API comuni che forniscono una classe che ha un modello di ereditarietà simile o, più probabilmente, un'interfaccia particolare (abbastanza possibile per alcune classi di applicazioni, come i giochi DirectX). Potrebbe essere possibile tracciare alcune semplici cause comuni come questa, ma tendo a liberarmi delle applicazioni che fanno il dereferenziamento nullo abbastanza rapidamente, quindi ...

    
risposta data 21.01.2015 - 10:32
fonte

Leggi altre domande sui tag