diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
| commit | dd58ef019b700900793a1eb48b52123db01b654e (patch) | |
| tree | fcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /test/Transforms/SafeStack | |
| parent | 2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff) | |
Notes
Diffstat (limited to 'test/Transforms/SafeStack')
| -rw-r--r-- | test/Transforms/SafeStack/AArch64/abi.ll | 20 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/AArch64/lit.local.cfg | 3 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/ARM/abi.ll | 18 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/ARM/lit.local.cfg | 3 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/ARM/setjmp.ll | 34 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/X86/abi.ll | 30 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/X86/lit.local.cfg | 3 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/array.ll | 53 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/byval.ll | 51 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/call.ll | 160 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/cast.ll | 28 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/debug-loc.ll | 83 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/ret.ll | 17 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/setjmp2.ll | 2 | ||||
| -rw-r--r-- | test/Transforms/SafeStack/store.ll | 63 |
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 +} |
