使用LLVM进行整数溢出陷阱?

时间:2019-05-16 22:24:29

标签: llvm undefined-behavior llvm-ir integer-overflow

我正在创建静态编译的编程语言,并且使用LLVM作为其后端。我希望每当整数溢出发生时,我的语言就会陷入陷阱/崩溃。

我知道类似llvm.sadd.with.overflow之类的东西,但是我认为这不是最佳/有效的解决方案。该函数将返回两个值的结构,而不仅仅是让我直接访问OF寄存器标志。理想情况下,每次算术运算后,只要整数溢出,我都将有一个“ JO”汇编指令来捕获。这正是clang的UndefinedBehaviorSanitizer所做的。但是,我正在编译为LLVM IR,而不是C或C ++。

如何直接在LLVM IR中使用UndefinedBehaviorSanitizer(或完成等效的工作)来处理整数溢出?

1 个答案:

答案 0 :(得分:3)

  

我知道llvm.sadd.with.overflow之类的东西,但我认为这不是最佳/有效的解决方案。理想情况下,在每次算术运算之后,只要有整数溢出,我都将有一条“ JO”汇编指令来捕获。这正是clang的UndefinedBehaviorSanitizer所做的。

UndefinedBehaviorSanitizer的作用是生成对llvm.sadd.with.overflow的调用。您可以通过使用-fsanitize=undefined编译以下C程序并查看生成的LLVM代码来轻松验证这一点:

bla.c:

#include <stdio.h>

int main(void){
  int x;
  scanf("%d", &x);
  printf("%d\n", x+1);
  return 0;
}

命令行:

clang -fsanitize=undefined -emit-llvm -O2 -S bla.c

bla.ll(摘录):

  %5 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %4, i32 1), !nosanitize !8
  %6 = extractvalue { i32, i1 } %5, 0, !nosanitize !8
  %7 = extractvalue { i32, i1 } %5, 1, !nosanitize !8
  br i1 %7, label %8, label %10, !prof !9, !nosanitize !8

; <label>:8:                                      ; preds = %0
  %9 = zext i32 %4 to i64, !nosanitize !8
  call void @__ubsan_handle_add_overflow(i8* bitcast ({ { [6 x i8]*, i32, i32 }, { i16, i16, [6 x i8] }* }* @1 to i8*), i64 %9, i64 1) #5, !nosanitize !8

sadd.with.overflow将最终成为常规的incl指令¹,而br i1 %7最终将成为生成的x64程序集中的jo,所以这正是您想要的。


¹当然,如果我在C代码中添加了非1的内容,那将是正确的添加指令。