KEMBAR78
C++ exceptions | PDF
Исключения в С++
Как это устроено
Подзадачи:
1) Как передать управление
в нужный catch блок
2) Как обустроить раскрутку стека
Архитектура Int FP
x86-32 8 8
x86-64 16 16
IBM/360 16 4
z/Architecture 16 16
Itanium 128 128
SPARC 31 32
IBM Cell 4~16 1~4
IBM POWER 32 32
Power Architecture 32 32
Архитектура Int FP
Alpha 32 32
6502 3 0
W65C816S 5 0
PIC microcontroller 1 0
AVR microcontroller 32 0
ARM 32-bit[5]
16 varies
ARM 64-bit[6]
31 32
PDP-11 6 0
MIPS 31 32
<1>: DW_TAG_subprogram
DW_AT_name = foo
<2>: DW_TAG_variable
DW_AT_name = b
DW_AT_type = <4>
DW_AT_location = (DW_OP_reg0)
<3>: DW_TAG_variable
DW_AT_name = c
DW_AT_type = <4>
DW_AT_location = (DW_OP_fbreg: -12)
<4>: DW_TAG_base_type
DW_AT_name = int
DW_AT_byte_size = 4
DW_AT_encoding = signed
<5>: DW_TAG_variable
DW_AT_name = a
DW_AT_type = <4>
DW_AT_external = 1
DW_AT_location = (DW_OP_addr: 0)
1: int a;
2: void foo()
3: {
4: register int b;
5: int c;
6: }
DWARF:
http://www.dwarfstd.org/doc/Debugging%20using%20DWARF.pdf
0x00000083: TAG_formal_parameter [4]
AT_name( "x" )
AT_decl_file( "test.c" )
AT_decl_line( 1 )
AT_type( {0x0000005f} ( int ) )
AT_location( 0x00000000
0x00000000 - 0x00000003: ecx
0x00000003 - 0x00000018: ecx )
0x00000090: TAG_formal_parameter [4]
AT_name( "y" )
AT_decl_file( "test.c" )
AT_decl_line( 1 )
AT_type( {0x0000005f} ( int ) )
AT_location( 0x0000001e
0x00000000 - 0x00000003: edx
0x00000003 - 0x00000018: edx )
int mult (int x, int y) { return x*y; }dwarfdump:
http://stackoverflow.com/questions/12252176/getting-calling-conventions-from-dwarf-info
http://www.codeproject.com/Articles/2126/How-a-C-compiler-implements-exception-handling
http://www.codeproject.com/Articles/2126/How-a-C-compiler-implements-exception-handling
Раскручиваем стек сами
struct jmp_buf_splice {
jmp_buf_splice ();
~jmp_buf_splice ();
jmp_buf buf_;
jmp_buf_splice *prev_;
unw_item_t objs_;
};
try блок:
static jmp_buf_splice *root_slice_ = NULL;
jmp_buf_splice::jmp_buf_splice ()
{
objs_ = NULL;
prev_ = root_slice_;
root_slice_ = this;
}
jmp_buf_splice::~jmp_buf_splice ()
{
root_slice_ = prev_;
}
struct unw_item_t {
unw_item_t ();
virtual ~unw_item_t ();
void unreg();
unw_item_t *prev_;
};
unw_item_t::unw_item_t ()
{
if (NULL != root_slice_)
{
prev_ = root_slice_->objs_;
root_slice_->objs_ = this;
}
}
unw_item_t::~unw_item_t ()
{
if (NULL != root_slice_ &&
(prev_ != reinterpret_cast <unw_item_t *>(~ 0)))
{
root_slice_->objs_ = prev_;
prev_ = reinterpret_cast <unw_item_t *>(~ 0);
}
}
Само(раз)регистрирующийся элемент:
Собственно раскрутка стека:
int throw_slice ( const char *str)
{
jmp_buf_splice *sl = root_slice_;
unw_item_t *obj = root_slice_->objs_;
while (NULL != obj)
{
unw_item_t *tmp = obj;
obj = obj->prev_;
tmp->~unw_item_t ();
}
longjmp (sl->buf_, int(str));
return 0;
}
Пример
TRY_BLOCK {
vec_deleter_t<_A> da(new _A[3]);
TRY_BLOCK {
THROW_IN_BLOCK("errorn");
std::cerr << "notreachedn";
}
CATCH_BLOCK_FIN {
std::cerr << "." << __exc;
RETHROW_IN_BLOCK;
}
FIN_BLOCK;
std::cerr << "notreachedn";
}
CATCH_BLOCK_FIN {
std::cerr << ".." << __exc;
}
FIN_BLOCK;
A::A(1)
A::A(2)
A::A(3)
.error
A::~A(3)
A::~A(2)
A::~A(1)
..error
Чего не хватает?
● Нельзя бросать исключения в деструкторе
● Потокобезопасность отсутствует
● Экземпляр наследованного от unw_item_t класса может
быть только стековым
● Класс, наследованный от unw_item_t нельзя
агрегировать
● Метод не дружит с аппаратными исключениями
● Удалять брошенный объект-исключение должен тот, кто
его поймал

C++ exceptions

  • 1.
    Исключения в С++ Какэто устроено
  • 2.
    Подзадачи: 1) Как передатьуправление в нужный catch блок 2) Как обустроить раскрутку стека
  • 3.
    Архитектура Int FP x86-328 8 x86-64 16 16 IBM/360 16 4 z/Architecture 16 16 Itanium 128 128 SPARC 31 32 IBM Cell 4~16 1~4 IBM POWER 32 32 Power Architecture 32 32 Архитектура Int FP Alpha 32 32 6502 3 0 W65C816S 5 0 PIC microcontroller 1 0 AVR microcontroller 32 0 ARM 32-bit[5] 16 varies ARM 64-bit[6] 31 32 PDP-11 6 0 MIPS 31 32
  • 4.
    <1>: DW_TAG_subprogram DW_AT_name =foo <2>: DW_TAG_variable DW_AT_name = b DW_AT_type = <4> DW_AT_location = (DW_OP_reg0) <3>: DW_TAG_variable DW_AT_name = c DW_AT_type = <4> DW_AT_location = (DW_OP_fbreg: -12) <4>: DW_TAG_base_type DW_AT_name = int DW_AT_byte_size = 4 DW_AT_encoding = signed <5>: DW_TAG_variable DW_AT_name = a DW_AT_type = <4> DW_AT_external = 1 DW_AT_location = (DW_OP_addr: 0) 1: int a; 2: void foo() 3: { 4: register int b; 5: int c; 6: } DWARF: http://www.dwarfstd.org/doc/Debugging%20using%20DWARF.pdf
  • 5.
    0x00000083: TAG_formal_parameter [4] AT_name("x" ) AT_decl_file( "test.c" ) AT_decl_line( 1 ) AT_type( {0x0000005f} ( int ) ) AT_location( 0x00000000 0x00000000 - 0x00000003: ecx 0x00000003 - 0x00000018: ecx ) 0x00000090: TAG_formal_parameter [4] AT_name( "y" ) AT_decl_file( "test.c" ) AT_decl_line( 1 ) AT_type( {0x0000005f} ( int ) ) AT_location( 0x0000001e 0x00000000 - 0x00000003: edx 0x00000003 - 0x00000018: edx ) int mult (int x, int y) { return x*y; }dwarfdump: http://stackoverflow.com/questions/12252176/getting-calling-conventions-from-dwarf-info
  • 6.
  • 7.
  • 8.
    Раскручиваем стек сами structjmp_buf_splice { jmp_buf_splice (); ~jmp_buf_splice (); jmp_buf buf_; jmp_buf_splice *prev_; unw_item_t objs_; }; try блок: static jmp_buf_splice *root_slice_ = NULL; jmp_buf_splice::jmp_buf_splice () { objs_ = NULL; prev_ = root_slice_; root_slice_ = this; } jmp_buf_splice::~jmp_buf_splice () { root_slice_ = prev_; }
  • 9.
    struct unw_item_t { unw_item_t(); virtual ~unw_item_t (); void unreg(); unw_item_t *prev_; }; unw_item_t::unw_item_t () { if (NULL != root_slice_) { prev_ = root_slice_->objs_; root_slice_->objs_ = this; } } unw_item_t::~unw_item_t () { if (NULL != root_slice_ && (prev_ != reinterpret_cast <unw_item_t *>(~ 0))) { root_slice_->objs_ = prev_; prev_ = reinterpret_cast <unw_item_t *>(~ 0); } } Само(раз)регистрирующийся элемент:
  • 10.
    Собственно раскрутка стека: intthrow_slice ( const char *str) { jmp_buf_splice *sl = root_slice_; unw_item_t *obj = root_slice_->objs_; while (NULL != obj) { unw_item_t *tmp = obj; obj = obj->prev_; tmp->~unw_item_t (); } longjmp (sl->buf_, int(str)); return 0; }
  • 11.
    Пример TRY_BLOCK { vec_deleter_t<_A> da(new_A[3]); TRY_BLOCK { THROW_IN_BLOCK("errorn"); std::cerr << "notreachedn"; } CATCH_BLOCK_FIN { std::cerr << "." << __exc; RETHROW_IN_BLOCK; } FIN_BLOCK; std::cerr << "notreachedn"; } CATCH_BLOCK_FIN { std::cerr << ".." << __exc; } FIN_BLOCK; A::A(1) A::A(2) A::A(3) .error A::~A(3) A::~A(2) A::~A(1) ..error
  • 12.
    Чего не хватает? ●Нельзя бросать исключения в деструкторе ● Потокобезопасность отсутствует ● Экземпляр наследованного от unw_item_t класса может быть только стековым ● Класс, наследованный от unw_item_t нельзя агрегировать ● Метод не дружит с аппаратными исключениями ● Удалять брошенный объект-исключение должен тот, кто его поймал