c++ - keywords - meta tag html



È possibile garantire il codice facendo le scritture di memoria non ottimizzate via in C++? (4)

I compilatori C ++ sono autorizzati a ottimizzare le scritture in trasferta in memoria :

 {
     //all this code can be eliminated
     char buffer[size];
     std::fill_n( buffer, size, 0);
 }

Quando si tratta di dati sensibili, l'approccio tipico utilizza puntatori volatile* per garantire che le scritture di memoria vengano emesse dal compilatore. Ecco come viene SecureZeroMemory() funzione SecureZeroMemory() nella libreria di runtime di Visual C ++ (WinNT.h):

FORCEINLINE PVOID RtlSecureZeroMemory(
     __in_bcount(cnt) PVOID ptr, __in SIZE_T cnt )
{
    volatile char *vptr = (volatile char *)ptr;
#if defined(_M_AMD64)
    __stosb((PBYTE )((DWORD64)vptr), 0, cnt);
#else
    while (cnt) {
        *vptr = 0;
        vptr++;
        cnt--;
    }
#endif
    return ptr;
}

La funzione esegue il puntatore passato su un puntatore volatile* e quindi scrive attraverso quest'ultimo. Tuttavia se lo uso su una variabile locale:

char buffer[size];
SecureZeroMemory( buffer, size );

la variabile stessa non è volatile . Quindi, secondo la definizione standard del C ++, le scritture sul comportamento osservabile nel buffer non contano come comportamento osservabile e sembra che possano essere ottimizzate.

Ora ci sono molti commenti sotto sui file di pagina, sulle cache, ecc., Che sono tutti validi, ma ignoriamoli in questa domanda. L'unica cosa di cui si tratta è se il codice per la scrittura della memoria sia ottimizzato o meno.

È possibile garantire che il codice che esegue le scritture in memoria non venga ottimizzato in C ++? La soluzione in SecureZeroMemory() conforme allo standard C ++?


C'è sempre una condizione di competizione tra quando ci sono informazioni sensibili in memoria e il tempo in cui lo cancelli. In quella finestra di tempo la tua applicazione potrebbe arrestarsi in modo anomalo e scaricare il core o un utente malintenzionato potrebbe ottenere un dump della memoria dello spazio degli indirizzi del processo con informazioni sensibili in testo normale.

Potrebbe essere che non dovresti memorizzare informazioni sensibili in memoria in testo normale. In questo modo ottieni una maggiore sicurezza e ignori completamente questo problema.


Con le funzioni di libreria come SecureZeroMemory , gli scrittori di librerie in genere si sono impegnati a garantire che tali funzioni non vengano delineate dal compilatore. Ciò significa che nello snippet

char buffer[size];
SecureZeroMemory( buffer, size );

il compilatore non sa cosa fa SecureZeroMemory con il buffer , quindi l'ottimizzatore non può dimostrare che il prelievo dello snippet non influisce sul comportamento osservabile del programma. In altre parole, gli scrittori della biblioteca avranno già fatto tutto il possibile per garantire che tale codice non venga ottimizzato.


Né lo standard C né C ++ impone alcun requisito su come le implementazioni memorizzano le cose nella memoria fisica. Le implementazioni sono libere di specificare tali cose, tuttavia, e le implementazioni di qualità che sono adatte per applicazioni che richiedono determinati comportamenti di memoria fisica specificheranno che si comporteranno coerentemente in modo adeguato.

Molte implementazioni elaborano almeno due dialetti distinti. Quando elaborano il loro dialetto "ottimizzazioni disabilitate", spesso documentano in modo dettagliato quante azioni interagiranno con la memoria fisica. Sfortunatamente, abilitare le ottimizzazioni normalmente si trasformerà in un dialetto semanticamente più debole che non garantisce quasi nulla su come le azioni interagiranno con la memoria fisica. Mentre dovrebbe essere possibile elaborare molte ottimizzazioni semplici e dirette pur continuando ad elaborare le cose in un modo che è coerente con il dialetto "ottimizzazioni disabilitate" in alcuni casi facilmente identificabili in cui sarebbe probabilmente importante, i compilatori non sono interessati a fornendo modalità che si concentrano sulla frutta a basso impatto sicuro.

L'unico modo affidabile per garantire che la memoria fisica venga trattata in un certo modo consiste nell'utilizzare un dialetto che promette di trattare la memoria fisica in quel modo. Se lo si fa, ottenere il trattamento richiesto sarà generalmente facile. In caso contrario, nulla garantirà che un'implementazione "creativa" non comporterà qualcosa di inaspettato.


Non esiste una soluzione portatile. Se lo desidera, il compilatore potrebbe aver fatto delle copie dei dati mentre lo stavate usando in più punti della memoria e qualsiasi funzione zero poteva azzerare solo quella che stava usando in quel momento. Qualsiasi soluzione sarà non portatile.





compiler-optimization