Информация о трассировке отличается на MacOS и Linux - PullRequest
0 голосов
/ 08 октября 2018

Это тестовый код на C ++ (адаптированный из поста StackOverflow, но я не смог его найти):

#include <signal.h>    
#include <stdio.h>
#include <stdlib.h>

#include <execinfo.h>
#include <unistd.h>

void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

void baz() {
  int *foo = (int*)-1; // make a bad pointer
  printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler
  foo(); // this will call foo, bar, and baz.  baz segfaults.
}

Это этап компиляции и компоновки (в macOS g++ выполняется на самом делеclang++):

g++ backtrace_example.cc -c -O0
g++ -rdynamic backtrace_example.o -o bt_example

Это информация об обратном следе, напечатанная в macOS:

$ ./bt_example
Error: signal 11:
0   bt_example                          0x000000010dd39dbf handler + 31
1   libsystem_platform.dylib            0x00007fff5e0b7b3d _sigtramp + 29
2   ???                                 0x0000000117f6a7c7 0x0 + 4697008071
3   bt_example                          0x000000010dd39eb9 _Z3barv + 9
4   bt_example                          0x000000010dd39ec9 _Z3foov + 9
5   bt_example                          0x000000010dd39efe main + 46
6   libdyld.dylib                       0x00007fff5dece085 start + 1
7   ???                                 0x0000000000000001 0x0 + 1

Это информация об обратном следе, напечатанная в Linux:

$ ./bt_example
Error: signal 11:
./bt_example(handler+0x2b)[0x400982]
/lib/x86_64-linux-gnu/libc.so.6(+0x354b0)[0x7f2aefc534b0]
./bt_example(_Z3bazv+0x14)[0x4009db]
./bt_example(_Z3barv+0x9)[0x4009fa]
./bt_example(_Z3foov+0x9)[0x400a06]
./bt_example(main+0x23)[0x400a2c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f2aefc3e830]
./bt_example(_start+0x29)[0x4008a9]

Помимо различий в форматах, есть ключевое отличие: версия macOS вообще не упоминает функцию baz(), но очевидно, что ошибка вызвана baz().

Почему?Является ли это недостатком реализации macOS backtrace_symbol_fd(), или она предназначена (если да, то как)?

Ссылка: документация GNU по следам glibc .macOS - это другая ОС, имеющая собственную библиотеку C, но в этом отношении она имеет тот же API-интерфейс для обратного отслеживания, начиная с 10.5.

1 Ответ

0 голосов
/ 08 октября 2018

Во-первых, ни одна из функций, которые вы вызываете в вашем handler, не подходит для вызова из обработчика сигнала.Таким образом, вы полностью находитесь на неопределенной территории поведения.

Во-вторых, это не столько недостаток в backtrace, сколько просто разница в механизмах обработки сигналов в двух ОС.macOS временно изменяет стек, пока он вызывает обработчик сигнала.Он сохранил достаточную контекстную информацию, чтобы восстановить ее, если обработчик сигнала вернется (и обработчик даже имеет возможность изменить ее).Вы можете увидеть реализацию здесь .

...