Thread View: pl.comp.lang.c
5 messages
5 total messages
Started by Borneq
Fri, 11 Dec 2015 07:44
Jak są zaimplementowane wyjątki ?
Author: Borneq
Date: Fri, 11 Dec 2015 07:44
Date: Fri, 11 Dec 2015 07:44
91 lines
3174 bytes
3174 bytes
Kiedyś na tej grupie (w 2012 roku) był przykład z C implementującymi
wyjątki za pomocą setjmp/longjmp:
#include <setjmp.h>
#define finally else
/* Typy wyjątków */
#define DivisionByZero 1
#define MemoryAllocError 2
jmp_buf ex_buffer;
int ex_status;
#include <stdio.h>
int calc(int w)
{
if(w%2)
{
return 0;
} else
{
longjmp(ex_buffer, DivisionByZero);
}
}
int main(int argc, char* argv[])
{
int w = 2;
if ((ex_status = setjmp(ex_buffer)) == 0)
{
printf("Zwrócono %d\n", calc(w));
} else if (ex_status == DivisionByZero)
{
printf("Chwycono wyjątek\n");
}
return 0;
}
Ograniczeniem jest to, że chwyta tylko wysłane wyjątki, a nie wyjątki
maszynowe jak błąd dzielenia czy pamięci.
A jak gcc sobie radzi?
int main (void)
{
int n=5;
int d=0;
int g;
try
{
g = n/d;
throw "";
}
catch(...)
{
g=0;
}
return 0;
}
generuje :
.LC0:
.string ""
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 5
mov DWORD PTR [rbp-8], 0
mov eax, DWORD PTR [rbp-4]
cdq
idiv DWORD PTR [rbp-8]
mov DWORD PTR [rbp-12], eax
mov edi, 8
call __cxa_allocate_exception
mov QWORD PTR [rax], OFFSET FLAT:.LC0
mov edx, 0
mov esi, OFFSET FLAT:typeinfo for char const*
mov rdi, rax
call __cxa_throw
mov rdi, rax
call __cxa_begin_catch
mov DWORD PTR [rbp-12], 0
call __cxa_end_catch
mov eax, 0
leave
ret
Link do gcc.godbolt.org: https://goo.gl/0J8TUn
Tu po prostu zamiast skoków używa wywołań funkcji
__cxa_allocate_exception,__cxa_throw,__cxa_begin_catch,__cxa_end_catch
Trzeba by się przypatrzyć ich wnętrzu.
Ale uwaga - gdy w .c nie było throw, wtedy nie ma obsługi wyjątku mimo
dzielenia. Czyżby gcc nie potrafił obsługiwać tego typu wyjątków? Co się
stanie, gdy jednak będzie błąd dzielenia?
Re: Jak są zaimplementowane wyjątki ?
Author: Wiktor S.
Date: Fri, 11 Dec 2015 19:51
Date: Fri, 11 Dec 2015 19:51
125 lines
3669 bytes
3669 bytes
> Ale uwaga - gdy w .c nie było throw, wtedy nie ma obsługi wyjątku mimo
> dzielenia. Czyżby gcc nie potrafił obsługiwać tego typu wyjątków? Co
> się stanie, gdy jednak będzie błąd dzielenia?
Nie wiem jak GCC.
Wiem za to, że Visual C++ ma obsługę wyjątków SEH (Structured Exception
Handling), która pozwala na łapanie wyjątków systemowych i sprzętowych.
-------------------
/* to jest C */
#include <stdio.h>
#include <windows.h>
int dziel(int a, int b)
{
__try
{
return a/b;
}
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO)
{
return 0;
}
}
int main()
{
printf("%d\n", dziel(5,0));
}
-------------------
__sehtable$_dziel DD 0fffffffeH
DD 00H
DD 0ffffffd8H
DD 00H
DD 0fffffffeH
DD FLAT:$LN5@dziel
DD FLAT:$LN6@dziel
...
__$SEHRec$ = -24 ; size = 24
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_dziel PROC
; Line 5
push ebp
mov ebp, esp
push -2 ; fffffffeH
push OFFSET __sehtable$_dziel
push OFFSET __except_handler4
mov eax, DWORD PTR fs:0
push eax
sub esp, 8
push ebx
push esi
push edi
mov eax, DWORD PTR ___security_cookie
xor DWORD PTR __$SEHRec$[ebp+16], eax
xor eax, ebp
push eax
lea eax, DWORD PTR __$SEHRec$[ebp+8]
mov DWORD PTR fs:0, eax
mov DWORD PTR __$SEHRec$[ebp], esp
; Line 6
mov DWORD PTR __$SEHRec$[ebp+20], 0
; Line 8
mov eax, DWORD PTR _a$[ebp]
cdq
idiv DWORD PTR _b$[ebp]
mov DWORD PTR __$SEHRec$[ebp+20], -2 ; fffffffeH
; Line 14
mov ecx, DWORD PTR __$SEHRec$[ebp+8]
mov DWORD PTR fs:0, ecx
pop ecx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
$LN5@dziel:
; Line 10
mov eax, DWORD PTR __$SEHRec$[ebp+4]
mov ecx, DWORD PTR [eax]
mov eax, DWORD PTR [ecx]
xor edx, edx
cmp eax, -1073741676 ; c0000094H
sete dl
mov eax, edx
$LN7@dziel:
ret 0
$LN6@dziel:
mov esp, DWORD PTR __$SEHRec$[ebp]
; Line 12
mov DWORD PTR __$SEHRec$[ebp+20], -2 ; fffffffeH
xor eax, eax
; Line 14
mov ecx, DWORD PTR __$SEHRec$[ebp+8]
mov DWORD PTR fs:0, ecx
pop ecx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
_dziel ENDP
-------------------
Uch... dużo tego. Nie analizowałem dokładnie. Wygląda na to że pod
"magicznym" adresem fs:0 umieszczany jest wskaźnik na strukturę zawierającą
m.in. adresy callbacków - funkcji sprawdzającej czy wyjątek ma być obsłużony
i samego handlera.
Callbacki wywoływane są przez system operacyjny.
--
Wiktor S.
Re: Jak są zaimplementowane wyjątki ?
Author: Wojciech Muła
Date: Sat, 12 Dec 2015 06:24
Date: Sat, 12 Dec 2015 06:24
66 lines
3160 bytes
3160 bytes
On Friday, December 11, 2015 at 8:43:54 AM UTC+1, Borneq wrote:
> Trzeba by się przypatrzyć ich wnętrzu.
Możesz zacząć od tego:
https://monoinfinito.wordpress.com/series/exception-handling-in-c/
Widziałem kiedyś dobrą prezentację pokazującą szczegóły, ale nie potrafię
jej teraz znaleźć. W każdym razie kluczowa fraza to "0-overhead exceptions".
> Ale uwaga - gdy w .c nie było throw, wtedy nie ma obsługi wyjątku mimo
> dzielenia. Czyżby gcc nie potrafił obsługiwać tego typu wyjątków?
Nie, bo to są wyjątki sprzętowe. Które np. na unixach są konwertowane
na sygnały (a sygnały to Zło(TM)).
> Co się stanie, gdy jednak będzie błąd dzielenia?
Program się mniej lub bardziej elegancko wyłoży.
BTW, kilka lat temu przysłałem na tę grupę program zamieniający sygnał
na wyjątek C++, ale... to jest brzydkie i nie wiem nawet czemu działa. :)
Wrzucam jako ciekawostkę, można dodać do kategorii "perwersje".
---start---
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
jmp_buf toplevel;
void sigsegv(int dummy) {
longjmp(toplevel, 1);
}
void bug(char* cantread) {
char a = cantread[0xfffffff];
}
class SegmentationFault { };
int main(int argc, char* argv[]) {
if (signal(SIGSEGV, sigsegv) == SIG_ERR) {
return 2;
}
try {
if (!setjmp(toplevel)) {
puts("Próba wykonania niebezpiecznego kodu");
bug((char*)0xffffffff);
puts("Uff, powiod³o siê");
}
else {
throw SegmentationFault();
}
}
catch (SegmentationFault& s) {
puts("*** Segmentation Fault ***");
return 1;
}
puts("Ok!");
return 0;
}
---end---
w.
Re: Jak są zaimplementowane wyjątki ?
Author: Matt D.
Date: Mon, 14 Dec 2015 14:50
Date: Mon, 14 Dec 2015 14:50
23 lines
1738 bytes
1738 bytes
To dosc szeroki temat: Specyfikacja: https://mentorembedded.github.io/cxx-abi/abi-eh.html Opis: http://llvm.org/docs/ExceptionHandling.html http://blog.kevmod.com/2014/05/digging-into-exception-handling/ https://monoinfinito.wordpress.com/series/exception-handling-in-c/ http://www.deadp0rk.com/2013/09/22/base_abi/ http://www.deadp0rk.com/2013/09/27/c-exception-handling-level-ii-abi/ StackOverflow: https://stackoverflow.com/questions/16597350/what-is-an-exception-handling-personality-function https://stackoverflow.com/questions/20027156/llvm-exception-handling-implementation Zob. tez: https://mentorembedded.github.io/cxx-abi/exceptions.pdf https://github.com/MentorEmbedded/cxx-abi/blob/master/MIPSCompactEH.pdf Pozdrawiam, Matt
Re: Jak są zaimplementowane wyjątki ?
Author: Borneq
Date: Mon, 14 Aug 2017 06:25
Date: Mon, 14 Aug 2017 06:25
25 lines
2034 bytes
2034 bytes
W dniu 14.12.2015 o 15:50, Matt D. pisze: > Specyfikacja: > https://mentorembedded.github.io/cxx-abi/abi-eh.html > > Opis: > http://llvm.org/docs/ExceptionHandling.html > http://blog.kevmod.com/2014/05/digging-into-exception-handling/ > https://monoinfinito.wordpress.com/series/exception-handling-in-c/ > http://www.deadp0rk.com/2013/09/22/base_abi/ > http://www.deadp0rk.com/2013/09/27/c-exception-handling-level-ii-abi/ > > StackOverflow: > https://stackoverflow.com/questions/16597350/what-is-an-exception-handling-personality-function > > https://stackoverflow.com/questions/20027156/llvm-exception-handling-implementation > > > Zob. tez: > https://mentorembedded.github.io/cxx-abi/exceptions.pdf > https://github.com/MentorEmbedded/cxx-abi/blob/master/MIPSCompactEH.pdf Dzięki Matt. Jeśli chodzi o SEH, mają tę zaletę że również wyłapują sprzętowe błędy, nie tylko dzielenie przez zero, ale zapis pod zły adres, zamiast tylko działać na wyjątkach generowanych przez throw. Wada - wymagane wspomaganie systemu, brak przenośności.
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads