[llvm-dev] How does -fsanitize=address work under the hood?

Peng Yu via llvm-dev llvm-dev at lists.llvm.org
Tue Apr 13 07:42:28 PDT 2021


Hi,

I am trying to see what -fsanitize=address does using the following
example. I see a number of _asan function and variables. But it is
still not clear how the original program is transformed so that memory
error will be catched. Could anybody help explain how it works?
Thanks.

Also, many functions (like __asan_report_load16) are not used. Why are
they declared? Thanks.

$ diff <(clang -Wno-array-bounds -S -emit-llvm -x c -o - - <<< 'int
main() { int a[2] = {1, 0}; int b=a[2]; return 0; }') <(clang
-Wno-array-bounds -fsanitize=address -S -emit-llvm -x c -o - -<<< 'int
main() { int a[2] = {1, 0}; int b=a[2]; return 0; }')
< @__const.main.a = private unnamed_addr constant [2 x i32] [i32 1,
i32 0], align 4
< ; Function Attrs: noinline nounwind optnone ssp uwtable
---
> @__const.main.a = internal constant { [2 x i32], [56 x i8] } { [2 x i32] [i32 1, i32 0], [56 x i8] zeroinitializer }, align 32
> @__asan_option_detect_stack_use_after_return = external global i32
> @___asan_gen_ = private unnamed_addr constant [11 x i8] c"1 32 8 1 a\00", align 1
> @___asan_gen_.1 = private constant [2 x i8] c"-\00", align 1
> @___asan_gen_.2 = private unnamed_addr constant [15 x i8] c"__const.main.a\00", align 1
> @__asan_global___const.main.a = internal global { i64, i64, i64, i64, i64, i64, i64, i64 } { i64 ptrtoint ({ [2 x i32], [56 x i8] }* @__const.main.a to i64), i64 8, i64 64, i64 ptrtoint ([15 x i8]* @___asan_gen_.2 to i64), i64 ptrtoint ([2 x i8]* @___asan_gen_.1 to i64), i64 0, i64 0, i64 -1 }, section "__DATA,__asan_globals,regular"
> @__asan_binder___const.main.a = internal global { i64, i64 } { i64 ptrtoint ({ [2 x i32], [56 x i8] }* @__const.main.a to i64), i64 ptrtoint ({ i64, i64, i64, i64, i64, i64, i64, i64 }* @__asan_global___const.main.a to i64) }, section "__DATA,__asan_liveness,regular,live_support"
> @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast ({ [2 x i32], [56 x i8] }* @__const.main.a to i8*), i8* bitcast ({ i64, i64 }* @__asan_binder___const.main.a to i8*)], section "llvm.metadata"
> @___asan_globals_registered = common hidden global i64 0
> @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* null }]
> @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_dtor, i8* null }]
> ; Function Attrs: noinline nounwind optnone sanitize_address ssp uwtable
9,17c19,121
<   %1 = alloca i32, align 4
<   %2 = alloca [2 x i32], align 4
<   %3 = alloca i32, align 4
<   store i32 0, i32* %1, align 4
<   %4 = bitcast [2 x i32]* %2 to i8*
<   call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %4, i8* align 4
bitcast ([2 x i32]* @__const.main.a to i8*), i64 8, i1 false)
<   %5 = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 0, i64 2
<   %6 = load i32, i32* %5, align 4
<   store i32 %6, i32* %3, align 4
---
> entry:
>   %retval = alloca i32, align 4
>   %b = alloca i32, align 4
>   %asan_local_stack_base = alloca i64
>   %0 = load i32, i32* @__asan_option_detect_stack_use_after_return
>   %1 = icmp ne i32 %0, 0
>   br i1 %1, label %2, label %4
>
> 2:                                                ; preds = %entry
>   %3 = call i64 @__asan_stack_malloc_0(i64 64)
>   br label %4
>
> 4:                                                ; preds = %entry, %2
>   %5 = phi i64 [ 0, %entry ], [ %3, %2 ]
>   %6 = icmp eq i64 %5, 0
>   br i1 %6, label %7, label %9
>
> 7:                                                ; preds = %4
>   %MyAlloca = alloca i8, i64 64, align 32
>   %8 = ptrtoint i8* %MyAlloca to i64
>   br label %9
>
> 9:                                                ; preds = %4, %7
>   %10 = phi i64 [ %5, %4 ], [ %8, %7 ]
>   store i64 %10, i64* %asan_local_stack_base
>   %11 = add i64 %10, 32
>   %12 = inttoptr i64 %11 to [2 x i32]*
>   %13 = inttoptr i64 %10 to i64*
>   store i64 1102416563, i64* %13
>   %14 = add i64 %10, 8
>   %15 = inttoptr i64 %14 to i64*
>   store i64 ptrtoint ([11 x i8]* @___asan_gen_ to i64), i64* %15
>   %16 = add i64 %10, 16
>   %17 = inttoptr i64 %16 to i64*
>   store i64 ptrtoint (i32 ()* @main to i64), i64* %17
>   %18 = lshr i64 %10, 3
>   %19 = or i64 %18, 17592186044416
>   %20 = add i64 %19, 0
>   %21 = inttoptr i64 %20 to i64*
>   store i64 -868082052615769615, i64* %21, align 1
>   store i32 0, i32* %retval, align 4
>   %22 = bitcast [2 x i32]* %12 to i8*
>   %23 = add i64 %19, 4
>   %24 = inttoptr i64 %23 to i8*
>   store i8 0, i8* %24, align 1
>   call void @llvm.lifetime.start.p0i8(i64 8, i8* %22) #2
>   %25 = bitcast [2 x i32]* %12 to i8*
>   %26 = call i8* @__asan_memcpy(i8* %25, i8* bitcast ({ [2 x i32], [56 x i8] }* @__const.main.a to i8*), i64 8)
>   %27 = bitcast i32* %b to i8*
>   call void @llvm.lifetime.start.p0i8(i64 4, i8* %27) #2
>   %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %12, i64 0, i64 2
>   %28 = ptrtoint i32* %arrayidx to i64
>   %29 = lshr i64 %28, 3
>   %30 = or i64 %29, 17592186044416
>   %31 = inttoptr i64 %30 to i8*
>   %32 = load i8, i8* %31
>   %33 = icmp ne i8 %32, 0
>   br i1 %33, label %34, label %40, !prof !4
>
> 34:                                               ; preds = %9
>   %35 = and i64 %28, 7
>   %36 = add i64 %35, 3
>   %37 = trunc i64 %36 to i8
>   %38 = icmp sge i8 %37, %32
>   br i1 %38, label %39, label %40
>
> 39:                                               ; preds = %34
>   call void @__asan_report_load4(i64 %28)
>   call void asm sideeffect "", ""()
>   unreachable
>
> 40:                                               ; preds = %34, %9
>   %41 = load i32, i32* %arrayidx, align 4
>   store i32 %41, i32* %b, align 4
>   %42 = bitcast i32* %b to i8*
>   call void @llvm.lifetime.end.p0i8(i64 4, i8* %42) #2
>   %43 = bitcast [2 x i32]* %12 to i8*
>   %44 = add i64 %19, 4
>   %45 = inttoptr i64 %44 to i8*
>   store i8 -8, i8* %45, align 1
>   call void @llvm.lifetime.end.p0i8(i64 8, i8* %43) #2
>   store i64 1172321806, i64* %13
>   %46 = icmp ne i64 %5, 0
>   br i1 %46, label %47, label %54
>
> 47:                                               ; preds = %40
>   %48 = add i64 %19, 0
>   %49 = inttoptr i64 %48 to i64*
>   store i64 -723401728380766731, i64* %49, align 1
>   %50 = add i64 %5, 56
>   %51 = inttoptr i64 %50 to i64*
>   %52 = load i64, i64* %51
>   %53 = inttoptr i64 %52 to i8*
>   store i8 0, i8* %53
>   br label %57
>
> 54:                                               ; preds = %40
>   %55 = add i64 %19, 0
>   %56 = inttoptr i64 %55 to i64*
>   store i64 0, i64* %56, align 1
>   br label %57
>
> 57:                                               ; preds = %54, %47
20a125,126
> declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
> ; Function Attrs: argmemonly nounwind willreturn
21a128,235
> ; Function Attrs: argmemonly nounwind willreturn
> declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
> declare void @__asan_report_load_n(i64, i64)
> declare void @__asan_loadN(i64, i64)
> declare void @__asan_report_load1(i64)
> declare void @__asan_load1(i64)
> declare void @__asan_report_load2(i64)
> declare void @__asan_load2(i64)
> declare void @__asan_report_load4(i64)
> declare void @__asan_load4(i64)
> declare void @__asan_report_load8(i64)
> declare void @__asan_load8(i64)
> declare void @__asan_report_load16(i64)
> declare void @__asan_load16(i64)
> declare void @__asan_report_store_n(i64, i64)
> declare void @__asan_storeN(i64, i64)
> declare void @__asan_report_store1(i64)
> declare void @__asan_store1(i64)
> declare void @__asan_report_store2(i64)
> declare void @__asan_store2(i64)
> declare void @__asan_report_store4(i64)
> declare void @__asan_store4(i64)
> declare void @__asan_report_store8(i64)
> declare void @__asan_store8(i64)
> declare void @__asan_report_store16(i64)
> declare void @__asan_store16(i64)
> declare void @__asan_report_exp_load_n(i64, i64, i32)
> declare void @__asan_exp_loadN(i64, i64, i32)
> declare void @__asan_report_exp_load1(i64, i32)
> declare void @__asan_exp_load1(i64, i32)
> declare void @__asan_report_exp_load2(i64, i32)
> declare void @__asan_exp_load2(i64, i32)
> declare void @__asan_report_exp_load4(i64, i32)
> declare void @__asan_exp_load4(i64, i32)
> declare void @__asan_report_exp_load8(i64, i32)
> declare void @__asan_exp_load8(i64, i32)
> declare void @__asan_report_exp_load16(i64, i32)
> declare void @__asan_exp_load16(i64, i32)
> declare void @__asan_report_exp_store_n(i64, i64, i32)
> declare void @__asan_exp_storeN(i64, i64, i32)
> declare void @__asan_report_exp_store1(i64, i32)
> declare void @__asan_exp_store1(i64, i32)
> declare void @__asan_report_exp_store2(i64, i32)
> declare void @__asan_exp_store2(i64, i32)
> declare void @__asan_report_exp_store4(i64, i32)
> declare void @__asan_exp_store4(i64, i32)
> declare void @__asan_report_exp_store8(i64, i32)
> declare void @__asan_exp_store8(i64, i32)
> declare void @__asan_report_exp_store16(i64, i32)
> declare void @__asan_exp_store16(i64, i32)
> declare i8* @__asan_memmove(i8*, i8*, i64)
> declare i8* @__asan_memcpy(i8*, i8*, i64)
> declare i8* @__asan_memset(i8*, i32, i64)
> declare void @__asan_handle_no_return()
> declare void @__sanitizer_ptr_cmp(i64, i64)
> declare void @__sanitizer_ptr_sub(i64, i64)
> declare i64 @__asan_stack_malloc_0(i64)
> declare void @__asan_stack_free_0(i64, i64)
> declare i64 @__asan_stack_malloc_1(i64)
> declare void @__asan_stack_free_1(i64, i64)
> declare i64 @__asan_stack_malloc_2(i64)
> declare void @__asan_stack_free_2(i64, i64)
> declare i64 @__asan_stack_malloc_3(i64)
> declare void @__asan_stack_free_3(i64, i64)
> declare i64 @__asan_stack_malloc_4(i64)
> declare void @__asan_stack_free_4(i64, i64)
> declare i64 @__asan_stack_malloc_5(i64)
> declare void @__asan_stack_free_5(i64, i64)
> declare i64 @__asan_stack_malloc_6(i64)
> declare void @__asan_stack_free_6(i64, i64)
> declare i64 @__asan_stack_malloc_7(i64)
> declare void @__asan_stack_free_7(i64, i64)
> declare i64 @__asan_stack_malloc_8(i64)
> declare void @__asan_stack_free_8(i64, i64)
> declare i64 @__asan_stack_malloc_9(i64)
> declare void @__asan_stack_free_9(i64, i64)
> declare i64 @__asan_stack_malloc_10(i64)
> declare void @__asan_stack_free_10(i64, i64)
> declare void @__asan_poison_stack_memory(i64, i64)
> declare void @__asan_unpoison_stack_memory(i64, i64)
> declare void @__asan_set_shadow_00(i64, i64)
> declare void @__asan_set_shadow_f1(i64, i64)
> declare void @__asan_set_shadow_f2(i64, i64)
> declare void @__asan_set_shadow_f3(i64, i64)
> declare void @__asan_set_shadow_f5(i64, i64)
> declare void @__asan_set_shadow_f8(i64, i64)
> declare void @__asan_alloca_poison(i64, i64)
> declare void @__asan_allocas_unpoison(i64, i64)
> declare void @__asan_before_dynamic_init(i64)
> declare void @__asan_after_dynamic_init()
> declare void @__asan_register_globals(i64, i64)
> declare void @__asan_unregister_globals(i64, i64)
> declare void @__asan_register_image_globals(i64)
> declare void @__asan_unregister_image_globals(i64)
> declare void @__asan_register_elf_globals(i64, i64, i64)
> declare void @__asan_unregister_elf_globals(i64, i64, i64)
> declare void @__asan_init()
> define internal void @asan.module_ctor() {
>   call void @__asan_init()
>   call void @__asan_version_mismatch_check_apple_clang_1200()
>   call void @__asan_register_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
>   ret void
> }
> declare void @__asan_version_mismatch_check_apple_clang_1200()
> define internal void @asan.module_dtor() {
>   call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))
>   ret void
> }
23c237
< attributes #0 = { noinline nounwind optnone ssp uwtable
"correctly-rounded-divide-sqrt-fp-math"="false"
"darwin-stkchk-strong-link" "disable-tail-calls"="false"
"frame-pointer"="all" "less-precise-fpmad"="false"
"min-legal-vector-width"="0" "no-infs-fp-math"="false"
"no-jump-tables"="false" "no-nans-fp-math"="false"
"no-signed-zeros-fp-math"="false" "no-trapping-math"="false"
"probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8"
"target-cpu"="penryn"
"target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87"
"unsafe-fp-math"="false" "use-soft-float"="false" }
---
> attributes #0 = { noinline nounwind optnone sanitize_address ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
24a239
> attributes #2 = { nounwind }
32a248
> !4 = !{!"branch_weights", i32 1, i32 100000}

-- 
Regards,
Peng


More information about the llvm-dev mailing list