<div dir="ltr">We also have a Wiki page explaining the basics of the algorithm: <a href="https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm">https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm</a></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Apr 13, 2021 at 8:18 AM Victor Campos via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">I recommend reading Address Sanitizer's paper:<br>
<a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37752.pdf" rel="noreferrer" target="_blank">https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37752.pdf</a><br>
<br>
It's an easy and quite interesting read.<br>
<br>
Cheers,<br>
Victor.<br>
<br>
On Tue, 13 Apr 2021, at 15:42, Peng Yu via llvm-dev wrote:<br>
> Hi,<br>
> <br>
> I am trying to see what -fsanitize=address does using the following<br>
> example. I see a number of _asan function and variables. But it is<br>
> still not clear how the original program is transformed so that memory<br>
> error will be catched. Could anybody help explain how it works?<br>
> Thanks.<br>
> <br>
> Also, many functions (like __asan_report_load16) are not used. Why are<br>
> they declared? Thanks.<br>
> <br>
> $ diff <(clang -Wno-array-bounds -S -emit-llvm -x c -o - - <<< 'int<br>
> main() { int a[2] = {1, 0}; int b=a[2]; return 0; }') <(clang<br>
> -Wno-array-bounds -fsanitize=address -S -emit-llvm -x c -o - -<<< 'int<br>
> main() { int a[2] = {1, 0}; int b=a[2]; return 0; }')<br>
> < @__const.main.a = private unnamed_addr constant [2 x i32] [i32 1,<br>
> i32 0], align 4<br>
> < ; Function Attrs: noinline nounwind optnone ssp uwtable<br>
> ---<br>
> > @__const.main.a = internal constant { [2 x i32], [56 x i8] } { [2 x i32] [i32 1, i32 0], [56 x i8] zeroinitializer }, align 32<br>
> > @__asan_option_detect_stack_use_after_return = external global i32<br>
> > @___asan_gen_ = private unnamed_addr constant [11 x i8] c"1 32 8 1 a\00", align 1<br>
> > @___asan_gen_.1 = private constant [2 x i8] c"-\00", align 1<br>
> > @___asan_gen_.2 = private unnamed_addr constant [15 x i8] c"__const.main.a\00", align 1<br>
> > @__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"<br>
> > @__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"<br>
> > @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"<br>
> > @___asan_globals_registered = common hidden global i64 0<br>
> > @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* null }]<br>
> > @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_dtor, i8* null }]<br>
> > ; Function Attrs: noinline nounwind optnone sanitize_address ssp uwtable<br>
> 9,17c19,121<br>
> <   %1 = alloca i32, align 4<br>
> <   %2 = alloca [2 x i32], align 4<br>
> <   %3 = alloca i32, align 4<br>
> <   store i32 0, i32* %1, align 4<br>
> <   %4 = bitcast [2 x i32]* %2 to i8*<br>
> <   call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %4, i8* align 4<br>
> bitcast ([2 x i32]* @__const.main.a to i8*), i64 8, i1 false)<br>
> <   %5 = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 0, i64 2<br>
> <   %6 = load i32, i32* %5, align 4<br>
> <   store i32 %6, i32* %3, align 4<br>
> ---<br>
> > entry:<br>
> >   %retval = alloca i32, align 4<br>
> >   %b = alloca i32, align 4<br>
> >   %asan_local_stack_base = alloca i64<br>
> >   %0 = load i32, i32* @__asan_option_detect_stack_use_after_return<br>
> >   %1 = icmp ne i32 %0, 0<br>
> >   br i1 %1, label %2, label %4<br>
> ><br>
> > 2:                                                ; preds = %entry<br>
> >   %3 = call i64 @__asan_stack_malloc_0(i64 64)<br>
> >   br label %4<br>
> ><br>
> > 4:                                                ; preds = %entry, %2<br>
> >   %5 = phi i64 [ 0, %entry ], [ %3, %2 ]<br>
> >   %6 = icmp eq i64 %5, 0<br>
> >   br i1 %6, label %7, label %9<br>
> ><br>
> > 7:                                                ; preds = %4<br>
> >   %MyAlloca = alloca i8, i64 64, align 32<br>
> >   %8 = ptrtoint i8* %MyAlloca to i64<br>
> >   br label %9<br>
> ><br>
> > 9:                                                ; preds = %4, %7<br>
> >   %10 = phi i64 [ %5, %4 ], [ %8, %7 ]<br>
> >   store i64 %10, i64* %asan_local_stack_base<br>
> >   %11 = add i64 %10, 32<br>
> >   %12 = inttoptr i64 %11 to [2 x i32]*<br>
> >   %13 = inttoptr i64 %10 to i64*<br>
> >   store i64 1102416563, i64* %13<br>
> >   %14 = add i64 %10, 8<br>
> >   %15 = inttoptr i64 %14 to i64*<br>
> >   store i64 ptrtoint ([11 x i8]* @___asan_gen_ to i64), i64* %15<br>
> >   %16 = add i64 %10, 16<br>
> >   %17 = inttoptr i64 %16 to i64*<br>
> >   store i64 ptrtoint (i32 ()* @main to i64), i64* %17<br>
> >   %18 = lshr i64 %10, 3<br>
> >   %19 = or i64 %18, 17592186044416<br>
> >   %20 = add i64 %19, 0<br>
> >   %21 = inttoptr i64 %20 to i64*<br>
> >   store i64 -868082052615769615, i64* %21, align 1<br>
> >   store i32 0, i32* %retval, align 4<br>
> >   %22 = bitcast [2 x i32]* %12 to i8*<br>
> >   %23 = add i64 %19, 4<br>
> >   %24 = inttoptr i64 %23 to i8*<br>
> >   store i8 0, i8* %24, align 1<br>
> >   call void @llvm.lifetime.start.p0i8(i64 8, i8* %22) #2<br>
> >   %25 = bitcast [2 x i32]* %12 to i8*<br>
> >   %26 = call i8* @__asan_memcpy(i8* %25, i8* bitcast ({ [2 x i32], [56 x i8] }* @__const.main.a to i8*), i64 8)<br>
> >   %27 = bitcast i32* %b to i8*<br>
> >   call void @llvm.lifetime.start.p0i8(i64 4, i8* %27) #2<br>
> >   %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* %12, i64 0, i64 2<br>
> >   %28 = ptrtoint i32* %arrayidx to i64<br>
> >   %29 = lshr i64 %28, 3<br>
> >   %30 = or i64 %29, 17592186044416<br>
> >   %31 = inttoptr i64 %30 to i8*<br>
> >   %32 = load i8, i8* %31<br>
> >   %33 = icmp ne i8 %32, 0<br>
> >   br i1 %33, label %34, label %40, !prof !4<br>
> ><br>
> > 34:                                               ; preds = %9<br>
> >   %35 = and i64 %28, 7<br>
> >   %36 = add i64 %35, 3<br>
> >   %37 = trunc i64 %36 to i8<br>
> >   %38 = icmp sge i8 %37, %32<br>
> >   br i1 %38, label %39, label %40<br>
> ><br>
> > 39:                                               ; preds = %34<br>
> >   call void @__asan_report_load4(i64 %28)<br>
> >   call void asm sideeffect "", ""()<br>
> >   unreachable<br>
> ><br>
> > 40:                                               ; preds = %34, %9<br>
> >   %41 = load i32, i32* %arrayidx, align 4<br>
> >   store i32 %41, i32* %b, align 4<br>
> >   %42 = bitcast i32* %b to i8*<br>
> >   call void @llvm.lifetime.end.p0i8(i64 4, i8* %42) #2<br>
> >   %43 = bitcast [2 x i32]* %12 to i8*<br>
> >   %44 = add i64 %19, 4<br>
> >   %45 = inttoptr i64 %44 to i8*<br>
> >   store i8 -8, i8* %45, align 1<br>
> >   call void @llvm.lifetime.end.p0i8(i64 8, i8* %43) #2<br>
> >   store i64 1172321806, i64* %13<br>
> >   %46 = icmp ne i64 %5, 0<br>
> >   br i1 %46, label %47, label %54<br>
> ><br>
> > 47:                                               ; preds = %40<br>
> >   %48 = add i64 %19, 0<br>
> >   %49 = inttoptr i64 %48 to i64*<br>
> >   store i64 -723401728380766731, i64* %49, align 1<br>
> >   %50 = add i64 %5, 56<br>
> >   %51 = inttoptr i64 %50 to i64*<br>
> >   %52 = load i64, i64* %51<br>
> >   %53 = inttoptr i64 %52 to i8*<br>
> >   store i8 0, i8* %53<br>
> >   br label %57<br>
> ><br>
> > 54:                                               ; preds = %40<br>
> >   %55 = add i64 %19, 0<br>
> >   %56 = inttoptr i64 %55 to i64*<br>
> >   store i64 0, i64* %56, align 1<br>
> >   br label %57<br>
> ><br>
> > 57:                                               ; preds = %54, %47<br>
> 20a125,126<br>
> > declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1<br>
> > ; Function Attrs: argmemonly nounwind willreturn<br>
> 21a128,235<br>
> > ; Function Attrs: argmemonly nounwind willreturn<br>
> > declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1<br>
> > declare void @__asan_report_load_n(i64, i64)<br>
> > declare void @__asan_loadN(i64, i64)<br>
> > declare void @__asan_report_load1(i64)<br>
> > declare void @__asan_load1(i64)<br>
> > declare void @__asan_report_load2(i64)<br>
> > declare void @__asan_load2(i64)<br>
> > declare void @__asan_report_load4(i64)<br>
> > declare void @__asan_load4(i64)<br>
> > declare void @__asan_report_load8(i64)<br>
> > declare void @__asan_load8(i64)<br>
> > declare void @__asan_report_load16(i64)<br>
> > declare void @__asan_load16(i64)<br>
> > declare void @__asan_report_store_n(i64, i64)<br>
> > declare void @__asan_storeN(i64, i64)<br>
> > declare void @__asan_report_store1(i64)<br>
> > declare void @__asan_store1(i64)<br>
> > declare void @__asan_report_store2(i64)<br>
> > declare void @__asan_store2(i64)<br>
> > declare void @__asan_report_store4(i64)<br>
> > declare void @__asan_store4(i64)<br>
> > declare void @__asan_report_store8(i64)<br>
> > declare void @__asan_store8(i64)<br>
> > declare void @__asan_report_store16(i64)<br>
> > declare void @__asan_store16(i64)<br>
> > declare void @__asan_report_exp_load_n(i64, i64, i32)<br>
> > declare void @__asan_exp_loadN(i64, i64, i32)<br>
> > declare void @__asan_report_exp_load1(i64, i32)<br>
> > declare void @__asan_exp_load1(i64, i32)<br>
> > declare void @__asan_report_exp_load2(i64, i32)<br>
> > declare void @__asan_exp_load2(i64, i32)<br>
> > declare void @__asan_report_exp_load4(i64, i32)<br>
> > declare void @__asan_exp_load4(i64, i32)<br>
> > declare void @__asan_report_exp_load8(i64, i32)<br>
> > declare void @__asan_exp_load8(i64, i32)<br>
> > declare void @__asan_report_exp_load16(i64, i32)<br>
> > declare void @__asan_exp_load16(i64, i32)<br>
> > declare void @__asan_report_exp_store_n(i64, i64, i32)<br>
> > declare void @__asan_exp_storeN(i64, i64, i32)<br>
> > declare void @__asan_report_exp_store1(i64, i32)<br>
> > declare void @__asan_exp_store1(i64, i32)<br>
> > declare void @__asan_report_exp_store2(i64, i32)<br>
> > declare void @__asan_exp_store2(i64, i32)<br>
> > declare void @__asan_report_exp_store4(i64, i32)<br>
> > declare void @__asan_exp_store4(i64, i32)<br>
> > declare void @__asan_report_exp_store8(i64, i32)<br>
> > declare void @__asan_exp_store8(i64, i32)<br>
> > declare void @__asan_report_exp_store16(i64, i32)<br>
> > declare void @__asan_exp_store16(i64, i32)<br>
> > declare i8* @__asan_memmove(i8*, i8*, i64)<br>
> > declare i8* @__asan_memcpy(i8*, i8*, i64)<br>
> > declare i8* @__asan_memset(i8*, i32, i64)<br>
> > declare void @__asan_handle_no_return()<br>
> > declare void @__sanitizer_ptr_cmp(i64, i64)<br>
> > declare void @__sanitizer_ptr_sub(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_0(i64)<br>
> > declare void @__asan_stack_free_0(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_1(i64)<br>
> > declare void @__asan_stack_free_1(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_2(i64)<br>
> > declare void @__asan_stack_free_2(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_3(i64)<br>
> > declare void @__asan_stack_free_3(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_4(i64)<br>
> > declare void @__asan_stack_free_4(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_5(i64)<br>
> > declare void @__asan_stack_free_5(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_6(i64)<br>
> > declare void @__asan_stack_free_6(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_7(i64)<br>
> > declare void @__asan_stack_free_7(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_8(i64)<br>
> > declare void @__asan_stack_free_8(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_9(i64)<br>
> > declare void @__asan_stack_free_9(i64, i64)<br>
> > declare i64 @__asan_stack_malloc_10(i64)<br>
> > declare void @__asan_stack_free_10(i64, i64)<br>
> > declare void @__asan_poison_stack_memory(i64, i64)<br>
> > declare void @__asan_unpoison_stack_memory(i64, i64)<br>
> > declare void @__asan_set_shadow_00(i64, i64)<br>
> > declare void @__asan_set_shadow_f1(i64, i64)<br>
> > declare void @__asan_set_shadow_f2(i64, i64)<br>
> > declare void @__asan_set_shadow_f3(i64, i64)<br>
> > declare void @__asan_set_shadow_f5(i64, i64)<br>
> > declare void @__asan_set_shadow_f8(i64, i64)<br>
> > declare void @__asan_alloca_poison(i64, i64)<br>
> > declare void @__asan_allocas_unpoison(i64, i64)<br>
> > declare void @__asan_before_dynamic_init(i64)<br>
> > declare void @__asan_after_dynamic_init()<br>
> > declare void @__asan_register_globals(i64, i64)<br>
> > declare void @__asan_unregister_globals(i64, i64)<br>
> > declare void @__asan_register_image_globals(i64)<br>
> > declare void @__asan_unregister_image_globals(i64)<br>
> > declare void @__asan_register_elf_globals(i64, i64, i64)<br>
> > declare void @__asan_unregister_elf_globals(i64, i64, i64)<br>
> > declare void @__asan_init()<br>
> > define internal void @asan.module_ctor() {<br>
> >   call void @__asan_init()<br>
> >   call void @__asan_version_mismatch_check_apple_clang_1200()<br>
> >   call void @__asan_register_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))<br>
> >   ret void<br>
> > }<br>
> > declare void @__asan_version_mismatch_check_apple_clang_1200()<br>
> > define internal void @asan.module_dtor() {<br>
> >   call void @__asan_unregister_image_globals(i64 ptrtoint (i64* @___asan_globals_registered to i64))<br>
> >   ret void<br>
> > }<br>
> 23c237<br>
> < attributes #0 = { noinline nounwind optnone ssp uwtable<br>
> "correctly-rounded-divide-sqrt-fp-math"="false"<br>
> "darwin-stkchk-strong-link" "disable-tail-calls"="false"<br>
> "frame-pointer"="all" "less-precise-fpmad"="false"<br>
> "min-legal-vector-width"="0" "no-infs-fp-math"="false"<br>
> "no-jump-tables"="false" "no-nans-fp-math"="false"<br>
> "no-signed-zeros-fp-math"="false" "no-trapping-math"="false"<br>
> "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8"<br>
> "target-cpu"="penryn"<br>
> "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87"<br>
> "unsafe-fp-math"="false" "use-soft-float"="false" }<br>
> ---<br>
> > 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" }<br>
> 24a239<br>
> > attributes #2 = { nounwind }<br>
> 32a248<br>
> > !4 = !{!"branch_weights", i32 1, i32 100000}<br>
> <br>
> -- <br>
> Regards,<br>
> Peng<br>
> _______________________________________________<br>
> LLVM Developers mailing list<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
> <br>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>