2017-05-08 4 views
2

Ich führe einige Updates durch undefined Behavior Sanitizer. Das Desinfektionsmittel produziert eine Botschaft, die ich nicht ganz verstehen:Laden von Adresse X mit nicht genügend Speicherplatz für ein Objekt vom Typ Y

kalyna.cpp:1326:61: runtime error: load of address 0x0000016262c0 with insufficient space for an object of type 'const uint32_t' 
0x0000016262c0: note: pointer points here 
20 8b c1 1f a9 f7 f9 5c 53 c4 cf d2 2f 3f 52 be 84 ed 96 1b b8 7a b2 85 e0 96 7d 5d 70 ee 06 07 
      ^

Der Code in Frage versucht Cache Timing-Angriffe härter durch Berühren Adressen im Bereich einer Cache-Zeile zu machen. Linie 1326 ist die Linie mit reinterpret_cast:

// In KalynaTab namespace 
uint64_t S[4][256] = { 
    ... 
}; 
... 

// In library's namespace 
const int cacheLineSize = GetCacheLineSize(); 
volatile uint32_t _u = 0; 
uint32_t u = _u; 

for (unsigned int i=0; i<256; i+=cacheLineSize) 
    u &= *reinterpret_cast<const uint32_t*>(KalynaTab::S+i); 

Warum ist die santizier behauptet, ein uint32_t u nicht genügend Platz hat eine uint32_t zu halten?

Oder vielleicht, analysiere ich die Fehlermeldung richtig? Berüchtigt sich der Sanitzier? Wenn ich es falsch analysiere, worüber beschwert sich dann der Sanitzer?


$ lsb_release -a 
LSB Version: :core-4.1-amd64:core-4.1-noarch 

$ gcc --version 
gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1) 
+0

Ich vermute es beschweren sich über '* reinterpret_cast (KalynaTab :: S + i)'. – cdhowie

+6

'KalynaTab :: S + i' ist das' i'th' 'uint64_t [256]' Array der * dominanten * Dimension Ihrer 4x256-Tabelle. Mit anderen Worten, sobald "i"> = 4 ist, sind Sie außerhalb der Reichweite und rufen * undefiniertes Verhalten * auf. Es ist ein Zeiger-arithmetisches Ding. – WhozCraig

+0

Danke @WhozCraig. Ich glaube, du hast Recht. Aber erklärt das die Fehlermeldung über nicht genügend Speicherplatz? Oder anders gesagt, würde das nicht zu einem anderen Ergebnis führen (wie ein Zugang außerhalb der Grenzen)? – jww

Antwort

2

Die Kennung S nicht auf einen Zeiger der Sie es tut denken Typ umwandeln. Als Ergebnis können Sie Ihre Zeigerarithmetik wirft Weg außerhalb der Reichweite Ihrer Daten und wird am besten durch das Beispiel gezeigt:

#include <iostream> 
#include <cstdint> 

uint64_t S[4][256]; 

int main() 
{ 
    std::cout << static_cast<void*>(S+0) << '\n'; 
    std::cout << static_cast<void*>(S+1) << '\n'; 
    std::cout << static_cast<void*>(S+2) << '\n'; 
    std::cout << static_cast<void*>(S+3) << '\n'; 
    std::cout << '\n'; 

    std::cout << static_cast<void*>(*S+0) << '\n'; 
    std::cout << static_cast<void*>(*S+1) << '\n'; 
    std::cout << static_cast<void*>(*S+2) << '\n'; 
    std::cout << static_cast<void*>(*S+3) << '\n'; 
} 

Output (natürlich plattformabhängig)

0x1000020b0 
0x1000028b0 
0x1000030b0 
0x1000038b0 

0x1000020b0 
0x1000020b8 
0x1000020c0 
0x1000020c8 

Hinweis der Schritt der ersten Folge von Zahlen 0x800 pro untere Reihe. Dies ist sinnvoll, da jede Zeile aus 0x100 Einträgen zu je 8 Bytes besteht (die Elemente uint64_t). Der Typ des in der Zeigerarithmetik verwendeten Zeigers ist uint64_t (*)[256].

Nun notieren Sie den Schritt der zweiten Sequenz, die nur in S[0] peers. Der Schritt ist 8 Bytes, eine für jeden Slot. Der Typ des konvertierten Zeigers in dieser Berechnung ist uint64_t *.

Kurz gesagt, Ihre Zeigerarithmetik geht davon aus, S konvertiert zu uint64_t*, und es tut es nicht. Wie alle Array-to-Pointer-Konvertierungen wird es in ein pointer-to-first-Element konvertiert, einschließlich des Typs selbe. Der Elementtyp im Array von Arrays ist uint64_t[256], daher ist der konvertierte Zeigertyp uint64_t (*)[256].

+0

Danke, du hattest Recht. Ich habe meine Drähte über die Größe der Elemente gekreuzt. Hoffentlich habe ich etwas Neues über die Diagnose gelernt und ich werde die Nachricht in Zukunft wiedererkennen. – jww

Verwandte Themen