2016-10-19 45 views
5

Proste MWE:Co się stanie, jeśli niepoprawny adres zostanie uprzednio pobrany?

int* ptr = (int*)malloc(64 * sizeof(int)); 
_mm_prefetch((const char*)(ptr + 64), _MM_HINT_0); 
  1. Czy to zdefiniowane lub niezdefiniowane zachowanie?
  2. Czy to może podnieść sygnał i przerwać działanie programu?

Pytam ponieważ widzę takiej prefetching w kompilator wygenerowany kod, gdzie wewnątrz prefetching pętla jest wykonywana bez sprawdzania adresu (przechowywanej w rbx):

400e73:  49 83 c5 40    add r13,0x40 
400e77:  62 f1 f9 08 28 03  vmovapd zmm0,ZMMWORD PTR [rbx] 
400e7d:  4d 3b ec    cmp r13,r12 
400e80:  62 d1 f9 08 eb 4d ff vporq zmm1,zmm0,ZMMWORD PTR [r13-0x40] 
400e87:  90      nop 
400e88:  62 d1 78 08 29 4d ff vmovaps ZMMWORD PTR [r13-0x40],zmm1 
400e8f:  72 03     jb  400e94 <main+0x244> 
400e91:  49 89 c5    mov r13,rax 
400e94:  62 f1 78 08 18 53 1d vprefetch1 [rbx+0x740] 
400e9b:  ff c1     inc ecx 
400e9d:  62 f1 78 08 18 4b 02 vprefetch0 [rbx+0x80] 
400ea4:  48 83 c3 40    add rbx,0x40 
400ea8:  81 f9 00 00 10 00  cmp ecx,0x100000 
400eae:  72 c3     jb  400e73 <main+0x223> 
+1

Czy obejrzałeś dokumentację? – fuz

+1

Intrinsics Guide Intela nie mówi nic na ten temat. Ani Intrinsics Refernce. Ani zestaw instrukcji do instrukcji Intel Xeon Phi (zdemontowany kod został skompilowany dla KNC). O ile mi wiadomo. Znalazłem tylko tę uwagę w Co każdy programista powinien wiedzieć o pamięci: _Programy mogą używać _mm_prefetch nieodłącznego dla dowolnego wskaźnika w programie. Większość procesorów (na pewno wszystkie procesory x86 i x86-64) ignoruje błędy wynikające z nieprawidłowych wskaźników, które znacznie ułatwiają życie programisty. –

+0

Dobrze. Dziękuję za spojrzenie, zanim zadasz to pytanie. Ciekawe, że tak ważny szczegół pozostaje nieudokumentowany! – fuz

Odpowiedz

4

Przede wszystkim, Robi to kompilator lub robisz to w teorii bardzo różnie. Tylko dlatego, że wygląda na równoważny, nie czyni tego tak, kompilator może używać jakichkolwiek brudnych hacków, które działają bez względu na to, czy są wyrażane lub definiowane w pełni w standardzie C.

Oczywiście prefetching nie generuje sygnałów * byłoby prawie bezużyteczne, gdyby tak było. Dla niektórych nieprawidłowych wskaźników może być bardzo powolny, w zależności od tego, czy wywołają one brak TLB. Tak więc kompilator może bezpiecznie z niego korzystać, ale nie powinien bezkrytycznie używać go na wszystko.

Teraz używanie arytmetyki wskaźnikowej do tworzenia wskaźników poza granicami (z wyjątkiem tylko zakończenia do końca) jest w teorii UB, ale w przypadku zastosowania do wskaźnika jest to rodzaj UB, który będzie działał w większości przypadków (z pamięcią płaską jest to po prostu dodatek Jedynym sposobem, który może zawieść, jest to, że kompilator robi wszystko, aby go wykryć, a to oznacza, że ​​musiałby rozumować na temat rozmiarów dynamicznych). Oczywiście powyższy przypadek musi być wspierany przez kompilatory twierdzące, że wspierają wewnętrzne SSE, w przeciwnym razie nie można rozsądnie skorzystać z pobierania wstępnego, co zostało zademonstrowane w tej odpowiedzi (i jest jeszcze kilka dodatkowych gwarancji, które muszą wykonać na podstawie standardu).

* z podręcznika:

Dyspozycja PREFETCHh jest jedynie wskazówkę i nie wpływa na działanie programu.

Sygnał wpłynąłby na zachowanie programu, więc nie można ich wygenerować.

+0

Podczas tworzenia wskaźników out-of-bounds jest dobrze zachowana na typowych architekturach, jest prawdopodobne, że przyszłe kompilatory zakładają, że jeśli obliczyć wskaźnik, jest on ważny, a kompilator może usunąć je z wyprzedzeniem/spekulatywnie, co prowadzi do niezdefiniowania zachowanie, jeśli nie jest prawidłowe. – fuz

+0

Kompilatory IA64 na FUZxxl już to robią, ale jest w porządku. Mimo to nie może się tak złamać * co najmniej * w przypadku użycia tego wskaźnika do wstępnego pobierania, w przeciwnym razie byłby po prostu zepsuty. – harold

+0

UB? To jest sprzęt, a nie standard językowy. – doug65536