Jakie jest znaczenie kodu wyjątku „EXC_I386_GPFLT”?

117

Jakie jest znaczenie kodu wyjątku EXC_I386_GPFLT?

Czy jego znaczenie różni się w zależności od sytuacji?

W takim przypadku odnoszę się do typu EXC_BAD_ACCESSwyjątku z kodem wyjątkuEXC_I386_GPFLT

Program został napisany w Xcode 5.0.1, zajmującym się cblas_zgemm()biblioteką BLAS (cóż, chyba nie ma to znaczenia ...)

Dziękuję Ci bardzo!

Lewen
źródło

Odpowiedzi:

112

EXC_I386_GPFLT z pewnością odnosi się do „ogólnego błędu ochrony”, który jest sposobem x86, aby powiedzieć ci, że „zrobiłeś coś, czego nie możesz zrobić”. Zwykle NIE oznacza to, że uzyskujesz dostęp poza granicami pamięci, ale może się zdarzyć, że twój kod wykracza poza granice i powoduje, że zły kod / dane są używane w sposób, który powoduje pewnego rodzaju naruszenie ochrony.

Niestety, bez szerszego kontekstu może być trudno ustalić dokładnie, na czym polega problem, jest 27 różnych przyczyn wymienionych w moim Podręczniku programisty AMD64, tom 2 z 2005 r. - według wszystkich relacji jest prawdopodobne, że 8 lat później dodałoby kilka więcej.

Jeśli jest to system 64-bitowy, prawdopodobny scenariusz jest taki, że Twój kod używa „niekanonicznego wskaźnika” - co oznacza, że ​​adres 64-bitowy jest utworzony w taki sposób, że górne 16 bitów adresu nie jest wszystkie kopie górnych 48 niższych bitów (innymi słowy, wszystkie 16 górnych bitów adresu powinno mieć wartość 0 lub wszystkie 1, na podstawie bitu nieco poniżej 16 bitów). Ta reguła ma na celu zagwarantowanie, że architektura może „bezpiecznie rozszerzyć liczbę ważnych bitów w zakresie adresów”. Oznaczałoby to, że kod albo nadpisuje niektóre dane wskaźnika innymi rzeczami, albo wychodzi poza granice podczas odczytywania wartości wskaźnika.

Inną prawdopodobną przyczyną jest dostęp bez wyrównania z rejestrem SSE - innymi słowy, odczyt 16-bajtowego rejestru SSE z adresu, który nie jest wyrównany do 16-bajtów.

Jest, jak powiedziałem, wiele innych możliwych powodów, ale większość z nich dotyczy rzeczy, których „normalny” kod nie wykonywałby w 32- lub 64-bitowym systemie operacyjnym (takich jak ładowanie rejestrów segmentu z nieprawidłowym indeksem selektora lub zapisywanie do MSR (rejestry specyficzne dla modelu)).

Mats Petersson
źródło
24

Aby debugować i znaleźć źródło: Włącz Zombies dla aplikacji (Produkt \ Schemat) i Uruchom instrumenty, Wybierz Zombie. Uruchom aplikację w Xcode Następnie przejdź do Instrumenty rozpocznij nagrywanie. Wróć do aplikacji i spróbuj wygenerować błąd. Instrumenty powinny wykrywać złe połączenie (do zombie), jeśli takie istnieje.

Mam nadzieję, że to pomoże!

Khalid Mammadov
źródło
23

Często można uzyskać informacje z plików nagłówkowych. Na przykład:

$ cd /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk
$ find usr -name \*.h -exec fgrep -l EXC_I386_GPFLT {} \;
usr/include/mach/i386/exception.h
^C
$ more usr/include/mach/i386/exception.h
....
#define EXC_I386_GPFLT          13      /* general protection fault     */

OK, więc jest to ogólny błąd ochrony (jak sama nazwa wskazuje). Wygooglowanie „i386 general protection fault” daje wiele trafień, ale wygląda to interesująco:

Ochrona pamięci jest również realizowana za pomocą deskryptorów segmentów. Najpierw procesor sprawdza, czy wartość załadowana do rejestru segmentowego odwołuje się do prawidłowego deskryptora. Następnie sprawdza, czy każdy obliczony adres liniowy faktycznie znajduje się w segmencie. Ponadto typ dostępu (odczyt, zapis lub wykonanie) jest sprawdzany z informacjami w deskryptorze segmentu. Za każdym razem, gdy jedna z tych kontroli nie powiedzie się, zgłaszany jest wyjątek (przerwanie) 13 (szesnastkowo 0D). Ten wyjątek nazywany jest ogólnym błędem ochrony (GPF).

To 13pasuje do tego, co widzieliśmy w plikach nagłówkowych, więc wygląda to tak samo. Jednak z punktu widzenia programisty aplikacji oznacza to po prostu, że odwołujemy się do pamięci, której nie powinniśmy, i tak naprawdę nie ma znaczenia, w jaki sposób jest ona zaimplementowana na sprzęcie.

trojanfoe
źródło
1
Jednak współczesne systemy operacyjne nie używają segmentów do ochrony pamięci w ogóle. Wszystko to odbywa się za pomocą MMU i prowadziłoby do PF, wektora 14 (zwykle wyświetlane jako „Błąd segmentacji”).
Mats Petersson
16

Zastanawiałem się, dlaczego pojawiło się to podczas moich testów jednostkowych.

Dodałem deklarację metody do protokołu, który zawierał throws ; ale metoda potencjalnie rzucania nie była nawet używana w tym konkretnym teście. Włączenie Zombie w teście brzmiało jak zbyt duży problem.

Okazuje się, że czystość cleanK załatwiła sprawę. Zawsze jestem oszołomiony, gdy rozwiązuje to rzeczywiste problemy.

ctietze
źródło
Naprawiło to również dla mnie w Swift. Dzięki!
lwdthe1
8

Miałem podobny wyjątek w Swift 4.2. Spędziłem około pół godziny próbując znaleźć błąd w moim kodzie, ale problem zniknął po zamknięciu Xcode i usunięciu folderu danych pochodnych. Oto skrót:

rm -rf ~/Library/Developer/Xcode/DerivedData
Stanislau Baranouski
źródło
2

W moim przypadku błąd został wyrzucony w Xcode podczas uruchamiania aplikacji na symulatorze iOS. Chociaż nie potrafię odpowiedzieć na konkretne pytanie „co oznacza błąd”, mogę powiedzieć, co mi pomogło, może pomaga też innym.

Rozwiązaniem dla mnie było Erase All Content and Settingsw symulatorze i Clean Build Folder...w Xcode.

Manuel
źródło
1

Miałem ten problem podczas wychodzenia z widoku (wróć do poprzedniego widoku).

powód był taki

addSubview(view)
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    view.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
    view.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
    view.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
    view.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)
])

Zmień safeAreaLayoutGuidenaself rozwiązać problem.

Znaczenie dopasowuje widok do wiodącego, końcowego, górnego, dolnego widoku superwizora zamiast do bezpiecznego obszaru)

nuynait
źródło
0

Przydarzyło mi się to, ponieważ Xcode nie lubił mnie, używając tej samej nazwy zmiennej w dwóch różnych klasach (które są zgodne z tym samym protokołem, jeśli ma to znaczenie, chociaż nazwa zmiennej nie ma nic związanego z żadnym protokołem). Po prostu zmieniłem nazwę mojej nowej zmiennej.

Musiałem wejść do seterów, w których dochodziło do awarii, aby to zobaczyć podczas debugowania. Ta odpowiedź dotyczy iOS

Stephen J.
źródło
0

Jeśli błąd zostanie zgłoszony w zamknięciu, które definiuje selfjako unowned, możesz mieć ograniczone możliwości dostępu i otrzymasz ten kod błędu w pewnych sytuacjach. Zwłaszcza podczas debugowania. Jeśli tak jest, spróbuj zmienić [unowned self]na[weak self]

Matjan
źródło
0

Otrzymałem ten błąd podczas robienia tego:

 NSMutableDictionary *aDictionary=[[NSMutableDictionary alloc] initWithObjectsAndKeys:<#(nonnull id), ...#>, nil]; //with 17 objects and keys

Odeszło, kiedy wróciłem do:

NSMutableDictionary *aDictionary=[[NSMutableDictionary alloc] init];
[aDictionary setObject:object1 forKey:@"Key1"]; //17 times
Peter B. Kramer
źródło
0

Dla mnie jest to kwestia związana ze scenorysem, jest opcja kompilacji ViewController na zestaw iOS 9.0 i późniejszy wcześniej ustawiony na iOS 10.0 i nowsze. Właściwie chcę obniżyć wersję ver z 10 do iOS 9.3.

Anil Kumar
źródło