2015-03-06 7 views
6

È un carico disallineato a causa di un cast dal comportamento non definito void*?È un carico disallineato a causa di un comportamento non definito del cast?


Ecco quello che sto vedendo con Clang e le sue disinfettanti:

bufhelp.h:146:29: runtime error: load of misaligned address 0x7fff04fdd0e1 for type 'const uintptr_t' (aka 'const unsigned long'), which requires 8 byte alignment 
0x7fff04fdd0e1: note: pointer points here 
00 00 00 66 66 6f 6f 62 61 72 34 32 46 4f 4f 42 41 52 31 37 66 6f 6f 62 61 72 34 33 46 4f 4f 42 
      ^

Ed è qui che il cast entra in gioco:

buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len) 
{ 
    ... 
    ldst = (uintptr_t *)(void *)dst; 
    lsrc1 = (const uintptr_t *)(const void *)src1; 
    lsrc2 = (const uintptr_t *)(const void *)src2; 

    for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) 
    *ldst++ = *lsrc1++^*lsrc2++; 

    ... 
} 

correlati, ma io don' Credo che risponda alla domanda di cui sopra:

+2

Dipenderà interamente da ciò che viene mostrato in quella funzione come parametri. Senza vedere il codice chiamante, non è davvero possibile rispondere alla domanda. – Lundin

+0

@Lundin: è questo il caso? Clang ha già avvisato che l'indirizzo è 0x7fff04fdd0e1. Può '0xXXXXXXX1' essere mai un' uintptr_t * 'usato nel ciclo? O sto analizzando l'output di Clang in modo errato? – jww

+0

Sì, ma _why_ è XXX1? È necessario passare un puntatore char o qualcosa alla funzione. Non c'è nulla nel codice pubblicato che possa causare un disallineamento, poiché tutta l'aritmetica del puntatore che si esegue è basata sul tipo corretto. – Lundin

risposta

6

La conversione di un puntatore erroneamente allineato sé è indefinito, non solo un carico attraverso tale puntatore (C11 (n1570) 6.3.2.3 p7):

Un puntatore a un tipo di oggetto può essere convertito ad un puntatore a un tipo di oggetto diverso. Se il puntatore risultante non è allineato correttamente [...] per il tipo di riferimento, il comportamento non è definito.

Il codice mostrato anche rompe rigorosa aliasing, come la punta-di opporsi è improbabile che possa essere dichiarata come uintptr_t (l'indirizzo sarebbe allineato correttamente altrimenti).

Per la conformità standard, è possibile utilizzare unsigned char.

Se uintptr_t pezzi -sized possono essere copiati per motivi di prestazioni, unsigned char può essere utilizzato fino a quando l'indirizzo è allineato correttamente, seguito da un altro ciclo di copiatura uintptr_t. Questo dovrebbe essere fatto attraverso un sindacato o tramite memcpy per evitare problemi di aliasing (Gcc può ottimizzare memcpy chiama se la dimensione è costante).È possibile che gli ultimi byte debbano essere copiati nuovamente tramite unsigned char per evitare l'accesso fuori dai limiti (leggere i byte sizeof(uintptr_t)-1 oltre l'array non dovrebbe causare problemi (Glibc lo fa in più punti), ma la scrittura tramite dst potrebbe scrivere in un altro oggetto). Potrebbe essere utile per restrict -qualificare i puntatori utilizzati.

+1

Modificato la parte di accesso fuori dai limiti. Non dovrei dare consigli per ignorare UB prima del mio primo caffè ... – mafso

1

Penso che la risposta alla tua domanda specifica è "sì" - anche se non sono sicuro che sia specifico per il cast in sé, ma per i puntatori non allineati in generale. Il codice interno a buf_xor() mi sembra prevalentemente OK, quindi darei un'occhiata a quali indirizzi vengono inoltrati.

Mi sembra che tu non voglia chiamare il buf_xor() con indirizzi non allineati. Se non è così (se chiami but_xor() ovunque con indirizzi allineati), allora mi assicurerei che uintptr_t sia definito come la stessa cosa (e in particolare larga 64 bit, basata sul tuo output) dove buf_xor() è compilato, così come dove è chiamato.

Un ultimo parere personale è che poiché l'implementazione buf_xor() richiede puntatori allineati come parametri su alcune implementazioni di processori/compilatori, è probabile che si possa risparmiare qualche problema futuro cambiando la firma in modo da riflettere (modifica void * in uintptr_t *) o modificare l'implementazione stessa per trattare con garbo, 'manualmente', con indirizzi non allineati su tutte le architetture.

+0

Questo è in realtà il codice GnuPG che sto analizzando e test di accettazione. Volevo risolvere il problema con i sindacati o i puntatori allineati nei chiamanti. Ma è stato fatto in così tanti posti, è diventato più facile sistemare la funzione con una 'memcpy' in una temporanea. Inserirò la segnalazione di errore per avvertirli del problema, tuttavia (vedi [Problema 1881: comportamento indefinito durante l'esecuzione di 'make check' in Clang sanitizers] (https://bugs.g10code.com/gnupg/issue1881)). – jww