Index: test/NaCl/PNaClABI/abi-stripped-pointers.ll |
diff --git a/test/NaCl/PNaClABI/abi-stripped-pointers.ll b/test/NaCl/PNaClABI/abi-stripped-pointers.ll |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7b67405483dea4924c810735c01896c31cbe31bc |
--- /dev/null |
+++ b/test/NaCl/PNaClABI/abi-stripped-pointers.ll |
@@ -0,0 +1,138 @@ |
+; RUN: not pnacl-abicheck < %s | FileCheck %s |
+ |
+; This test checks that the PNaCl ABI verifier enforces the normal |
+; form introduced by the ReplacePtrsWithInts pass. |
+ |
+ |
+@var = global [4 x i8] c"xxxx" |
+@ptr = global i32 ptrtoint ([4 x i8]* @var to i32) |
+ |
+declare i8* @llvm.nacl.read.tp() |
+ |
+ |
+define internal void @pointer_arg(i8* %arg) { |
+ ret void |
+} |
+; CHECK: Function pointer_arg has disallowed type |
+ |
+define internal i8* @pointer_return() { |
+ unreachable |
+} |
+; CHECK-NEXT: Function pointer_return has disallowed type |
+ |
+define internal void @func() { |
+ ret void |
+} |
+ |
+define internal void @func_with_arg(i32 %arg) { |
+ ret void |
+} |
+ |
+ |
+define internal void @allowed_cases(i32 %arg) { |
+ inttoptr i32 123 to i8* |
+ |
+ ptrtoint [4 x i8]* @var to i32 |
+ |
+ %alloc = alloca i8 |
+ ptrtoint i8* %alloc to i32 |
+ load i8* %alloc, align 1 |
+ |
+ ; These instructions may use a NormalizedPtr, which may be a global. |
+ load i32* @ptr, align 1 |
+ store i32 123, i32* @ptr, align 1 |
+ |
+ ; A NormalizedPtr may be a bitcast. |
+ %ptr_bitcast = bitcast [4 x i8]* @var to i32* |
+ load i32* %ptr_bitcast, align 1 |
+ |
+ ; A NormalizedPtr may be an inttoptr. |
+ %ptr_from_int = inttoptr i32 123 to i32* |
+ load i32* %ptr_from_int, align 1 |
+ |
+ ; Check direct and indirect function calls. |
+ %func_as_int = ptrtoint void ()* @func to i32 |
+ %func_ptr = inttoptr i32 %func_as_int to void ()* |
+ call void %func_ptr() |
+ call void @func() |
+ call void @func_with_arg(i32 123) |
+ |
+ ; Intrinsic calls may return pointers. |
+ %thread_ptr = call i8* @llvm.nacl.read.tp() |
+ ptrtoint i8* %thread_ptr to i32 |
+ |
+ ; Bitcasts between non-pointers are not restricted |
+ bitcast i64 0 to double |
+ bitcast i32 0 to float |
+ |
+ ; ConstantInts and Arguments are allowed as operands. |
+ add i32 %arg, 123 |
+ |
+ ret void |
+} |
+; CHECK-NOT: disallowed |
+ |
+ |
+define internal void @bad_cases() { |
+entry: |
+ ptrtoint [4 x i8]* @var to i16 |
+; CHECK: Function bad_cases disallowed: non-i32 ptrtoint |
+ |
+ inttoptr i16 123 to i8* |
+; CHECK-NEXT: non-i32 inttoptr |
+ |
+ %a = alloca i32 |
+; CHECK-NEXT: non-i8 alloca: %a |
+ %a2 = alloca [4 x i8] |
+; CHECK-NEXT: non-i8 alloca: %a2 |
+ |
+ store i32 0, i32* null, align 1 |
+; CHECK-NEXT: bad pointer |
+ |
+ store i32 0, i32* undef, align 1 |
+; CHECK-NEXT: bad pointer |
+ |
+ %bc = bitcast i32* @ptr to i31* |
+; CHECK-NEXT: bad result type |
+ store i31 0, i31* %bc, align 1 |
+; CHECK-NEXT: bad pointer |
+ |
+ ; Only one level of bitcasts is allowed. |
+ %b = bitcast i32* %a to i8* |
+ %c = bitcast i8* %b to i16* |
+; CHECK-NEXT: operand not InherentPtr |
+ |
+ br label %block |
+block: |
+ %phi1 = phi i8* [ undef, %entry ] |
+; CHECK-NEXT: bad operand: %phi1 |
+ %phi2 = phi i32* [ undef, %entry ] |
+; CHECK-NEXT: bad operand: %phi2 |
+ |
+ icmp eq i32* @ptr, @ptr |
+; CHECK-NEXT: Expects integer arithmetic type: {{.*}} icmp eq i32* |
+ icmp eq void ()* @func, @func |
+; CHECK-NEXT: Expects integer arithmetic type: {{.*}} icmp eq void ()* |
+ icmp eq i31 0, 0 |
+; CHECK-NEXT: Invalid integer arithmetic type: {{.*}} icmp eq i31 |
+ |
+ call void null() |
+; CHECK-NEXT: bad function callee operand |
+ |
+ call void @func_with_arg(i32 ptrtoint (i32* @ptr to i32)) |
+; CHECK-NEXT: bad operand |
+ |
+ ; Taking the address of an intrinsic is not allowed. |
+ ptrtoint i8* ()* @llvm.nacl.read.tp to i32 |
+; CHECK-NEXT: operand not InherentPtr |
+ |
+ ret void |
+} |
+ |
+; CHECK-NOT: disallowed |
+ |
+ |
+; This stops the verifier from complaining about the lack of an entry point. |
+define void @_start(i32 %arg) { |
+ ret void |
+} |