summaryrefslogtreecommitdiff
path: root/test/Transforms/SafeStack
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
commitdd58ef019b700900793a1eb48b52123db01b654e (patch)
treefcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /test/Transforms/SafeStack
parent2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff)
Notes
Diffstat (limited to 'test/Transforms/SafeStack')
-rw-r--r--test/Transforms/SafeStack/AArch64/abi.ll20
-rw-r--r--test/Transforms/SafeStack/AArch64/lit.local.cfg3
-rw-r--r--test/Transforms/SafeStack/ARM/abi.ll18
-rw-r--r--test/Transforms/SafeStack/ARM/lit.local.cfg3
-rw-r--r--test/Transforms/SafeStack/ARM/setjmp.ll34
-rw-r--r--test/Transforms/SafeStack/X86/abi.ll30
-rw-r--r--test/Transforms/SafeStack/X86/lit.local.cfg3
-rw-r--r--test/Transforms/SafeStack/array.ll53
-rw-r--r--test/Transforms/SafeStack/byval.ll51
-rw-r--r--test/Transforms/SafeStack/call.ll160
-rw-r--r--test/Transforms/SafeStack/cast.ll28
-rw-r--r--test/Transforms/SafeStack/debug-loc.ll83
-rw-r--r--test/Transforms/SafeStack/ret.ll17
-rw-r--r--test/Transforms/SafeStack/setjmp2.ll2
-rw-r--r--test/Transforms/SafeStack/store.ll63
15 files changed, 563 insertions, 5 deletions
diff --git a/test/Transforms/SafeStack/AArch64/abi.ll b/test/Transforms/SafeStack/AArch64/abi.ll
new file mode 100644
index 0000000000000..cdec923eb74ce
--- /dev/null
+++ b/test/Transforms/SafeStack/AArch64/abi.ll
@@ -0,0 +1,20 @@
+; RUN: opt -safe-stack -S -mtriple=aarch64-linux-android < %s -o - | FileCheck %s
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; CHECK: %[[TP:.*]] = call i8* @llvm.aarch64.thread.pointer()
+; CHECK: %[[SPA0:.*]] = getelementptr i8, i8* %[[TP]], i32 72
+; CHECK: %[[SPA:.*]] = bitcast i8* %[[SPA0]] to i8**
+; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; CHECK: store i8* %[[USP]], i8** %[[SPA]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/test/Transforms/SafeStack/AArch64/lit.local.cfg b/test/Transforms/SafeStack/AArch64/lit.local.cfg
new file mode 100644
index 0000000000000..cec29af5bbe47
--- /dev/null
+++ b/test/Transforms/SafeStack/AArch64/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'AArch64' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/Transforms/SafeStack/ARM/abi.ll b/test/Transforms/SafeStack/ARM/abi.ll
new file mode 100644
index 0000000000000..e33c913ae9169
--- /dev/null
+++ b/test/Transforms/SafeStack/ARM/abi.ll
@@ -0,0 +1,18 @@
+; RUN: opt -safe-stack -S -mtriple=arm-linux-android < %s -o - | FileCheck %s
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
+; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CHECK: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; CHECK: store i8* %[[USP]], i8** %[[SPA]]
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/test/Transforms/SafeStack/ARM/lit.local.cfg b/test/Transforms/SafeStack/ARM/lit.local.cfg
new file mode 100644
index 0000000000000..98c6700c209d7
--- /dev/null
+++ b/test/Transforms/SafeStack/ARM/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'ARM' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/Transforms/SafeStack/ARM/setjmp.ll b/test/Transforms/SafeStack/ARM/setjmp.ll
new file mode 100644
index 0000000000000..8c57908bbe4bd
--- /dev/null
+++ b/test/Transforms/SafeStack/ARM/setjmp.ll
@@ -0,0 +1,34 @@
+; Test stack pointer restore after setjmp() with the function-call safestack ABI.
+; RUN: opt -safe-stack -S -mtriple=arm-linux-androideabi < %s -o - | FileCheck %s
+
+@env = global [64 x i32] zeroinitializer, align 4
+
+define void @f(i32 %b) safestack {
+entry:
+; CHECK: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
+; CHECK: %[[USDP:.*]] = alloca i8*
+; CHECK: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CHECK: store i8* %[[USP]], i8** %[[USDP]]
+; CHECK: call i32 @setjmp
+
+ %call = call i32 @setjmp(i32* getelementptr inbounds ([64 x i32], [64 x i32]* @env, i32 0, i32 0)) returns_twice
+
+; CHECK: %[[USP2:.*]] = load i8*, i8** %[[USDP]]
+; CHECK: store i8* %[[USP2]], i8** %[[SPA]]
+
+ %tobool = icmp eq i32 %b, 0
+ br i1 %tobool, label %if.end, label %if.then
+
+if.then:
+ %0 = alloca [42 x i8], align 1
+ %.sub = getelementptr inbounds [42 x i8], [42 x i8]* %0, i32 0, i32 0
+ call void @_Z7CapturePv(i8* %.sub)
+ br label %if.end
+
+if.end:
+ ret void
+}
+
+declare i32 @setjmp(i32*) returns_twice
+
+declare void @_Z7CapturePv(i8*)
diff --git a/test/Transforms/SafeStack/X86/abi.ll b/test/Transforms/SafeStack/X86/abi.ll
new file mode 100644
index 0000000000000..f437c4f7157d9
--- /dev/null
+++ b/test/Transforms/SafeStack/X86/abi.ll
@@ -0,0 +1,30 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS32
+; RUN: opt -safe-stack -S -mtriple=x86_64-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS64
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; TLS: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; TLS: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; TLS: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
+
+; DIRECT-TLS32: %[[USP:.*]] = load i8*, i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+; DIRECT-TLS32: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS32: store i8* %[[USST]], i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+
+; DIRECT-TLS64: %[[USP:.*]] = load i8*, i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+; DIRECT-TLS64: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS64: store i8* %[[USST]], i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; TLS: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+; DIRECT-TLS32: store i8* %[[USP]], i8* addrspace(256)* inttoptr (i32 36 to i8* addrspace(256)*)
+; DIRECT-TLS64: store i8* %[[USP]], i8* addrspace(257)* inttoptr (i32 72 to i8* addrspace(257)*)
+ ret void
+}
+
+declare void @Capture(i8*)
diff --git a/test/Transforms/SafeStack/X86/lit.local.cfg b/test/Transforms/SafeStack/X86/lit.local.cfg
new file mode 100644
index 0000000000000..e71f3cc4c41e7
--- /dev/null
+++ b/test/Transforms/SafeStack/X86/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'X86' in config.root.targets:
+ config.unsupported = True
+
diff --git a/test/Transforms/SafeStack/array.ll b/test/Transforms/SafeStack/array.ll
index 6036bfc2c9c5b..564213e6d58fa 100644
--- a/test/Transforms/SafeStack/array.ll
+++ b/test/Transforms/SafeStack/array.ll
@@ -1,9 +1,14 @@
; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -safe-stack-usp-storage=single-thread -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck -check-prefix=SINGLE-THREAD %s
; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -safe-stack-usp-storage=single-thread -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck -check-prefix=SINGLE-THREAD %s
; array [4 x i8]
; Requires protector.
+; CHECK: @__safestack_unsafe_stack_ptr = external thread_local(initialexec) global i8*
+; SINGLE-THREAD: @__safestack_unsafe_stack_ptr = external global i8*
+
define void @foo(i8* %a) nounwind uwtable safestack {
entry:
; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
@@ -35,4 +40,52 @@ entry:
ret void
}
+; Load from an array at a fixed offset, no overflow.
+define i8 @StaticArrayFixedSafe() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayFixedSafe(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 2
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array at a fixed offset with overflow.
+define i8 @StaticArrayFixedUnsafe() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayFixedUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 5
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array at an unknown offset.
+define i8 @StaticArrayVariableUnsafe(i32 %ofs) nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @StaticArrayVariableUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 4, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 %ofs
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
+; Load from an array of an unknown size.
+define i8 @DynamicArrayUnsafe(i32 %sz) nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: define i8 @DynamicArrayUnsafe(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %buf = alloca i8, i32 %sz, align 1
+ %gep = getelementptr inbounds i8, i8* %buf, i32 2
+ %x = load i8, i8* %gep, align 1
+ ret i8 %x
+}
+
declare i8* @strcpy(i8*, i8*)
diff --git a/test/Transforms/SafeStack/byval.ll b/test/Transforms/SafeStack/byval.ll
new file mode 100644
index 0000000000000..f9a06e54d2df9
--- /dev/null
+++ b/test/Transforms/SafeStack/byval.ll
@@ -0,0 +1,51 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.S = type { [100 x i32] }
+
+; Safe access to a byval argument.
+define i32 @ByValSafe(%struct.S* byval nocapture readonly align 8 %zzz) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValSafe
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 3
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; Unsafe access to a byval argument.
+; Argument is copied to the unsafe stack.
+define i32 @ByValUnsafe(%struct.S* byval nocapture readonly align 8 %zzz, i64 %idx) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValUnsafe
+ ; CHECK: %[[A:.*]] = load {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: store {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[B:.*]] = getelementptr i8, i8* %[[A]], i32 -400
+ ; CHECK: %[[C:.*]] = bitcast %struct.S* %zzz to i8*
+ ; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %[[B]], i8* %[[C]], i64 400, i32 8, i1 false)
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 %idx
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; Highly aligned byval argument.
+define i32 @ByValUnsafeAligned(%struct.S* byval nocapture readonly align 64 %zzz, i64 %idx) norecurse nounwind readonly safestack uwtable {
+entry:
+ ; CHECK-LABEL: @ByValUnsafeAligned
+ ; CHECK: %[[A:.*]] = load {{.*}} @__safestack_unsafe_stack_ptr
+ ; CHECK: %[[B:.*]] = ptrtoint i8* %[[A]] to i64
+ ; CHECK: and i64 %[[B]], -64
+ ; CHECK: ret i32
+ %arrayidx = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 0
+ %0 = load i32, i32* %arrayidx, align 64
+ %arrayidx2 = getelementptr inbounds %struct.S, %struct.S* %zzz, i64 0, i32 0, i64 %idx
+ %1 = load i32, i32* %arrayidx2, align 4
+ %add = add nsw i32 %1, %0
+ ret i32 %add
+}
+
diff --git a/test/Transforms/SafeStack/call.ll b/test/Transforms/SafeStack/call.ll
index ac12ec02b0b1b..cbac4ce1bb0d3 100644
--- a/test/Transforms/SafeStack/call.ll
+++ b/test/Transforms/SafeStack/call.ll
@@ -6,10 +6,11 @@
; no arrays / no nested arrays
; Requires no protector.
-; CHECK-LABEL: @foo(
define void @foo(i8* %a) nounwind uwtable safestack {
entry:
+ ; CHECK-LABEL: define void @foo(
; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
%a.addr = alloca i8*, align 8
store i8* %a, i8** %a.addr, align 8
%0 = load i8*, i8** %a.addr, align 8
@@ -18,3 +19,160 @@ entry:
}
declare i32 @printf(i8*, ...)
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @call_memset(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 %len, i32 1, i1 false)
+ ret void
+}
+
+define void @call_constant_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_memset
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 2
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 7, i32 1, i1 false)
+ ret void
+}
+
+define void @call_constant_overflow_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_overflow_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 7
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 5, i32 1, i1 false)
+ ret void
+}
+
+define void @call_constant_underflow_memset() safestack {
+entry:
+ ; CHECK-LABEL: define void @call_constant_underflow_memset
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr [10 x i8], [10 x i8]* %q, i32 0, i32 -1
+ call void @llvm.memset.p0i8.i64(i8* %arraydecay, i8 1, i64 3, i32 1, i1 false)
+ ret void
+}
+
+; Readnone nocapture -> safe
+define void @call_readnone(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone(i8* %arraydecay)
+ ret void
+}
+
+; Arg0 is readnone, arg1 is not. Pass alloca ptr as arg0 -> safe
+define void @call_readnone0_0(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone0_0
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone0(i8* %arraydecay, i8* zeroinitializer)
+ ret void
+}
+
+; Arg0 is readnone, arg1 is not. Pass alloca ptr as arg1 -> unsafe
+define void @call_readnone0_1(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readnone0_1
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readnone0(i8 *zeroinitializer, i8* %arraydecay)
+ ret void
+}
+
+; Readonly nocapture -> unsafe
+define void @call_readonly(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readonly
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readonly(i8* %arraydecay)
+ ret void
+}
+
+; Readonly nocapture -> unsafe
+define void @call_arg_readonly(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_arg_readonly
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @arg_readonly(i8* %arraydecay)
+ ret void
+}
+
+; Readwrite nocapture -> unsafe
+define void @call_readwrite(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_readwrite
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @readwrite(i8* %arraydecay)
+ ret void
+}
+
+; Captures the argument -> unsafe
+define void @call_capture(i64 %len) safestack {
+entry:
+ ; CHECK-LABEL: define void @call_capture
+ ; CHECK: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %q = alloca [10 x i8], align 1
+ %arraydecay = getelementptr inbounds [10 x i8], [10 x i8]* %q, i32 0, i32 0
+ call void @capture(i8* %arraydecay)
+ ret void
+}
+
+; Lifetime intrinsics are always safe.
+define void @call_lifetime(i32* %p) {
+ ; CHECK-LABEL: define void @call_lifetime
+ ; CHECK-NOT: @__safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+entry:
+ %q = alloca [100 x i8], align 16
+ %0 = bitcast [100 x i8]* %q to i8*
+ call void @llvm.lifetime.start(i64 100, i8* %0)
+ call void @llvm.lifetime.end(i64 100, i8* %0)
+ ret void
+}
+
+declare void @readonly(i8* nocapture) readonly
+declare void @arg_readonly(i8* readonly nocapture)
+declare void @readwrite(i8* nocapture)
+declare void @capture(i8* readnone) readnone
+
+declare void @readnone(i8* nocapture) readnone
+declare void @readnone0(i8* nocapture readnone, i8* nocapture)
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind argmemonly
+
+declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind argmemonly
+declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind argmemonly
diff --git a/test/Transforms/SafeStack/cast.ll b/test/Transforms/SafeStack/cast.ll
index df6273a117c3f..23f525d5e0b18 100644
--- a/test/Transforms/SafeStack/cast.ll
+++ b/test/Transforms/SafeStack/cast.ll
@@ -4,14 +4,36 @@
@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
; PtrToInt/IntToPtr Cast
-; Requires no protector.
-; CHECK-LABEL: @foo(
-define void @foo() nounwind uwtable safestack {
+define void @IntToPtr() nounwind uwtable safestack {
entry:
+ ; CHECK-LABEL: @IntToPtr(
; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
%a = alloca i32, align 4
%0 = ptrtoint i32* %a to i64
%1 = inttoptr i64 %0 to i32*
ret void
}
+
+define i8 @BitCastNarrow() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @BitCastNarrow(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i8
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = load i8, i8* %0, align 1
+ ret i8 %1
+}
+
+define i64 @BitCastWide() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @BitCastWide(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i64
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i64*
+ %1 = load i64, i64* %0, align 1
+ ret i64 %1
+}
diff --git a/test/Transforms/SafeStack/debug-loc.ll b/test/Transforms/SafeStack/debug-loc.ll
new file mode 100644
index 0000000000000..e72d0e9d2ff25
--- /dev/null
+++ b/test/Transforms/SafeStack/debug-loc.ll
@@ -0,0 +1,83 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+
+; Test debug location for the local variables moved onto the unsafe stack.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%struct.S = type { [100 x i8] }
+
+; Function Attrs: safestack uwtable
+define void @f(%struct.S* byval align 8 %zzz) #0 !dbg !12 {
+; CHECK: define void @f
+
+entry:
+; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+
+ %xxx = alloca %struct.S, align 1
+ call void @llvm.dbg.declare(metadata %struct.S* %zzz, metadata !18, metadata !19), !dbg !20
+ call void @llvm.dbg.declare(metadata %struct.S* %xxx, metadata !21, metadata !19), !dbg !22
+
+; dbg.declare for %zzz and %xxx are gone; replaced with dbg.declare based off the unsafe stack pointer
+; CHECK-NOT: call void @llvm.dbg.declare
+; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_ARG:.*]], metadata ![[EXPR_ARG:.*]])
+; CHECK-NOT: call void @llvm.dbg.declare
+; CHECK: call void @llvm.dbg.declare(metadata i8* %[[USP]], metadata ![[VAR_LOCAL:.*]], metadata ![[EXPR_LOCAL:.*]])
+; CHECK-NOT: call void @llvm.dbg.declare
+
+ call void @Capture(%struct.S* %zzz), !dbg !23
+ call void @Capture(%struct.S* %xxx), !dbg !24
+
+; dbg.declare appears before the first use
+; CHECK: call void @Capture
+; CHECK: call void @Capture
+
+ ret void, !dbg !25
+}
+
+; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz"
+; 100 aligned up to 8
+; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_deref, DW_OP_minus, 104
+
+; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx"
+; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_deref, DW_OP_minus, 208
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare void @Capture(%struct.S*) #2
+
+attributes #0 = { safestack uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!15, !16}
+!llvm.ident = !{!17}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !11)
+!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm")
+!2 = !{}
+!3 = !{!4}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !1, line: 4, size: 800, align: 8, elements: !5, identifier: "_ZTS1S")
+!5 = !{!6}
+!6 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !"_ZTS1S", file: !1, line: 5, baseType: !7, size: 800, align: 8)
+!7 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 800, align: 8, elements: !9)
+!8 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char)
+!9 = !{!10}
+!10 = !DISubrange(count: 100)
+!11 = !{!12}
+!12 = distinct !DISubprogram(name: "f", linkageName: "_Z1f1S", scope: !1, file: !1, line: 10, type: !13, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, variables: !2)
+!13 = !DISubroutineType(types: !14)
+!14 = !{null, !"_ZTS1S"}
+!15 = !{i32 2, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{!"clang version 3.8.0 (trunk 254019) (llvm/trunk 254036)"}
+!18 = !DILocalVariable(name: "zzz", arg: 1, scope: !12, file: !1, line: 10, type: !"_ZTS1S")
+!19 = !DIExpression()
+!20 = !DILocation(line: 10, column: 10, scope: !12)
+!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !"_ZTS1S")
+!22 = !DILocation(line: 11, column: 5, scope: !12)
+!23 = !DILocation(line: 12, column: 3, scope: !12)
+!24 = !DILocation(line: 13, column: 3, scope: !12)
+!25 = !DILocation(line: 14, column: 1, scope: !12)
diff --git a/test/Transforms/SafeStack/ret.ll b/test/Transforms/SafeStack/ret.ll
new file mode 100644
index 0000000000000..b2b8e56652979
--- /dev/null
+++ b/test/Transforms/SafeStack/ret.ll
@@ -0,0 +1,17 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+; Returns an alloca address.
+; Requires protector.
+
+define i64 @foo() nounwind readnone safestack {
+entry:
+ ; CHECK-LABEL: define i64 @foo(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret i64
+ %x = alloca [100 x i32], align 16
+ %0 = ptrtoint [100 x i32]* %x to i64
+ ret i64 %0
+}
diff --git a/test/Transforms/SafeStack/setjmp2.ll b/test/Transforms/SafeStack/setjmp2.ll
index 65fd920d63da2..bb15d7e03ace7 100644
--- a/test/Transforms/SafeStack/setjmp2.ll
+++ b/test/Transforms/SafeStack/setjmp2.ll
@@ -25,7 +25,7 @@ entry:
; CHECK-NEXT: %[[INTTOPTR:.*]] = inttoptr i64 %[[AND]] to i8*
; CHECK-NEXT: store i8* %[[INTTOPTR]], i8** @__safestack_unsafe_stack_ptr
; CHECK-NEXT: store i8* %[[INTTOPTR]], i8** %unsafe_stack_dynamic_ptr
- ; CHECK-NEXT: %[[ALLOCA:.*]] = inttoptr i64 %[[SUB]] to i32*
+ ; CHECK-NEXT: %[[ALLOCA:.*]] = bitcast i8* %[[INTTOPTR]] to i32*
%a = alloca i32, i32 %size
; CHECK: setjmp
diff --git a/test/Transforms/SafeStack/store.ll b/test/Transforms/SafeStack/store.ll
new file mode 100644
index 0000000000000..f493dd038bb82
--- /dev/null
+++ b/test/Transforms/SafeStack/store.ll
@@ -0,0 +1,63 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s
+
+@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+
+define void @bad_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @bad_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = ptrtoint i32* %a to i64
+ %1 = inttoptr i64 %0 to i64*
+ store i64 zeroinitializer, i64* %1
+ ret void
+}
+
+define void @good_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @good_store(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ store i8 zeroinitializer, i8* %0
+ ret void
+}
+
+define void @overflow_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @overflow_gep_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 4
+ store i8 zeroinitializer, i8* %1
+ ret void
+}
+
+define void @underflow_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @underflow_gep_store(
+ ; CHECK: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 -1
+ store i8 zeroinitializer, i8* %1
+ ret void
+}
+
+define void @good_gep_store() nounwind uwtable safestack {
+entry:
+ ; CHECK-LABEL: @good_gep_store(
+ ; CHECK-NOT: __safestack_unsafe_stack_ptr
+ ; CHECK: ret void
+ %a = alloca i32, align 4
+ %0 = bitcast i32* %a to i8*
+ %1 = getelementptr i8, i8* %0, i32 3
+ store i8 zeroinitializer, i8* %1
+ ret void
+}