Некорректная трассировка стека в ядре по необработанному std :: exception

Вот мой код:

#include <string>
#include <tr1/functional>

using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;

class Event
{
public:
  typedef std::tr1::function<void()> Handler;

  void set(Handler h)
  {
    m_handler = h;
  }

  template<typename T, typename F>
  void set(T * obj, F memfn)
  {
    set(std::tr1::bind(memfn, obj));
  }

  void operator()()
  {
    m_handler();
  }

  static void fire(Event * event) throw ()
  {
    (*event)();
  }

  Handler m_handler;
};

class BuggyHandler
{
public:

  BuggyHandler()
  {
  }

  BuggyHandler(Event * b) :
      bar(b)
  {
    bar->set(this, &BuggyHandler::HandleEvent);
  }

  void HandleEvent()
  {
    // throw std::length_error
    std::string().append(std::numeric_limits<size_t>::max(), '0');
  }

private:

  Event * bar;
};

void get_correct_stacktrace()
{
  Event bar;
  BuggyHandler handler(&bar);
  bar();
}

void get_incorrect_stacktrace()
{
  Event bar;
  BuggyHandler handler(&bar);
  Event::fire(&bar);
}

int main(int argc, char **argv)
{
  int opt = atoi(argv[1]);
  if (opt)
    get_correct_stacktrace();
  else
    get_incorrect_stacktrace();
}

Когда я вызываю ./test 1, я могу получить правильную трассировку стека от ядра:

#0  0xffffe410 in __kernel_vsyscall ()
#1  0xf7d028d0 in raise () from /lib/libc.so.6
#2  0xf7d03ff3 in abort () from /lib/libc.so.6
#3  0xf7ede880 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib/libstdc++.so.6
#4  0xf7edc2a5 in std::exception::what () from /usr/lib/libstdc++.so.6
#5  0xf7edc2e2 in std::terminate () from /usr/lib/libstdc++.so.6
#6  0xf7edc41a in __cxa_throw () from /usr/lib/libstdc++.so.6
#7  0xf7e73c6f in std::__throw_length_error () from /usr/lib/libstdc++.so.6
#8  0xf7eb9a17 in std::string::append () from /usr/lib/libstdc++.so.6
#9  0x08049b96 in BuggyHandler::HandleEvent (this=0xffc26c9c) at /home/liangxu/release/server_2.0/test/src/test.cc:54
#10 0x08049857 in get_correct_stacktrace () at /home/liangxu/release/server_2.0/test/src/test.cc:67
#11 0x080498e0 in main (argc=Cannot access memory at address 0x5ac6) at /home/liangxu/release/server_2.0/test/src/test.cc:81

Расположение исключения броска - test.cc:54

Когда я вызываю ./test 0, я могу получить неверную трассировку стека от ядра:

#0  0xffffe410 in __kernel_vsyscall ()
#1  0xf7d508d0 in raise () from /lib/libc.so.6
#2  0xf7d51ff3 in abort () from /lib/libc.so.6
#3  0xf7f2c880 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib/libstdc++.so.6
#4  0xf7f2a2a5 in std::exception::what () from /usr/lib/libstdc++.so.6
#5  0xf7f2a2e2 in std::terminate () from /usr/lib/libstdc++.so.6
#6  0xf7f2a305 in std::exception::what () from /usr/lib/libstdc++.so.6
#7  0xf7f29d98 in __cxa_call_unexpected () from /usr/lib/libstdc++.so.6
#8  0x080497eb in get_incorrect_stacktrace () at /home/liangxu/release/server_2.0/test/src/test.cc:30
#9  0x080498f5 in main (argc=Cannot access memory at address 0x5adf) at /home/liangxu/release/server_2.0/test/src/test.cc:83

Нет места для исключения броска.

Мой компилятор - "gcc (GCC) 4.1.2 20070115 (предварительная версия) (SUSE Linux)"

Если скомпилировано с "-fno-exceptions", оба метода генерируют правильную трассировку стека.

В чем причина?

4 голоса | спросил lxu4net 5 Jam1000000amThu, 05 Jan 2012 09:59:59 +040012 2012, 09:59:59

1 ответ


0

Обе трассировки стека верны.

Когда вы вызываете Event::fire, в HandleEvent и раскрутка стека происходит до тех пор, пока не встретится fire со спецификацией исключения та .

Если вы не знаете реального поведения спецификаций исключений, вы можете прочитать об этом здесь: http://www.gotw.ca/publications/mill22.htm

По сути, спецификация throw () действительно гарантирует, что этот метод не вызывает сбои из-за неудачного завершения одного из содержащихся вызовов. Когда разматывание стека пытается выйти из этого метода, оно проверяет спецификацию исключения, обнаруживает, что оно не совпадает, и вызывает std::unexpected из текущее местоположение раскрутки, таким образом, __cxa_call_unexpected () в вашей трассировке стека сразу после get_incorrect_stacktrace ().

В большинстве случаев использование спецификаций исключений в C ++ бесполезно, потому что гарантия предоставляется за счет общего сбоя программы, который выдает и не должен.

ответил slaphappy 5 Jpm1000000pmThu, 05 Jan 2012 14:55:36 +040012 2012, 14:55:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132