reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=alignment | FileCheck %s -check-prefixes=ALIGN,COMMON
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null | FileCheck %s -check-prefixes=NULL,COMMON
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=object-size | FileCheck %s -check-prefixes=OBJSIZE,COMMON
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=null,vptr | FileCheck %s -check-prefixes=VPTR
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=vptr | FileCheck %s -check-prefixes=VPTR_NO_NULL

struct A {
  // COMMON-LABEL: define linkonce_odr void @_ZN1A10do_nothingEv
  void do_nothing() {
    // ALIGN-NOT: ptrtoint %struct.A* %{{.*}} to i64, !nosanitize
 
    // NULL: icmp ne %struct.A* %{{.*}}, null, !nosanitize
 
    // OBJSIZE-NOT: call i64 @llvm.objectsize
  }
};

struct B {
  int x;

  // COMMON-LABEL: define linkonce_odr void @_ZN1B10do_nothingEv
  void do_nothing() {
    // ALIGN: ptrtoint %struct.B* %{{.*}} to i64, !nosanitize
    // ALIGN: and i64 %{{.*}}, 3, !nosanitize

    // NULL: icmp ne %struct.B* %{{.*}}, null, !nosanitize

    // OBJSIZE-NOT: call i64 @llvm.objectsize
    // OBJSIZE: ret void
  }
};

struct Animal {
  virtual const char *speak() = 0;
};

struct Cat : Animal {
  const char *speak() override { return "meow"; }
};

struct Dog : Animal {
  const char *speak() override { return "woof"; }
};

// VPTR-LABEL: define void @_Z12invalid_castP3Cat
void invalid_cast(Cat *cat = nullptr) {
  // If -fsanitize=null is available, we'll reuse its check:
  //
  // VPTR: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
  // VPTR-NEXT: br i1 [[ICMP]]
  // VPTR: call void @__ubsan_handle_type_mismatch
  // VPTR-NOT: icmp ne %struct.Dog* {{.*}}, null
  // VPTR: br i1 [[ICMP]]
  // VPTR: call void @__ubsan_handle_dynamic_type_cache_miss
  //
  // Fall back to the vptr sanitizer's null check when -fsanitize=null isn't
  // available.
  //
  // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch
  // VPTR_NO_NULL: [[ICMP:%.*]] = icmp ne %struct.Dog* {{.*}}, null
  // VPTR_NO_NULL-NEXT: br i1 [[ICMP]]
  // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss
  auto *badDog = reinterpret_cast<Dog *>(cat);
  badDog->speak();
}

// VPTR_NO_NULL-LABEL: define void @_Z13invalid_cast2v
void invalid_cast2() {
  // We've got a pointer to an alloca, so there's no run-time null check needed.
  // VPTR_NO_NULL-NOT: call void @__ubsan_handle_type_mismatch
  // VPTR_NO_NULL: call void @__ubsan_handle_dynamic_type_cache_miss
  Cat cat;
  cat.speak();
}

int main() {
  A a;
  a.do_nothing();

  B b;
  b.do_nothing();

  invalid_cast();
  return 0;
}