2009-10-06 15 views
6

biegnę do problemu z floating point wyjątki włączone w Visual Studio 2005. Jeśli mam kod jak poniżej:zmiennoprzecinkowej postępowania z wyjątków zmiennoprzecinkowych stos włączony

double d = 0.0; 
    double d2 = 3.0; 
    double d3 = d2/d; 

i gdybym zarejestrować procedura obsługi SEH, a następnie mogę łatwo przekształcić div-by-zero w wyjątek C++ i go przechwycić. Jak na razie dobrze.

Jednak, gdy to zrobię, pierwszy operand (0.0 w powyższym przykładzie) pozostanie na stosie rejestru FPU. Jeśli zrobię to osiem razy, wtedy zacznę od tego momentu otrzymywać wyjątek sprawdzania stosu zmiennoprzecinkowego z KAŻDYM operatorem zmiennoprzecinkowym.

Mogę sobie z tym poradzić za pomocą bloku __asm, aby wykonać FSTP, odrywając w ten sposób zbłąkaną wartość ze stosu i wszystko jest w porządku.

Jednak to mnie martwi, ponieważ nie widziałem tego omawianego w dowolnym miejscu. Jak mogę być pewny liczby wartości, które powinienem wyskoczyć? Czy bezpiecznie jest po prostu wyskoczyć ze wszystkiego, co jest na stosie w momencie wyjątku? Czy są jakieś zalecane najlepsze praktyki w tej dziedzinie?

Dzięki!

+0

Czy dzieje się to również z SEH? jeśli nie zarejestrujesz obsługi SEH, czy zachowujesz się tak samo? –

+0

Dzieje się tak w wyniku wywołania funkcji _controlfp(), która demaskuje wyjątki, które mnie interesują (np. Div-by-zero). Nie sądzę, aby miało to znaczenie, jeśli mam zarejestrowany program obsługi SEH-a, ale jeśli nie, po prostu ulegam awarii z nieobsługiwanym wyjątkiem. –

Odpowiedz

3

Chociaż nie mogę znaleźć nic albo mogę dać pewne wyjaśnienia co do prawdopodobnej odpowiedzi:

ABI określa, że ​​na funkcję nazywamy stos powinien być pusty, a powinien on być pusty znów na wylocie chyba że return jest wartością zmiennoprzecinkową, gdzie byłby to jedyny przedmiot na stosie.

Ponieważ program obsługi wyjątku musi mieć możliwość powrotu do dowolnego miejsca, niektóre kryteria muszą obowiązywać w tych lokalizacjach. Pytanie tutaj brzmi: czy odwijacz stosu ma jakąkolwiek wiedzę o stosie FPU funkcji posiadającej catch()? Najprawdopodobniej odpowiedź brzmi nie, ponieważ łatwiej i szybciej tworzy się odpowiedni punkt zwrotny o ustalonych właściwościach niż włączenie pełnego stosu FPU do rozwijania.

Co prowadzi do twojego problemu - zwykle wychodząc z wyjątku kompilator dba o to, że FPU jest pusty, ale w programie obsługi SEH kompilator nie ma pojęcia, że ​​spowodował on wejście do innej funkcji, a zatem nie może wziąć dbanie o rzeczy na wszelki wypadek. (poza tym, że znowu jest ohydnie powolny)

Co oznacza, że ​​najprawdopodobniej po powrocie stos FPU powinien być w stanie "stałym", co oznacza, że ​​prawdopodobnie potrzebujesz odpowiednika instrukcji EMMS.

Dlaczego EMMS? No chyba, że ​​to nie jest obsługiwany wykonuje następujące:

  • jasne stos (który rozwiązuje wszystkie resztki pływających argumentów punktowych)
  • czyści stosie znaczników (które rozwiązuje bezużyteczny stos przy wychodzeniu z MMX-włączony funkcja)

Jeśli chcesz obsługiwać Pentium 1 lub gorzej, możesz oczywiście (+) wokół EMMS i użyć czegoś innego.

Oczywiście nie mam gwarancji, ale mam nadzieję, że wyjaśniłem wystarczająco prawdopodobne przyczyny odpowiedzi.

+0

To ma sens - doszedłem do tego samego wniosku. Dzięki. –

Powiązane problemy