Skip to content

[UBSan][Clang][CodeGen] Improve memory effect modeling of ubsan handlers #130093

@dtcxzyw

Description

@dtcxzyw

Consider the following case: https://godbolt.org/z/zxxn3oG1z

; bin/clang -O3 -fsanitize=undefined -S -emit-llvm -o -
int test(int &a, short &c) {
    a += c;
    return c;
}
@.src = private unnamed_addr constant [17 x i8] c"/app/example.cpp\00", align 1
@0 = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
@1 = private unnamed_addr global { { ptr, i32, i32 }, ptr } { { ptr, i32, i32 } { ptr @.src, i32 2, i32 7 }, ptr @0 }

define dso_local noundef range(i32 -32768, 32768) i32 @test(int&, short&)(ptr noundef nonnull align 4 captures(none) dereferenceable(4) %a, ptr noundef nonnull readonly align 2 captures(none) dereferenceable(2) %c) local_unnamed_addr #0 {
entry:
  %0 = load i16, ptr %c, align 2
  %conv = sext i16 %0 to i32
  %1 = load i32, ptr %a, align 4
  %2 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %1, i32 %conv)
  %3 = extractvalue { i32, i1 } %2, 1
  br i1 %3, label %handler.add_overflow, label %cont

handler.add_overflow:
  %4 = zext i32 %1 to i64
  %5 = zext i32 %conv to i64
  tail call void @__ubsan_handle_add_overflow(ptr nonnull @1, i64 %4, i64 %5) #3
  %.pre = load i16, ptr %c, align 2
  %.pre3 = sext i16 %.pre to i32
  br label %cont

cont:
  %conv1.pre-phi = phi i32 [ %.pre3, %handler.add_overflow ], [ %conv, %entry ]
  %6 = extractvalue { i32, i1 } %2, 0
  store i32 %6, ptr %a, align 4
  ret i32 %conv1.pre-phi
}

declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) #1

declare void @__ubsan_handle_add_overflow(ptr, i64, i64) local_unnamed_addr #2

attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #2 = { uwtable }
attributes #3 = { nounwind }

If we mark __ubsan_handle_add_overflow(_abort) as memory(argmem: read, inaccessiblemem: readwrite), we can avoid reloading c after the call to __ubsan_handle_add_overflow.

TBH this example doesn't demonstrate a performance issue since we only optimize code in the cold path. However, it would allow more aggressive LICM in the hot path, which improves the performance of fuzzers like AFL.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions