我正在尝试使用clang manual中的-ftrap-function标志来捕获自定义处理程序中的CFI(call frame information)错误。

这是生成CFI错误的基本示例:

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

__attribute__((used)) extern "C" void CatchCfi() {
  printf("catched\n");
}

struct Foo {
  Foo(const char* s) : command(s) {}
  virtual ~Foo() {}

  void fooStuff() { printf("fooStuff\n"); }

  const char* command;
};

struct Bar {
  Bar(const char* s) : name(s) {}
  virtual ~Bar() {}

  void barStuff() { printf("barStuff\n"); }

  const char* name;
};

enum class WhichObject { FooObject, BarObject };

static void* allocator(WhichObject w, const char* arg) {
  switch (w) {
    case WhichObject::FooObject:
      return new Foo(arg);
    case WhichObject::BarObject:
      return new Bar(arg);
  }
}

int main(int argc, const char* argv[]) {
  void* ptr = nullptr;
  (void)(argc);
  (void)(argv);

  ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");

  Foo* fooptr = static_cast<Foo*>(ptr);
  fooptr->fooStuff();

  printf("not printed when compiled with -O2\n");
  return 0;
}

我使用以下与CFI相关的clang选项进行构建:
-ftrap-function=CatchCfi -fsanitize=cfi-vcall -fvisibility=hidden -fsanitize=cfi-derived-cast -fsanitize=cfi-unrelated-cast -flto=thin

当构建本示例而不进行优化时,它可以按我的要求工作。输出:
catched
fooStuff
not printed when compiled with -O2

当我使用-O2选项构建它时,会出现问题:
catched
Trace/breakpoint trap (core dumped)

GDB显示,在CatchCfi返回后,程序正在接收SIGTRAP:
(gdb) r
Starting program: /home/romex/browser/src/out/debug/hello_cfi
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
catched

Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000000020118a in ?? ()
(gdb) bt
#0  0x000000000020118a in ?? ()
#1  0x00000000002010f0 in frame_dummy ()
#2  0x00007ffff748e830 in __libc_start_main (main=0x201180 <main(int, char const**)>, argc=1, argv=0x7fffffffde18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7fffffffde08) at ../csu/libc-start.c:291
#3  0x0000000000201029 in _start ()
Warning: the current language does not match this frame.
(gdb)

如何解决?
我想知道是否有人有一个成功的故事,关于功能陷阱标志?可能有一些特定的优化标志修复了此错误?
谢谢。

最佳答案

我已经更新了您的代码,因此可以正常工作。我的环境没有引发SIGTRAP,因此我插入了__builtin_trap()调用。如@YSC所述,它是UB。陷阱函数返回后,程序无法继续执行,必须在引发SIGTRAP之前将程序还原到众所周知的良好状态。

#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

jmp_buf env;

__attribute__((used)) extern "C" void CatchCfi() {
  printf("catched\n");
  longjmp(env, 1);
}

struct Foo {
  Foo(const char* s) : command(s) {}
  virtual ~Foo() {}

  void fooStuff() { printf("fooStuff\n"); }

  const char* command;
};

struct Bar {
  Bar(const char* s) : name(s) {}
  virtual ~Bar() {}

  void barStuff() { printf("barStuff\n"); }

  const char* name;
};

enum class WhichObject { FooObject, BarObject };

static void* allocator(WhichObject w, const char* arg) {
  switch (w) {
    case WhichObject::FooObject:
      return new Foo(arg);
    case WhichObject::BarObject:
      return new Bar(arg);
  }
}

int main(int argc, const char* argv[]) {
  void* ptr = nullptr;
  (void)(argc);
  (void)(argv);

  ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")");

  int val = setjmp(env);

  if (!val) {
    Foo* fooptr = static_cast<Foo*>(ptr);
    fooptr->fooStuff();
    __builtin_trap();
  }

  printf("not printed when compiled with -O2\n");
  return 0;
}

关于c++ - clang-linux:报告CFI错误而不会崩溃。陷阱函数和-O2,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46274534/

10-13 03:35