Index: llvm/trunk/test/Transforms/SafeStack/X86/addr-taken.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/addr-taken.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/addr-taken.ll @@ -0,0 +1,22 @@ +; 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 + +; Address-of local taken (j = &a) +; Requires protector. + +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %retval = alloca i32, align 4 + %a = alloca i32, align 4 + %j = alloca i32*, align 8 + store i32 0, i32* %retval + %0 = load i32, i32* %a, align 4 + %add = add nsw i32 %0, 1 + store i32 %add, i32* %a, align 4 + store i32* %a, i32** %j, align 8 + ret void +} + Index: llvm/trunk/test/Transforms/SafeStack/X86/array-aligned.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/array-aligned.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/array-aligned.ll @@ -0,0 +1,38 @@ +; 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 + +; array of [16 x i8] + +define void @foo(i8* %a) nounwind uwtable safestack { +entry: + ; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + + ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + + ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr + + %a.addr = alloca i8*, align 8 + %buf = alloca [16 x i8], align 16 + + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 + ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 + store i8* %a, i8** %a.addr, align 8 + + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]* + ; CHECK: %[[GEP:.*]] = getelementptr inbounds [16 x i8], [16 x i8]* %[[BUFPTR2]], i32 0, i32 0 + %gep = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 + + ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8 + %a2 = load i8*, i8** %a.addr, align 8 + + ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]]) + %call = call i8* @strcpy(i8* %gep, i8* %a2) + + ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr + ret void +} + +declare i8* @strcpy(i8*, i8*) Index: llvm/trunk/test/Transforms/SafeStack/X86/array.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/array.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/array.ll @@ -0,0 +1,90 @@ +; 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 + + ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + + ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr + + %a.addr = alloca i8*, align 8 + %buf = alloca [4 x i8], align 1 + + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 + ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 + store i8* %a, i8** %a.addr, align 8 + + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]* + ; CHECK: %[[GEP:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUFPTR2]], i32 0, i32 0 + %gep = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i32 0, i32 0 + + ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8 + %a2 = load i8*, i8** %a.addr, align 8 + + ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]]) + %call = call i8* @strcpy(i8* %gep, i8* %a2) + + ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr + 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*) Index: llvm/trunk/test/Transforms/SafeStack/X86/byval.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/byval.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/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 +} + Index: llvm/trunk/test/Transforms/SafeStack/X86/call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/call.ll @@ -0,0 +1,178 @@ +; 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 + +; no arrays / no nested arrays +; Requires no protector. + +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 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %0) + ret void +} + +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 Index: llvm/trunk/test/Transforms/SafeStack/X86/cast.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/cast.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/cast.ll @@ -0,0 +1,39 @@ +; 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 + +; PtrToInt/IntToPtr Cast + +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 +} Index: llvm/trunk/test/Transforms/SafeStack/X86/coloring-ssp.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/coloring-ssp.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/coloring-ssp.ll @@ -0,0 +1,34 @@ +; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s + +; %x and %y share a stack slot between them, but not with the stack guard. +define void @f() safestack sspreq { +; CHECK-LABEL: define void @f +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + +; CHECK: %[[A:.*]] = getelementptr i8, i8* %[[USP]], i32 -8 +; CHECK: %[[StackGuardSlot:.*]] = bitcast i8* %[[A]] to i8** +; CHECK: store i8* %{{.*}}, i8** %[[StackGuardSlot]] + + %x = alloca i64, align 8 + %y = alloca i64, align 8 + %x0 = bitcast i64* %x to i8* + %y0 = bitcast i64* %y to i8* + + call void @llvm.lifetime.start(i64 -1, i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + call void @capture64(i64* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + call void @capture64(i64* %y) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + + ret void +} + +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) +declare void @capture64(i64*) Index: llvm/trunk/test/Transforms/SafeStack/X86/coloring.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/coloring.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/coloring.ll @@ -0,0 +1,44 @@ +; 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 + +define void @f() safestack { +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + + %x = alloca i32, align 4 + %x1 = alloca i32, align 4 + %x2 = alloca i32, align 4 + %0 = bitcast i32* %x to i8* + call void @llvm.lifetime.start(i64 4, i8* %0) + +; CHECK: %[[A1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: %[[A2:.*]] = bitcast i8* %[[A1]] to i32* +; CHECK: call void @capture(i32* nonnull %[[A2]]) + + call void @capture(i32* nonnull %x) + call void @llvm.lifetime.end(i64 4, i8* %0) + %1 = bitcast i32* %x1 to i8* + call void @llvm.lifetime.start(i64 4, i8* %1) + +; CHECK: %[[B1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: %[[B2:.*]] = bitcast i8* %[[B1]] to i32* +; CHECK: call void @capture(i32* nonnull %[[B2]]) + + call void @capture(i32* nonnull %x1) + call void @llvm.lifetime.end(i64 4, i8* %1) + %2 = bitcast i32* %x2 to i8* + call void @llvm.lifetime.start(i64 4, i8* %2) + +; CHECK: %[[C1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: %[[C2:.*]] = bitcast i8* %[[C1]] to i32* +; CHECK: call void @capture(i32* nonnull %[[C2]]) + + call void @capture(i32* nonnull %x2) + call void @llvm.lifetime.end(i64 4, i8* %2) + ret void +} + +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) +declare void @capture(i32*) Index: llvm/trunk/test/Transforms/SafeStack/X86/coloring2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/coloring2.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/coloring2.ll @@ -0,0 +1,521 @@ +; 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 + +; x and y share the stack slot. +define void @f() safestack { +; CHECK-LABEL: define void @f +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i32* %z to i8* + + call void @llvm.lifetime.start(i64 -1, i8* %z0) + call void @llvm.lifetime.start(i64 -1, i8* %x0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + call void @llvm.lifetime.start(i64 -1, i8* %y0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @capture32(i32* %y) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture32(i32* %z) + call void @llvm.lifetime.end(i64 -1, i8* %z0) + + ret void +} + +define void @no_markers() safestack { +; CHECK-LABEL: define void @no_markers( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + + call void @llvm.lifetime.start(i64 -1, i8* %x0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture32(i32* %y) + + ret void +} + +; x and y can't share memory, but they can split z's storage. +define void @g() safestack { +; CHECK-LABEL: define void @g +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i64, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i64* %z to i8* + + call void @llvm.lifetime.start(i64 -1, i8* %x0) + call void @llvm.lifetime.start(i64 -1, i8* %y0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture32(i32* %y) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + call void @llvm.lifetime.start(i64 -1, i8* %z0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture64(i64* %z) + call void @llvm.lifetime.end(i64 -1, i8* %z0) + + ret void +} + +; Both y and z fit in x's alignment gap. +define void @h() safestack { +; CHECK-LABEL: define void @h +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + + %x = alloca i32, align 16 + %z = alloca i64, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i64* %z to i8* + + call void @llvm.lifetime.start(i64 -1, i8* %x0) + call void @llvm.lifetime.start(i64 -1, i8* %y0) + call void @llvm.lifetime.start(i64 -1, i8* %z0) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + call void @capture32(i32* %x) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -12 + call void @capture32(i32* %y) + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture64(i64* %z) + + call void @llvm.lifetime.end(i64 -1, i8* %x0) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + call void @llvm.lifetime.end(i64 -1, i8* %z0) + + ret void +} + +; void f(bool a, bool b) { +; long x1, x2; capture64(&x1); capture64(&x2); +; if (a) { +; long y; capture64(&y); +; if (b) { +; long y1; capture64(&y1); +; } else { +; long y2; capture64(&y2); +; } +; } else { +; long z; capture64(&z); +; if (b) { +; long z1; capture64(&z1); +; } else { +; long z2; capture64(&z2); +; } +; } +; } +; Everything fits in 4 x 64-bit slots. +define void @i(i1 zeroext %a, i1 zeroext %b) safestack { +; CHECK-LABEL: define void @i +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -32 + %x1 = alloca i64, align 8 + %x2 = alloca i64, align 8 + %y = alloca i64, align 8 + %y1 = alloca i64, align 8 + %y2 = alloca i64, align 8 + %z = alloca i64, align 8 + %z1 = alloca i64, align 8 + %z2 = alloca i64, align 8 + %0 = bitcast i64* %x1 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %0) + %1 = bitcast i64* %x2 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %x1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %x2) + br i1 %a, label %if.then, label %if.else4 + +if.then: ; preds = %entry + %2 = bitcast i64* %y to i8* + call void @llvm.lifetime.start(i64 -1, i8* %2) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -24 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %y) + br i1 %b, label %if.then3, label %if.else + +if.then3: ; preds = %if.then + %3 = bitcast i64* %y1 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %3) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %y1) + call void @llvm.lifetime.end(i64 -1, i8* %3) + br label %if.end + +if.else: ; preds = %if.then + %4 = bitcast i64* %y2 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %4) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %y2) + call void @llvm.lifetime.end(i64 -1, i8* %4) + br label %if.end + +if.end: ; preds = %if.else, %if.then3 + call void @llvm.lifetime.end(i64 -1, i8* %2) + br label %if.end9 + +if.else4: ; preds = %entry + %5 = bitcast i64* %z to i8* + call void @llvm.lifetime.start(i64 -1, i8* %5) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -24 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %z) + br i1 %b, label %if.then6, label %if.else7 + +if.then6: ; preds = %if.else4 + %6 = bitcast i64* %z1 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %6) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %z1) + call void @llvm.lifetime.end(i64 -1, i8* %6) + br label %if.end8 + +if.else7: ; preds = %if.else4 + %7 = bitcast i64* %z2 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %7) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 +; CHECK: call void @capture64( + call void @capture64(i64* nonnull %z2) + call void @llvm.lifetime.end(i64 -1, i8* %7) + br label %if.end8 + +if.end8: ; preds = %if.else7, %if.then6 + call void @llvm.lifetime.end(i64 -1, i8* %5) + br label %if.end9 + +if.end9: ; preds = %if.end8, %if.end + call void @llvm.lifetime.end(i64 -1, i8* %1) + call void @llvm.lifetime.end(i64 -1, i8* %0) + ret void +} + +; lifetime for x ends in 2 different BBs +define void @no_merge1(i1 %d) safestack { +; CHECK-LABEL: define void @no_merge1( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start(i64 -1, i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %x) + br i1 %d, label %bb2, label %bb3 +bb2: + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 +; CHECK: call void @capture32( + call void @capture32(i32* %y) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + ret void +bb3: + call void @llvm.lifetime.end(i64 -1, i8* %x0) + ret void +} + +define void @merge1(i1 %d) safestack { +; CHECK-LABEL: define void @merge1( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start(i64 -1, i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + br i1 %d, label %bb2, label %bb3 +bb2: + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %y) + call void @llvm.lifetime.end(i64 -1, i8* %y0) + ret void +bb3: + ret void +} + +; Missing lifetime.end +define void @merge2_noend(i1 %d) safestack { +; CHECK-LABEL: define void @merge2_noend( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start(i64 -1, i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + br i1 %d, label %bb2, label %bb3 +bb2: + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %y) + ret void +bb3: + ret void +} + +; Missing lifetime.end +define void @merge3_noend(i1 %d) safestack { +; CHECK-LABEL: define void @merge3_noend( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start(i64 -1, i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %x) + br i1 %d, label %bb2, label %bb3 +bb2: + call void @llvm.lifetime.end(i64 -1, i8* %x0) + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %y) + ret void +bb3: + ret void +} + +; Missing lifetime.start +define void @nomerge4_nostart(i1 %d) safestack { +; CHECK-LABEL: define void @nomerge4_nostart( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 +; CHECK: call void @capture32( + call void @capture32(i32* %x) + call void @llvm.lifetime.end(i64 -1, i8* %x0) + br i1 %d, label %bb2, label %bb3 +bb2: + call void @llvm.lifetime.start(i64 -1, i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 +; CHECK: call void @capture32( + call void @capture32(i32* %y) + ret void +bb3: + ret void +} + +define void @array_merge() safestack { +; CHECK-LABEL: define void @array_merge( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800 + %A.i1 = alloca [100 x i32], align 4 + %B.i2 = alloca [100 x i32], align 4 + %A.i = alloca [100 x i32], align 4 + %B.i = alloca [100 x i32], align 4 + %0 = bitcast [100 x i32]* %A.i to i8* + call void @llvm.lifetime.start(i64 -1, i8* %0) + %1 = bitcast [100 x i32]* %B.i to i8* + call void @llvm.lifetime.start(i64 -1, i8* %1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -400 +; CHECK: call void @capture100x32( + call void @capture100x32([100 x i32]* %A.i) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -800 +; CHECK: call void @capture100x32( + call void @capture100x32([100 x i32]* %B.i) + call void @llvm.lifetime.end(i64 -1, i8* %0) + call void @llvm.lifetime.end(i64 -1, i8* %1) + %2 = bitcast [100 x i32]* %A.i1 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %2) + %3 = bitcast [100 x i32]* %B.i2 to i8* + call void @llvm.lifetime.start(i64 -1, i8* %3) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -400 +; CHECK: call void @capture100x32( + call void @capture100x32([100 x i32]* %A.i1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -800 +; CHECK: call void @capture100x32( + call void @capture100x32([100 x i32]* %B.i2) + call void @llvm.lifetime.end(i64 -1, i8* %2) + call void @llvm.lifetime.end(i64 -1, i8* %3) + ret void +} + +define void @myCall_pr15707() safestack { +; CHECK-LABEL: define void @myCall_pr15707( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -200000 + %buf1 = alloca i8, i32 100000, align 16 + %buf2 = alloca i8, i32 100000, align 16 + + call void @llvm.lifetime.start(i64 -1, i8* %buf1) + call void @llvm.lifetime.end(i64 -1, i8* %buf1) + + call void @llvm.lifetime.start(i64 -1, i8* %buf1) + call void @llvm.lifetime.start(i64 -1, i8* %buf2) + call void @capture8(i8* %buf1) + call void @capture8(i8* %buf2) + ret void +} + +; Check that we don't assert and crash even when there are allocas +; outside the declared lifetime regions. +define void @bad_range() safestack { +; CHECK-LABEL: define void @bad_range( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; A.i and B.i unsafe, not merged +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800 +; A.i1 and B.i2 safe +; CHECK: = alloca [100 x i32], align 4 +; CHECK: = alloca [100 x i32], align 4 + + %A.i1 = alloca [100 x i32], align 4 + %B.i2 = alloca [100 x i32], align 4 + %A.i = alloca [100 x i32], align 4 + %B.i = alloca [100 x i32], align 4 + %0 = bitcast [100 x i32]* %A.i to i8* + call void @llvm.lifetime.start(i64 -1, i8* %0) nounwind + %1 = bitcast [100 x i32]* %B.i to i8* + call void @llvm.lifetime.start(i64 -1, i8* %1) nounwind + call void @capture100x32([100 x i32]* %A.i) + call void @capture100x32([100 x i32]* %B.i) + call void @llvm.lifetime.end(i64 -1, i8* %0) nounwind + call void @llvm.lifetime.end(i64 -1, i8* %1) nounwind + br label %block2 + +block2: + ; I am used outside the marked lifetime. + call void @capture100x32([100 x i32]* %A.i) + call void @capture100x32([100 x i32]* %B.i) + ret void +} + +%struct.Klass = type { i32, i32 } + +define i32 @shady_range(i32 %argc, i8** nocapture %argv) safestack { +; CHECK-LABEL: define i32 @shady_range( +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -64 + %a.i = alloca [4 x %struct.Klass], align 16 + %b.i = alloca [4 x %struct.Klass], align 16 + %a8 = bitcast [4 x %struct.Klass]* %a.i to i8* + %b8 = bitcast [4 x %struct.Klass]* %b.i to i8* + ; I am used outside the lifetime zone below: + %z2 = getelementptr inbounds [4 x %struct.Klass], [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0 + call void @llvm.lifetime.start(i64 -1, i8* %a8) + call void @llvm.lifetime.start(i64 -1, i8* %b8) + call void @capture8(i8* %a8) + call void @capture8(i8* %b8) + %z3 = load i32, i32* %z2, align 16 + call void @llvm.lifetime.end(i64 -1, i8* %a8) + call void @llvm.lifetime.end(i64 -1, i8* %b8) + ret i32 %z3 +} + +define void @end_loop() safestack { +; CHECK-LABEL: define void @end_loop() +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i8, align 4 + call void @llvm.lifetime.start(i64 4, i8* %x) nounwind + br label %l2 + +l2: + call void @capture8(i8* %x) + call void @llvm.lifetime.end(i64 4, i8* %x) nounwind + br label %l2 +} + +; Check that @x and @y get distinct stack slots => @x lifetime does not break +; when control re-enters l2. +define void @start_loop() safestack { +; CHECK-LABEL: define void @start_loop() +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 + %x = alloca i8, align 4 + %y = alloca i8, align 4 + call void @llvm.lifetime.start(i64 4, i8* %x) nounwind + br label %l2 + +l2: +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @llvm.lifetime.start(i64 4, i8* %y) nounwind + call void @capture8(i8* %y) + call void @llvm.lifetime.end(i64 4, i8* %y) nounwind + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @llvm.lifetime.start(i64 4, i8* %x) nounwind + call void @capture8(i8* %x) + br label %l2 +} + +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) +declare void @capture8(i8*) +declare void @capture32(i32*) +declare void @capture64(i64*) +declare void @capture100x32([100 x i32]*) Index: llvm/trunk/test/Transforms/SafeStack/X86/constant-gep-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/constant-gep-call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/constant-gep-call.ll @@ -0,0 +1,26 @@ +; 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 + +%struct.nest = type { %struct.pair, %struct.pair } +%struct.pair = type { i32, i32 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Nested structure, no arrays, no address-of expressions. +; Verify that the resulting gep-of-gep does not incorrectly trigger +; a safe stack protector. +; safestack attribute +; Requires no protector. +; CHECK-LABEL: @foo( +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK-NOT: __safestack_unsafe_stack_ptr + %c = alloca %struct.nest, align 4 + %b = getelementptr inbounds %struct.nest, %struct.nest* %c, i32 0, i32 1 + %_a = getelementptr inbounds %struct.pair, %struct.pair* %b, i32 0, i32 0 + %0 = load i32, i32* %_a, align 4 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %0) + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/constant-gep.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/constant-gep.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/constant-gep.ll @@ -0,0 +1,20 @@ +; 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 + +%class.A = type { [2 x i8] } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; [2 x i8] in a class +; safestack attribute +; Requires no protector. +; CHECK-LABEL: @foo( +define signext i8 @foo() nounwind uwtable safestack { +entry: + ; CHECK-NOT: __safestack_unsafe_stack_ptr + %a = alloca %class.A, align 1 + %array = getelementptr inbounds %class.A, %class.A* %a, i32 0, i32 0 + %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} Index: llvm/trunk/test/Transforms/SafeStack/X86/constant-geps.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/constant-geps.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/constant-geps.ll @@ -0,0 +1,28 @@ +; 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 + +%struct.deep = type { %union.anon } +%union.anon = type { %struct.anon } +%struct.anon = type { %struct.anon.0 } +%struct.anon.0 = type { %union.anon.1 } +%union.anon.1 = type { [2 x i8] } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; [2 x i8] nested in several layers of structs and unions +; safestack attribute +; Requires no protector. +; CHECK-LABEL: @foo( +define signext i8 @foo() nounwind uwtable safestack { +entry: + ; CHECK-NOT: __safestack_unsafe_stack_ptr + %x = alloca %struct.deep, align 1 + %b = getelementptr inbounds %struct.deep, %struct.deep* %x, i32 0, i32 0 + %c = bitcast %union.anon* %b to %struct.anon* + %d = getelementptr inbounds %struct.anon, %struct.anon* %c, i32 0, i32 0 + %e = getelementptr inbounds %struct.anon.0, %struct.anon.0* %d, i32 0, i32 0 + %array = bitcast %union.anon.1* %e to [2 x i8]* + %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0 + %0 = load i8, i8* %arrayidx, align 1 + ret i8 %0 +} Index: llvm/trunk/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/debug-loc-dynamic.ll @@ -0,0 +1,57 @@ +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s + +; Test llvm.dbg.value for dynamic allocas moved onto the unsafe stack. +; In the dynamic alloca case, the dbg.value does not change with the exception +; of the alloca pointer in the first argument being replaced with the new stack +; top address. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f(i32 %n) safestack !dbg !6 { +entry: + tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !11, metadata !14), !dbg !15 + %0 = zext i32 %n to i64, !dbg !16 + +; CHECK: store i8* %[[VLA:.*]], i8** @__safestack_unsafe_stack_ptr +; CHECK: tail call void @llvm.dbg.value(metadata i8* %[[VLA]], i64 0, metadata ![[TYPE:.*]], metadata ![[EXPR:.*]]) +; CHECK: call void @capture({{.*}} %[[VLA]]) + + %vla = alloca i8, i64 %0, align 16, !dbg !16 + tail call void @llvm.dbg.value(metadata i8* %vla, i64 0, metadata !12, metadata !17), !dbg !18 + call void @capture(i8* nonnull %vla), !dbg !19 + ret void, !dbg !20 +} + +declare void @capture(i8*) +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "../llvm/1.cc", directory: "/code/build-llvm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)"} +!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fi", scope: !1, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{null, !9} +!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!10 = !{!11, !12} +!11 = !DILocalVariable(name: "n", arg: 1, scope: !6, file: !1, line: 2, type: !9) + +; CHECK-DAG: ![[TYPE]] = !DILocalVariable(name: "x", +!12 = !DILocalVariable(name: "x", scope: !6, file: !1, line: 3, type: !13) +!13 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!14 = !DIExpression() +!15 = !DILocation(line: 2, column: 12, scope: !6) +!16 = !DILocation(line: 3, column: 3, scope: !6) + +; CHECK-DAG: ![[EXPR]] = !DIExpression(DW_OP_deref) +!17 = !DIExpression(DW_OP_deref) +!18 = !DILocation(line: 3, column: 8, scope: !6) +!19 = !DILocation(line: 4, column: 3, scope: !6) +!20 = !DILocation(line: 5, column: 1, scope: !6) Index: llvm/trunk/test/Transforms/SafeStack/X86/debug-loc.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/debug-loc.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/debug-loc.ll @@ -0,0 +1,82 @@ +; 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: FullDebug, enums: !2, retainedTypes: !3) +!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: !4, 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) +!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, unit: !0, variables: !2) +!13 = !DISubroutineType(types: !14) +!14 = !{null, !4} +!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: !4) +!19 = !DIExpression() +!20 = !DILocation(line: 10, column: 10, scope: !12) +!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !4) +!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) Index: llvm/trunk/test/Transforms/SafeStack/X86/debug-loc2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/debug-loc2.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/debug-loc2.ll @@ -0,0 +1,98 @@ +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s + +; Test llvm.dbg.value for the local variables moved onto the unsafe stack. +; SafeStack rewrites them relative to the unsafe stack pointer (base address of +; the unsafe stack frame). + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: noinline safestack uwtable +define void @f() #0 !dbg !6 { +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + %x1 = alloca i32, align 4 + %x2 = alloca i32, align 4 + %0 = bitcast i32* %x1 to i8*, !dbg !13 + %1 = bitcast i32* %x2 to i8*, !dbg !14 + +; Unhandled dbg.value: expression does not start with OP_DW_deref +; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY:.*]], i64 0, metadata !{{.*}}, metadata !{{.*}}) + tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !23), !dbg !16 + +; Unhandled dbg.value: expression does not start with OP_DW_deref +; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY]], i64 0, metadata !{{.*}}, metadata !{{.*}}) + tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !24), !dbg !16 + +; Supported dbg.value: rewritted based on the [[USP]] value. +; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X1:.*]], metadata ![[X1_EXPR:.*]]) + tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !15), !dbg !16 + call void @capture(i32* nonnull %x1), !dbg !17 + +; An extra non-dbg.value metadata use of %x2. Replaced with an empty metadata. +; CHECK: call void @llvm.random.metadata.use(metadata ![[EMPTY]]) + call void @llvm.random.metadata.use(metadata i32* %x2) + +; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X2:.*]], metadata ![[X2_EXPR:.*]]) + call void @llvm.dbg.value(metadata i32* %x2, i64 0, metadata !12, metadata !15), !dbg !18 + call void @capture(i32* nonnull %x2), !dbg !19 + ret void, !dbg !20 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start(i64, i8* nocapture) #1 + +declare void @capture(i32*) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #3 + +declare void @llvm.random.metadata.use(metadata) + +attributes #0 = { noinline safestack uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "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,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind readnone } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm") + +; CHECK-DAG: ![[EMPTY]] = !{} +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)"} +!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !1, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !9) +!7 = !DISubroutineType(types: !8) +!8 = !{null} +!9 = !{!10, !12} + +; CHECK-DAG: ![[X1]] = !DILocalVariable(name: "x1", +!10 = !DILocalVariable(name: "x1", scope: !6, file: !1, line: 5, type: !11) +!11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) + +; CHECK-DAG: ![[X2]] = !DILocalVariable(name: "x2", +!12 = !DILocalVariable(name: "x2", scope: !6, file: !1, line: 6, type: !11) +!13 = !DILocation(line: 5, column: 3, scope: !6) +!14 = !DILocation(line: 6, column: 3, scope: !6) + +; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 4) +; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 8) +!15 = !DIExpression(DW_OP_deref) +!16 = !DILocation(line: 5, column: 7, scope: !6) +!17 = !DILocation(line: 8, column: 3, scope: !6) +!18 = !DILocation(line: 6, column: 7, scope: !6) +!19 = !DILocation(line: 9, column: 3, scope: !6) +!20 = !DILocation(line: 10, column: 1, scope: !6) +!21 = !DILocation(line: 10, column: 1, scope: !22) +!22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 1) +!23 = !DIExpression() +!24 = !DIExpression(DW_OP_minus, 42) Index: llvm/trunk/test/Transforms/SafeStack/X86/dynamic-alloca.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/dynamic-alloca.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/dynamic-alloca.ll @@ -0,0 +1,22 @@ +; 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 + +; Variable sized alloca +; safestack attribute +; Requires protector. +define void @foo(i32 %n) nounwind uwtable safestack { +entry: + ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + %n.addr = alloca i32, align 4 + %a = alloca i32*, align 8 + store i32 %n, i32* %n.addr, align 4 + %0 = load i32, i32* %n.addr, align 4 + %conv = sext i32 %0 to i64 + %1 = alloca i8, i64 %conv + %2 = bitcast i8* %1 to i32* + store i32* %2, i32** %a, align 8 + ; CHECK: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr + ret void +} Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-addr-pointer.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-addr-pointer.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-addr-pointer.ll @@ -0,0 +1,23 @@ +; 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 + +; Addr-of a pointer +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %a = alloca i32*, align 8 + %b = alloca i32**, align 8 + %call = call i32* @getp() + store i32* %call, i32** %a, align 8 + store i32** %a, i32*** %b, align 8 + %0 = load i32**, i32*** %b, align 8 + call void @funcall2(i32** %0) + ret void +} + +declare void @funcall2(i32**) +declare i32* @getp() Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store.ll @@ -0,0 +1,23 @@ +; 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 + +; Addr-of a local cast to a ptr of a different type +; (e.g., int a; ... ; float *b = &a;) +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %a = alloca i32, align 4 + %b = alloca float*, align 8 + store i32 0, i32* %a, align 4 + %0 = bitcast i32* %a to float* + store float* %0, float** %b, align 8 + %1 = load float*, float** %b, align 8 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), float* %1) + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-bitcast-store2.ll @@ -0,0 +1,20 @@ +; 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 + +; Addr-of a local cast to a ptr of a different type (optimized) +; (e.g., int a; ... ; float *b = &a;) +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %a = alloca i32, align 4 + store i32 0, i32* %a, align 4 + %0 = bitcast i32* %a to float* + call void @funfloat(float* %0) nounwind + ret void +} + +declare void @funfloat(float*) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-call.ll @@ -0,0 +1,16 @@ +; 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 + +; Passing addr-of to function call +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %b = alloca i32, align 4 + call void @funcall(i32* %b) nounwind + ret void +} + +declare void @funcall(i32*) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-casted-pointer.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-casted-pointer.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-casted-pointer.ll @@ -0,0 +1,24 @@ +; 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 + +; Addr-of a casted pointer +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %a = alloca i32*, align 8 + %b = alloca float**, align 8 + %call = call i32* @getp() + store i32* %call, i32** %a, align 8 + %0 = bitcast i32** %a to float** + store float** %0, float*** %b, align 8 + %1 = load float**, float*** %b, align 8 + call void @funfloat2(float** %1) + ret void +} + +declare void @funfloat2(float**) +declare i32* @getp() Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-call.ll @@ -0,0 +1,20 @@ +; 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 + +%struct.pair = type { i32, i32 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Addr-of struct element, GEP followed by callinst. +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %c = alloca %struct.pair, align 4 + %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i64 0, i32 1 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %y) nounwind + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-invoke.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-invoke.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-invoke.ll @@ -0,0 +1,34 @@ +; 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 + +%struct.pair = type { i32, i32 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Addr-of a struct element passed into an invoke instruction. +; (GEP followed by an invoke) +; safestack attribute +; Requires protector. +define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %c = alloca %struct.pair, align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + %a = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0 + store i32 0, i32* %a, align 4 + %a1 = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0 + invoke void @_Z3exceptPi(i32* %a1) + to label %invoke.cont unwind label %lpad + +invoke.cont: + ret i32 0 + +lpad: + %0 = landingpad { i8*, i32 } + catch i8* null + ret i32 0 +} + +declare void @_Z3exceptPi(i32*) +declare i32 @__gxx_personality_v0(...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-negative.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-negative.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-negative.ll @@ -0,0 +1,18 @@ +; 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 + +; Addr-of a local, optimized into a GEP (e.g., &a - 12) +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %a = alloca i32, align 4 + %add.ptr5 = getelementptr inbounds i32, i32* %a, i64 -12 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %add.ptr5) nounwind + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-ptrtoint.ll @@ -0,0 +1,22 @@ +; 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 + +%struct.pair = type { i32, i32 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Addr-of struct element, GEP followed by ptrtoint. +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1 + %0 = ptrtoint i32* %y to i64 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i64 %0) + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-store.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-gep-store.ll @@ -0,0 +1,23 @@ +; 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 + +%struct.pair = type { i32, i32 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Addr-of struct element. (GEP followed by store). +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %c = alloca %struct.pair, align 4 + %b = alloca i32*, align 8 + %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1 + store i32* %y, i32** %b, align 8 + %0 = load i32*, i32** %b, align 8 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32* %0) + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-phi-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-phi-call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-phi-call.ll @@ -0,0 +1,36 @@ +; 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 + +; Addr-of in phi instruction +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp = fcmp ogt double %call, 3.140000e+00 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %call1 = call double @testi_aux() nounwind + store double %call1, double* %x, align 8 + br label %if.end4 + +if.else: ; preds = %entry + %cmp2 = fcmp ogt double %call, 1.000000e+00 + br i1 %cmp2, label %if.then3, label %if.end4 + +if.then3: ; preds = %if.else + br label %if.end4 + +if.end4: ; preds = %if.else, %if.then3, %if.then + %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] + %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind + ret void +} + +declare double @testi_aux() +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-select-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-select-call.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-select-call.ll @@ -0,0 +1,22 @@ +; 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 + +; Addr-of in select instruction +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %x = alloca double, align 8 + %call = call double @testi_aux() nounwind + store double %call, double* %x, align 8 + %cmp2 = fcmp ogt double %call, 0.000000e+00 + %y.1 = select i1 %cmp2, double* %x, double* null + %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), double* %y.1) + ret void +} + +declare double @testi_aux() +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/escape-vector.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/escape-vector.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/escape-vector.ll @@ -0,0 +1,21 @@ +; 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 + +%struct.vec = type { <4 x i32> } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Addr-of a vector nested in a struct +; safestack attribute +; Requires protector. +define void @foo() nounwind uwtable safestack { +entry: + ; CHECK: __safestack_unsafe_stack_ptr + %c = alloca %struct.vec, align 16 + %y = getelementptr inbounds %struct.vec, %struct.vec* %c, i64 0, i32 0 + %add.ptr = getelementptr inbounds <4 x i32>, <4 x i32>* %y, i64 -12 + %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), <4 x i32>* %add.ptr) nounwind + ret void +} + +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/invoke.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/invoke.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/invoke.ll @@ -0,0 +1,33 @@ +; 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 + +; Addr-of a variable passed into an invoke instruction. +; safestack attribute +; Requires protector and stack restore after landing pad. +define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16 + %a = alloca i32, align 4 + %exn.slot = alloca i8* + %ehselector.slot = alloca i32 + store i32 0, i32* %a, align 4 + invoke void @_Z3exceptPi(i32* %a) + to label %invoke.cont unwind label %lpad + +invoke.cont: + ret i32 0 + +lpad: + ; CHECK: landingpad + ; CHECK-NEXT: catch + %0 = landingpad { i8*, i32 } + catch i8* null + ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr + ret i32 0 +} + +declare void @_Z3exceptPi(i32*) +declare i32 @__gxx_personality_v0(...) Index: llvm/trunk/test/Transforms/SafeStack/X86/layout-frag.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/layout-frag.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/layout-frag.ll @@ -0,0 +1,39 @@ +; Test that safestack layout reuses a region w/o fragmentation. +; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s + +define void @f() safestack { +; CHECK-LABEL: define void @f +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + + %x0 = alloca i64, align 8 + %x1 = alloca i8, align 1 + %x2 = alloca i64, align 8 + + %x0a = bitcast i64* %x0 to i8* + %x2a = bitcast i64* %x2 to i8* + + call void @llvm.lifetime.start(i64 4, i8* %x0a) + call void @capture64(i64* %x0) + call void @llvm.lifetime.end(i64 4, i8* %x0a) + + call void @llvm.lifetime.start(i64 4, i8* %x1) + call void @llvm.lifetime.start(i64 4, i8* %x2a) + call void @capture8(i8* %x1) + call void @capture64(i64* %x2) + call void @llvm.lifetime.end(i64 4, i8* %x1) + call void @llvm.lifetime.end(i64 4, i8* %x2a) + +; Test that i64 allocas share space. +; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8 +; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -9 +; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8 + + ret void +} + +declare void @llvm.lifetime.start(i64, i8* nocapture) +declare void @llvm.lifetime.end(i64, i8* nocapture) +declare void @capture8(i8*) +declare void @capture64(i64*) Index: llvm/trunk/test/Transforms/SafeStack/X86/layout-region-split.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/layout-region-split.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/layout-region-split.ll @@ -0,0 +1,84 @@ +; Regression test for safestack layout. Used to fail with asan. +; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s + +define void @f() safestack { +; CHECK-LABEL: define void @f +entry: +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK: getelementptr i8, i8* %[[USP]], i32 -224 + + %x0 = alloca i8, align 16 + %x1 = alloca i8, align 16 + %x2 = alloca i8, align 16 + %x3 = alloca i8, align 16 + %x4 = alloca i8, align 16 + %x5 = alloca i8, align 16 + %x6 = alloca i8, align 16 + %x7 = alloca i8, align 16 + %x8 = alloca i8, align 16 + %x9 = alloca i8, align 16 + %x10 = alloca i8, align 16 + %x11 = alloca i8, align 16 + %x12 = alloca i8, align 16 + %x13 = alloca i8, align 16 + %y0 = alloca i8, align 2 + %y1 = alloca i8, align 2 + %y2 = alloca i8, align 2 + %y3 = alloca i8, align 2 + %y4 = alloca i8, align 2 + %y5 = alloca i8, align 2 + %y6 = alloca i8, align 2 + %y7 = alloca i8, align 2 + %y8 = alloca i8, align 2 + +; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 + call void @capture8(i8* %x0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 + call void @capture8(i8* %x1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -48 + call void @capture8(i8* %x2) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -64 + call void @capture8(i8* %x3) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -80 + call void @capture8(i8* %x4) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -96 + call void @capture8(i8* %x5) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -112 + call void @capture8(i8* %x6) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -128 + call void @capture8(i8* %x7) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -144 + call void @capture8(i8* %x8) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -160 + call void @capture8(i8* %x9) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -176 + call void @capture8(i8* %x10) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -192 + call void @capture8(i8* %x11) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -208 + call void @capture8(i8* %x12) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -224 + call void @capture8(i8* %x13) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -2 + call void @capture8(i8* %y0) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 + call void @capture8(i8* %y1) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -6 + call void @capture8(i8* %y2) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 + call void @capture8(i8* %y3) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -10 + call void @capture8(i8* %y4) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -12 + call void @capture8(i8* %y5) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -14 + call void @capture8(i8* %y6) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -18 + call void @capture8(i8* %y7) +; CHECK: getelementptr i8, i8* %[[USP]], i32 -20 + call void @capture8(i8* %y8) + + ret void +} + +declare void @capture8(i8*) Index: llvm/trunk/test/Transforms/SafeStack/X86/no-attr.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/no-attr.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/no-attr.ll @@ -0,0 +1,27 @@ +; 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 + +; no safestack attribute +; Requires no protector. + +; CHECK-NOT: __safestack_unsafe_stack_ptr + +; CHECK: @foo +define void @foo(i8* %a) nounwind uwtable { +entry: + ; CHECK-NOT: __safestack_unsafe_stack_ptr + %a.addr = alloca i8*, align 8 + %buf = alloca [16 x i8], align 16 + store i8* %a, i8** %a.addr, align 8 + %arraydecay = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 + %0 = load i8*, i8** %a.addr, align 8 + %call = call i8* @strcpy(i8* %arraydecay, i8* %0) + %arraydecay1 = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 + %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %arraydecay1) + ret void +} + +declare i8* @strcpy(i8*, i8*) +declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/X86/phi-cycle.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/phi-cycle.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/phi-cycle.ll @@ -0,0 +1,50 @@ +; 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 + +%struct.small = type { i8 } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; Address-of a structure taken in a function with a loop where +; the alloca is an incoming value to a PHI node and a use of that PHI +; node is also an incoming value. +; Verify that the address-of analysis does not get stuck in infinite +; recursion when chasing the alloca through the PHI nodes. +; Requires protector. +define i32 @foo(i32 %arg) nounwind uwtable safestack { +bb: + ; CHECK: __safestack_unsafe_stack_ptr + %tmp = alloca %struct.small*, align 8 + %tmp1 = call i32 (...) @dummy(%struct.small** %tmp) nounwind + %tmp2 = load %struct.small*, %struct.small** %tmp, align 8 + %tmp3 = ptrtoint %struct.small* %tmp2 to i64 + %tmp4 = trunc i64 %tmp3 to i32 + %tmp5 = icmp sgt i32 %tmp4, 0 + br i1 %tmp5, label %bb6, label %bb21 + +bb6: ; preds = %bb17, %bb + %tmp7 = phi %struct.small* [ %tmp19, %bb17 ], [ %tmp2, %bb ] + %tmp8 = phi i64 [ %tmp20, %bb17 ], [ 1, %bb ] + %tmp9 = phi i32 [ %tmp14, %bb17 ], [ %tmp1, %bb ] + %tmp10 = getelementptr inbounds %struct.small, %struct.small* %tmp7, i64 0, i32 0 + %tmp11 = load i8, i8* %tmp10, align 1 + %tmp12 = icmp eq i8 %tmp11, 1 + %tmp13 = add nsw i32 %tmp9, 8 + %tmp14 = select i1 %tmp12, i32 %tmp13, i32 %tmp9 + %tmp15 = trunc i64 %tmp8 to i32 + %tmp16 = icmp eq i32 %tmp15, %tmp4 + br i1 %tmp16, label %bb21, label %bb17 + +bb17: ; preds = %bb6 + %tmp18 = getelementptr inbounds %struct.small*, %struct.small** %tmp, i64 %tmp8 + %tmp19 = load %struct.small*, %struct.small** %tmp18, align 8 + %tmp20 = add i64 %tmp8, 1 + br label %bb6 + +bb21: ; preds = %bb6, %bb + %tmp22 = phi i32 [ %tmp1, %bb ], [ %tmp14, %bb6 ] + %tmp23 = call i32 (...) @dummy(i32 %tmp22) nounwind + ret i32 undef +} + +declare i32 @dummy(...) Index: llvm/trunk/test/Transforms/SafeStack/X86/phi.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/phi.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/phi.ll @@ -0,0 +1,35 @@ +; 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 + +define void @f(i1 %d1, i1 %d2) safestack { +entry: +; CHECK-LABEL: define void @f( +; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr +; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 +; CHECK: br i1 %d1, label %[[BB0:.*]], label %[[BB1:.*]] + %a = alloca i32, align 8 + %b = alloca i32, align 8 + br i1 %d1, label %bb0, label %bb1 + +bb0: +; CHECK: [[BB0]]: +; CHECK: %[[Ai8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32 +; CHECK: %[[AUNSAFE:.*]] = bitcast i8* %[[Ai8]] to i32* +; CHECK: br i1 + br i1 %d2, label %bb2, label %bb2 + +bb1: +; CHECK: [[BB1]]: +; CHECK: %[[Bi8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32 +; CHECK: %[[BUNSAFE:.*]] = bitcast i8* %[[Bi8]] to i32* +; CHECK: br label + br label %bb2 + +bb2: +; CHECK: phi i32* [ %[[AUNSAFE]], %[[BB0]] ], [ %[[AUNSAFE]], %[[BB0]] ], [ %[[BUNSAFE]], %[[BB1]] ] + %c = phi i32* [ %a, %bb0 ], [ %a, %bb0 ], [ %b, %bb1 ] + call void @capture(i32* %c) + ret void +} + +declare void @capture(i32*) Index: llvm/trunk/test/Transforms/SafeStack/X86/ret.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/ret.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/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 +} Index: llvm/trunk/test/Transforms/SafeStack/X86/setjmp.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/setjmp.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/setjmp.ll @@ -0,0 +1,37 @@ +; 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 + +%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t } +%struct.__sigset_t = type { [16 x i64] } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16 + +; setjmp/longjmp test. +; Requires protector. +define i32 @foo() nounwind uwtable safestack { +entry: + ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16 + %retval = alloca i32, align 4 + %x = alloca i32, align 4 + store i32 0, i32* %retval + store i32 42, i32* %x, align 4 + %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice + ; CHECK: setjmp + ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr + %tobool = icmp ne i32 %call, 0 + br i1 %tobool, label %if.else, label %if.then +if.then: ; preds = %entry + call void @funcall(i32* %x) + br label %if.end +if.else: ; preds = %entry + call i32 (...) @dummy() + br label %if.end +if.end: ; preds = %if.else, %if.then + ret i32 0 +} + +declare i32 @_setjmp(%struct.__jmp_buf_tag*) +declare void @funcall(i32*) +declare i32 @dummy(...) Index: llvm/trunk/test/Transforms/SafeStack/X86/setjmp2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/setjmp2.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/setjmp2.ll @@ -0,0 +1,43 @@ +; 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 + +%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t } +%struct.__sigset_t = type { [16 x i64] } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 +@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16 + +; setjmp/longjmp test with dynamically sized array. +; Requires protector. +; CHECK: @foo(i32 %[[ARG:.*]]) +define i32 @foo(i32 %size) nounwind uwtable safestack { +entry: + ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + ; CHECK-NEXT: %[[DYNPTR:.*]] = alloca i8* + ; CHECK-NEXT: store i8* %[[SP]], i8** %[[DYNPTR]] + + ; CHECK-NEXT: %[[ZEXT:.*]] = zext i32 %[[ARG]] to i64 + ; CHECK-NEXT: %[[MUL:.*]] = mul i64 %[[ZEXT]], 4 + ; CHECK-NEXT: %[[SP2:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + ; CHECK-NEXT: %[[PTRTOINT:.*]] = ptrtoint i8* %[[SP2]] to i64 + ; CHECK-NEXT: %[[SUB:.*]] = sub i64 %[[PTRTOINT]], %[[MUL]] + ; CHECK-NEXT: %[[AND:.*]] = and i64 %[[SUB]], -16 + ; 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:.*]] = bitcast i8* %[[INTTOPTR]] to i32* + %a = alloca i32, i32 %size + + ; CHECK: setjmp + ; CHECK-NEXT: %[[LOAD:.*]] = load i8*, i8** %[[DYNPTR]] + ; CHECK-NEXT: store i8* %[[LOAD]], i8** @__safestack_unsafe_stack_ptr + %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice + + ; CHECK: call void @funcall(i32* %[[ALLOCA]]) + call void @funcall(i32* %a) + ; CHECK-NEXT: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr + ret i32 0 +} + +declare i32 @_setjmp(%struct.__jmp_buf_tag*) +declare void @funcall(i32*) Index: llvm/trunk/test/Transforms/SafeStack/X86/sink-to-use.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/sink-to-use.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/sink-to-use.ll @@ -0,0 +1,22 @@ +; Test that unsafe alloca address calculation is done immediately before each use. +; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s +; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s + +define void @f() safestack { +entry: + %x0 = alloca i32, align 4 + %x1 = alloca i32, align 4 + +; CHECK: %[[A:.*]] = getelementptr i8, i8* %{{.*}}, i32 -4 +; CHECK: %[[X0:.*]] = bitcast i8* %[[A]] to i32* +; CHECK: call void @use(i32* %[[X0]]) + call void @use(i32* %x0) + +; CHECK: %[[B:.*]] = getelementptr i8, i8* %{{.*}}, i32 -8 +; CHECK: %[[X1:.*]] = bitcast i8* %[[B]] to i32* +; CHECK: call void @use(i32* %[[X1]]) + call void @use(i32* %x1) + ret void +} + +declare void @use(i32*) Index: llvm/trunk/test/Transforms/SafeStack/X86/store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/store.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/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 +} Index: llvm/trunk/test/Transforms/SafeStack/X86/struct.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/X86/struct.ll +++ llvm/trunk/test/Transforms/SafeStack/X86/struct.ll @@ -0,0 +1,40 @@ +; 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 + +%struct.foo = type { [16 x i8] } + +@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 + +; struct { [16 x i8] } + +define void @foo(i8* %a) nounwind uwtable safestack { +entry: + ; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr + + ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + + ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr + + %a.addr = alloca i8*, align 8 + %buf = alloca %struct.foo, align 1 + + ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 + ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 + store i8* %a, i8** %a.addr, align 8 + + ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 + ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo* + ; CHECK: %[[GEP:.*]] = getelementptr inbounds %struct.foo, %struct.foo* %[[BUFPTR2]], i32 0, i32 0, i32 0 + %gep = getelementptr inbounds %struct.foo, %struct.foo* %buf, i32 0, i32 0, i32 0 + + ; CHECK: %[[A:.*]] = load i8*, i8** %[[AADDR]], align 8 + %a2 = load i8*, i8** %a.addr, align 8 + + ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A]]) + %call = call i8* @strcpy(i8* %gep, i8* %a2) + + ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr + ret void +} + +declare i8* @strcpy(i8*, i8*) Index: llvm/trunk/test/Transforms/SafeStack/addr-taken.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/addr-taken.ll +++ llvm/trunk/test/Transforms/SafeStack/addr-taken.ll @@ -1,22 +0,0 @@ -; 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 - -; Address-of local taken (j = &a) -; Requires protector. - -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %retval = alloca i32, align 4 - %a = alloca i32, align 4 - %j = alloca i32*, align 8 - store i32 0, i32* %retval - %0 = load i32, i32* %a, align 4 - %add = add nsw i32 %0, 1 - store i32 %add, i32* %a, align 4 - store i32* %a, i32** %j, align 8 - ret void -} - Index: llvm/trunk/test/Transforms/SafeStack/array-aligned.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/array-aligned.ll +++ llvm/trunk/test/Transforms/SafeStack/array-aligned.ll @@ -1,38 +0,0 @@ -; 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 - -; array of [16 x i8] - -define void @foo(i8* %a) nounwind uwtable safestack { -entry: - ; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - - ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - - ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - - %a.addr = alloca i8*, align 8 - %buf = alloca [16 x i8], align 16 - - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 - ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 - store i8* %a, i8** %a.addr, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]* - ; CHECK: %[[GEP:.*]] = getelementptr inbounds [16 x i8], [16 x i8]* %[[BUFPTR2]], i32 0, i32 0 - %gep = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 - - ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8 - %a2 = load i8*, i8** %a.addr, align 8 - - ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]]) - %call = call i8* @strcpy(i8* %gep, i8* %a2) - - ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr - ret void -} - -declare i8* @strcpy(i8*, i8*) Index: llvm/trunk/test/Transforms/SafeStack/array.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/array.ll +++ llvm/trunk/test/Transforms/SafeStack/array.ll @@ -1,90 +0,0 @@ -; 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 - - ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - - ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - - %a.addr = alloca i8*, align 8 - %buf = alloca [4 x i8], align 1 - - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 - ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 - store i8* %a, i8** %a.addr, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]* - ; CHECK: %[[GEP:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUFPTR2]], i32 0, i32 0 - %gep = getelementptr inbounds [4 x i8], [4 x i8]* %buf, i32 0, i32 0 - - ; CHECK: %[[A2:.*]] = load i8*, i8** %[[AADDR]], align 8 - %a2 = load i8*, i8** %a.addr, align 8 - - ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A2]]) - %call = call i8* @strcpy(i8* %gep, i8* %a2) - - ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr - 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*) Index: llvm/trunk/test/Transforms/SafeStack/byval.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/byval.ll +++ llvm/trunk/test/Transforms/SafeStack/byval.ll @@ -1,51 +0,0 @@ -; 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 -} - Index: llvm/trunk/test/Transforms/SafeStack/call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/call.ll +++ llvm/trunk/test/Transforms/SafeStack/call.ll @@ -1,178 +0,0 @@ -; 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 - -; no arrays / no nested arrays -; Requires no protector. - -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 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %0) - ret void -} - -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 Index: llvm/trunk/test/Transforms/SafeStack/cast.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/cast.ll +++ llvm/trunk/test/Transforms/SafeStack/cast.ll @@ -1,39 +0,0 @@ -; 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 - -; PtrToInt/IntToPtr Cast - -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 -} Index: llvm/trunk/test/Transforms/SafeStack/coloring-ssp.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/coloring-ssp.ll +++ llvm/trunk/test/Transforms/SafeStack/coloring-ssp.ll @@ -1,34 +0,0 @@ -; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s - -; %x and %y share a stack slot between them, but not with the stack guard. -define void @f() safestack sspreq { -; CHECK-LABEL: define void @f -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - -; CHECK: %[[A:.*]] = getelementptr i8, i8* %[[USP]], i32 -8 -; CHECK: %[[StackGuardSlot:.*]] = bitcast i8* %[[A]] to i8** -; CHECK: store i8* %{{.*}}, i8** %[[StackGuardSlot]] - - %x = alloca i64, align 8 - %y = alloca i64, align 8 - %x0 = bitcast i64* %x to i8* - %y0 = bitcast i64* %y to i8* - - call void @llvm.lifetime.start(i64 -1, i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - call void @capture64(i64* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - call void @capture64(i64* %y) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - - ret void -} - -declare void @llvm.lifetime.start(i64, i8* nocapture) -declare void @llvm.lifetime.end(i64, i8* nocapture) -declare void @capture64(i64*) Index: llvm/trunk/test/Transforms/SafeStack/coloring.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/coloring.ll +++ llvm/trunk/test/Transforms/SafeStack/coloring.ll @@ -1,44 +0,0 @@ -; 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 - -define void @f() safestack { -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - - %x = alloca i32, align 4 - %x1 = alloca i32, align 4 - %x2 = alloca i32, align 4 - %0 = bitcast i32* %x to i8* - call void @llvm.lifetime.start(i64 4, i8* %0) - -; CHECK: %[[A1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: %[[A2:.*]] = bitcast i8* %[[A1]] to i32* -; CHECK: call void @capture(i32* nonnull %[[A2]]) - - call void @capture(i32* nonnull %x) - call void @llvm.lifetime.end(i64 4, i8* %0) - %1 = bitcast i32* %x1 to i8* - call void @llvm.lifetime.start(i64 4, i8* %1) - -; CHECK: %[[B1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: %[[B2:.*]] = bitcast i8* %[[B1]] to i32* -; CHECK: call void @capture(i32* nonnull %[[B2]]) - - call void @capture(i32* nonnull %x1) - call void @llvm.lifetime.end(i64 4, i8* %1) - %2 = bitcast i32* %x2 to i8* - call void @llvm.lifetime.start(i64 4, i8* %2) - -; CHECK: %[[C1:.*]] = getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: %[[C2:.*]] = bitcast i8* %[[C1]] to i32* -; CHECK: call void @capture(i32* nonnull %[[C2]]) - - call void @capture(i32* nonnull %x2) - call void @llvm.lifetime.end(i64 4, i8* %2) - ret void -} - -declare void @llvm.lifetime.start(i64, i8* nocapture) -declare void @llvm.lifetime.end(i64, i8* nocapture) -declare void @capture(i32*) Index: llvm/trunk/test/Transforms/SafeStack/coloring2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/coloring2.ll +++ llvm/trunk/test/Transforms/SafeStack/coloring2.ll @@ -1,521 +0,0 @@ -; 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 - -; x and y share the stack slot. -define void @f() safestack { -; CHECK-LABEL: define void @f -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %z = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - %z0 = bitcast i32* %z to i8* - - call void @llvm.lifetime.start(i64 -1, i8* %z0) - call void @llvm.lifetime.start(i64 -1, i8* %x0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - call void @llvm.lifetime.start(i64 -1, i8* %y0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @capture32(i32* %y) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture32(i32* %z) - call void @llvm.lifetime.end(i64 -1, i8* %z0) - - ret void -} - -define void @no_markers() safestack { -; CHECK-LABEL: define void @no_markers( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - - call void @llvm.lifetime.start(i64 -1, i8* %x0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture32(i32* %y) - - ret void -} - -; x and y can't share memory, but they can split z's storage. -define void @g() safestack { -; CHECK-LABEL: define void @g -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %z = alloca i64, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - %z0 = bitcast i64* %z to i8* - - call void @llvm.lifetime.start(i64 -1, i8* %x0) - call void @llvm.lifetime.start(i64 -1, i8* %y0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture32(i32* %y) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - call void @llvm.lifetime.start(i64 -1, i8* %z0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture64(i64* %z) - call void @llvm.lifetime.end(i64 -1, i8* %z0) - - ret void -} - -; Both y and z fit in x's alignment gap. -define void @h() safestack { -; CHECK-LABEL: define void @h -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - - %x = alloca i32, align 16 - %z = alloca i64, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - %z0 = bitcast i64* %z to i8* - - call void @llvm.lifetime.start(i64 -1, i8* %x0) - call void @llvm.lifetime.start(i64 -1, i8* %y0) - call void @llvm.lifetime.start(i64 -1, i8* %z0) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - call void @capture32(i32* %x) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -12 - call void @capture32(i32* %y) - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture64(i64* %z) - - call void @llvm.lifetime.end(i64 -1, i8* %x0) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - call void @llvm.lifetime.end(i64 -1, i8* %z0) - - ret void -} - -; void f(bool a, bool b) { -; long x1, x2; capture64(&x1); capture64(&x2); -; if (a) { -; long y; capture64(&y); -; if (b) { -; long y1; capture64(&y1); -; } else { -; long y2; capture64(&y2); -; } -; } else { -; long z; capture64(&z); -; if (b) { -; long z1; capture64(&z1); -; } else { -; long z2; capture64(&z2); -; } -; } -; } -; Everything fits in 4 x 64-bit slots. -define void @i(i1 zeroext %a, i1 zeroext %b) safestack { -; CHECK-LABEL: define void @i -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -32 - %x1 = alloca i64, align 8 - %x2 = alloca i64, align 8 - %y = alloca i64, align 8 - %y1 = alloca i64, align 8 - %y2 = alloca i64, align 8 - %z = alloca i64, align 8 - %z1 = alloca i64, align 8 - %z2 = alloca i64, align 8 - %0 = bitcast i64* %x1 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %0) - %1 = bitcast i64* %x2 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %x1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %x2) - br i1 %a, label %if.then, label %if.else4 - -if.then: ; preds = %entry - %2 = bitcast i64* %y to i8* - call void @llvm.lifetime.start(i64 -1, i8* %2) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -24 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %y) - br i1 %b, label %if.then3, label %if.else - -if.then3: ; preds = %if.then - %3 = bitcast i64* %y1 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %3) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %y1) - call void @llvm.lifetime.end(i64 -1, i8* %3) - br label %if.end - -if.else: ; preds = %if.then - %4 = bitcast i64* %y2 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %4) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %y2) - call void @llvm.lifetime.end(i64 -1, i8* %4) - br label %if.end - -if.end: ; preds = %if.else, %if.then3 - call void @llvm.lifetime.end(i64 -1, i8* %2) - br label %if.end9 - -if.else4: ; preds = %entry - %5 = bitcast i64* %z to i8* - call void @llvm.lifetime.start(i64 -1, i8* %5) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -24 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %z) - br i1 %b, label %if.then6, label %if.else7 - -if.then6: ; preds = %if.else4 - %6 = bitcast i64* %z1 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %6) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %z1) - call void @llvm.lifetime.end(i64 -1, i8* %6) - br label %if.end8 - -if.else7: ; preds = %if.else4 - %7 = bitcast i64* %z2 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %7) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 -; CHECK: call void @capture64( - call void @capture64(i64* nonnull %z2) - call void @llvm.lifetime.end(i64 -1, i8* %7) - br label %if.end8 - -if.end8: ; preds = %if.else7, %if.then6 - call void @llvm.lifetime.end(i64 -1, i8* %5) - br label %if.end9 - -if.end9: ; preds = %if.end8, %if.end - call void @llvm.lifetime.end(i64 -1, i8* %1) - call void @llvm.lifetime.end(i64 -1, i8* %0) - ret void -} - -; lifetime for x ends in 2 different BBs -define void @no_merge1(i1 %d) safestack { -; CHECK-LABEL: define void @no_merge1( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - call void @llvm.lifetime.start(i64 -1, i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %x) - br i1 %d, label %bb2, label %bb3 -bb2: - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 -; CHECK: call void @capture32( - call void @capture32(i32* %y) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - ret void -bb3: - call void @llvm.lifetime.end(i64 -1, i8* %x0) - ret void -} - -define void @merge1(i1 %d) safestack { -; CHECK-LABEL: define void @merge1( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - call void @llvm.lifetime.start(i64 -1, i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - br i1 %d, label %bb2, label %bb3 -bb2: - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %y) - call void @llvm.lifetime.end(i64 -1, i8* %y0) - ret void -bb3: - ret void -} - -; Missing lifetime.end -define void @merge2_noend(i1 %d) safestack { -; CHECK-LABEL: define void @merge2_noend( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - call void @llvm.lifetime.start(i64 -1, i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - br i1 %d, label %bb2, label %bb3 -bb2: - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %y) - ret void -bb3: - ret void -} - -; Missing lifetime.end -define void @merge3_noend(i1 %d) safestack { -; CHECK-LABEL: define void @merge3_noend( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* - call void @llvm.lifetime.start(i64 -1, i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %x) - br i1 %d, label %bb2, label %bb3 -bb2: - call void @llvm.lifetime.end(i64 -1, i8* %x0) - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %y) - ret void -bb3: - ret void -} - -; Missing lifetime.start -define void @nomerge4_nostart(i1 %d) safestack { -; CHECK-LABEL: define void @nomerge4_nostart( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %x0 = bitcast i32* %x to i8* - %y0 = bitcast i32* %y to i8* -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 -; CHECK: call void @capture32( - call void @capture32(i32* %x) - call void @llvm.lifetime.end(i64 -1, i8* %x0) - br i1 %d, label %bb2, label %bb3 -bb2: - call void @llvm.lifetime.start(i64 -1, i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 -; CHECK: call void @capture32( - call void @capture32(i32* %y) - ret void -bb3: - ret void -} - -define void @array_merge() safestack { -; CHECK-LABEL: define void @array_merge( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800 - %A.i1 = alloca [100 x i32], align 4 - %B.i2 = alloca [100 x i32], align 4 - %A.i = alloca [100 x i32], align 4 - %B.i = alloca [100 x i32], align 4 - %0 = bitcast [100 x i32]* %A.i to i8* - call void @llvm.lifetime.start(i64 -1, i8* %0) - %1 = bitcast [100 x i32]* %B.i to i8* - call void @llvm.lifetime.start(i64 -1, i8* %1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -400 -; CHECK: call void @capture100x32( - call void @capture100x32([100 x i32]* %A.i) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -800 -; CHECK: call void @capture100x32( - call void @capture100x32([100 x i32]* %B.i) - call void @llvm.lifetime.end(i64 -1, i8* %0) - call void @llvm.lifetime.end(i64 -1, i8* %1) - %2 = bitcast [100 x i32]* %A.i1 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %2) - %3 = bitcast [100 x i32]* %B.i2 to i8* - call void @llvm.lifetime.start(i64 -1, i8* %3) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -400 -; CHECK: call void @capture100x32( - call void @capture100x32([100 x i32]* %A.i1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -800 -; CHECK: call void @capture100x32( - call void @capture100x32([100 x i32]* %B.i2) - call void @llvm.lifetime.end(i64 -1, i8* %2) - call void @llvm.lifetime.end(i64 -1, i8* %3) - ret void -} - -define void @myCall_pr15707() safestack { -; CHECK-LABEL: define void @myCall_pr15707( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -200000 - %buf1 = alloca i8, i32 100000, align 16 - %buf2 = alloca i8, i32 100000, align 16 - - call void @llvm.lifetime.start(i64 -1, i8* %buf1) - call void @llvm.lifetime.end(i64 -1, i8* %buf1) - - call void @llvm.lifetime.start(i64 -1, i8* %buf1) - call void @llvm.lifetime.start(i64 -1, i8* %buf2) - call void @capture8(i8* %buf1) - call void @capture8(i8* %buf2) - ret void -} - -; Check that we don't assert and crash even when there are allocas -; outside the declared lifetime regions. -define void @bad_range() safestack { -; CHECK-LABEL: define void @bad_range( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; A.i and B.i unsafe, not merged -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -800 -; A.i1 and B.i2 safe -; CHECK: = alloca [100 x i32], align 4 -; CHECK: = alloca [100 x i32], align 4 - - %A.i1 = alloca [100 x i32], align 4 - %B.i2 = alloca [100 x i32], align 4 - %A.i = alloca [100 x i32], align 4 - %B.i = alloca [100 x i32], align 4 - %0 = bitcast [100 x i32]* %A.i to i8* - call void @llvm.lifetime.start(i64 -1, i8* %0) nounwind - %1 = bitcast [100 x i32]* %B.i to i8* - call void @llvm.lifetime.start(i64 -1, i8* %1) nounwind - call void @capture100x32([100 x i32]* %A.i) - call void @capture100x32([100 x i32]* %B.i) - call void @llvm.lifetime.end(i64 -1, i8* %0) nounwind - call void @llvm.lifetime.end(i64 -1, i8* %1) nounwind - br label %block2 - -block2: - ; I am used outside the marked lifetime. - call void @capture100x32([100 x i32]* %A.i) - call void @capture100x32([100 x i32]* %B.i) - ret void -} - -%struct.Klass = type { i32, i32 } - -define i32 @shady_range(i32 %argc, i8** nocapture %argv) safestack { -; CHECK-LABEL: define i32 @shady_range( -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -64 - %a.i = alloca [4 x %struct.Klass], align 16 - %b.i = alloca [4 x %struct.Klass], align 16 - %a8 = bitcast [4 x %struct.Klass]* %a.i to i8* - %b8 = bitcast [4 x %struct.Klass]* %b.i to i8* - ; I am used outside the lifetime zone below: - %z2 = getelementptr inbounds [4 x %struct.Klass], [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0 - call void @llvm.lifetime.start(i64 -1, i8* %a8) - call void @llvm.lifetime.start(i64 -1, i8* %b8) - call void @capture8(i8* %a8) - call void @capture8(i8* %b8) - %z3 = load i32, i32* %z2, align 16 - call void @llvm.lifetime.end(i64 -1, i8* %a8) - call void @llvm.lifetime.end(i64 -1, i8* %b8) - ret i32 %z3 -} - -define void @end_loop() safestack { -; CHECK-LABEL: define void @end_loop() -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i8, align 4 - call void @llvm.lifetime.start(i64 4, i8* %x) nounwind - br label %l2 - -l2: - call void @capture8(i8* %x) - call void @llvm.lifetime.end(i64 4, i8* %x) nounwind - br label %l2 -} - -; Check that @x and @y get distinct stack slots => @x lifetime does not break -; when control re-enters l2. -define void @start_loop() safestack { -; CHECK-LABEL: define void @start_loop() -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 - %x = alloca i8, align 4 - %y = alloca i8, align 4 - call void @llvm.lifetime.start(i64 4, i8* %x) nounwind - br label %l2 - -l2: -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @llvm.lifetime.start(i64 4, i8* %y) nounwind - call void @capture8(i8* %y) - call void @llvm.lifetime.end(i64 4, i8* %y) nounwind - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @llvm.lifetime.start(i64 4, i8* %x) nounwind - call void @capture8(i8* %x) - br label %l2 -} - -declare void @llvm.lifetime.start(i64, i8* nocapture) -declare void @llvm.lifetime.end(i64, i8* nocapture) -declare void @capture8(i8*) -declare void @capture32(i32*) -declare void @capture64(i64*) -declare void @capture100x32([100 x i32]*) Index: llvm/trunk/test/Transforms/SafeStack/constant-gep-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/constant-gep-call.ll +++ llvm/trunk/test/Transforms/SafeStack/constant-gep-call.ll @@ -1,26 +0,0 @@ -; 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 - -%struct.nest = type { %struct.pair, %struct.pair } -%struct.pair = type { i32, i32 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Nested structure, no arrays, no address-of expressions. -; Verify that the resulting gep-of-gep does not incorrectly trigger -; a safe stack protector. -; safestack attribute -; Requires no protector. -; CHECK-LABEL: @foo( -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK-NOT: __safestack_unsafe_stack_ptr - %c = alloca %struct.nest, align 4 - %b = getelementptr inbounds %struct.nest, %struct.nest* %c, i32 0, i32 1 - %_a = getelementptr inbounds %struct.pair, %struct.pair* %b, i32 0, i32 0 - %0 = load i32, i32* %_a, align 4 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %0) - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/constant-gep.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/constant-gep.ll +++ llvm/trunk/test/Transforms/SafeStack/constant-gep.ll @@ -1,20 +0,0 @@ -; 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 - -%class.A = type { [2 x i8] } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; [2 x i8] in a class -; safestack attribute -; Requires no protector. -; CHECK-LABEL: @foo( -define signext i8 @foo() nounwind uwtable safestack { -entry: - ; CHECK-NOT: __safestack_unsafe_stack_ptr - %a = alloca %class.A, align 1 - %array = getelementptr inbounds %class.A, %class.A* %a, i32 0, i32 0 - %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0 - %0 = load i8, i8* %arrayidx, align 1 - ret i8 %0 -} Index: llvm/trunk/test/Transforms/SafeStack/constant-geps.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/constant-geps.ll +++ llvm/trunk/test/Transforms/SafeStack/constant-geps.ll @@ -1,28 +0,0 @@ -; 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 - -%struct.deep = type { %union.anon } -%union.anon = type { %struct.anon } -%struct.anon = type { %struct.anon.0 } -%struct.anon.0 = type { %union.anon.1 } -%union.anon.1 = type { [2 x i8] } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; [2 x i8] nested in several layers of structs and unions -; safestack attribute -; Requires no protector. -; CHECK-LABEL: @foo( -define signext i8 @foo() nounwind uwtable safestack { -entry: - ; CHECK-NOT: __safestack_unsafe_stack_ptr - %x = alloca %struct.deep, align 1 - %b = getelementptr inbounds %struct.deep, %struct.deep* %x, i32 0, i32 0 - %c = bitcast %union.anon* %b to %struct.anon* - %d = getelementptr inbounds %struct.anon, %struct.anon* %c, i32 0, i32 0 - %e = getelementptr inbounds %struct.anon.0, %struct.anon.0* %d, i32 0, i32 0 - %array = bitcast %union.anon.1* %e to [2 x i8]* - %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %array, i32 0, i64 0 - %0 = load i8, i8* %arrayidx, align 1 - ret i8 %0 -} Index: llvm/trunk/test/Transforms/SafeStack/debug-loc-dynamic.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/debug-loc-dynamic.ll +++ llvm/trunk/test/Transforms/SafeStack/debug-loc-dynamic.ll @@ -1,57 +0,0 @@ -; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s - -; Test llvm.dbg.value for dynamic allocas moved onto the unsafe stack. -; In the dynamic alloca case, the dbg.value does not change with the exception -; of the alloca pointer in the first argument being replaced with the new stack -; top address. - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define void @f(i32 %n) safestack !dbg !6 { -entry: - tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !11, metadata !14), !dbg !15 - %0 = zext i32 %n to i64, !dbg !16 - -; CHECK: store i8* %[[VLA:.*]], i8** @__safestack_unsafe_stack_ptr -; CHECK: tail call void @llvm.dbg.value(metadata i8* %[[VLA]], i64 0, metadata ![[TYPE:.*]], metadata ![[EXPR:.*]]) -; CHECK: call void @capture({{.*}} %[[VLA]]) - - %vla = alloca i8, i64 %0, align 16, !dbg !16 - tail call void @llvm.dbg.value(metadata i8* %vla, i64 0, metadata !12, metadata !17), !dbg !18 - call void @capture(i8* nonnull %vla), !dbg !19 - ret void, !dbg !20 -} - -declare void @capture(i8*) -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4} -!llvm.ident = !{!5} - -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) -!1 = !DIFile(filename: "../llvm/1.cc", directory: "/code/build-llvm") -!2 = !{} -!3 = !{i32 2, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} -!5 = !{!"clang version 3.9.0 (trunk 272832) (llvm/trunk 272831)"} -!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fi", scope: !1, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !10) -!7 = !DISubroutineType(types: !8) -!8 = !{null, !9} -!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!10 = !{!11, !12} -!11 = !DILocalVariable(name: "n", arg: 1, scope: !6, file: !1, line: 2, type: !9) - -; CHECK-DAG: ![[TYPE]] = !DILocalVariable(name: "x", -!12 = !DILocalVariable(name: "x", scope: !6, file: !1, line: 3, type: !13) -!13 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) -!14 = !DIExpression() -!15 = !DILocation(line: 2, column: 12, scope: !6) -!16 = !DILocation(line: 3, column: 3, scope: !6) - -; CHECK-DAG: ![[EXPR]] = !DIExpression(DW_OP_deref) -!17 = !DIExpression(DW_OP_deref) -!18 = !DILocation(line: 3, column: 8, scope: !6) -!19 = !DILocation(line: 4, column: 3, scope: !6) -!20 = !DILocation(line: 5, column: 1, scope: !6) Index: llvm/trunk/test/Transforms/SafeStack/debug-loc.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/debug-loc.ll +++ llvm/trunk/test/Transforms/SafeStack/debug-loc.ll @@ -1,82 +0,0 @@ -; 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: FullDebug, enums: !2, retainedTypes: !3) -!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: !4, 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) -!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, unit: !0, variables: !2) -!13 = !DISubroutineType(types: !14) -!14 = !{null, !4} -!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: !4) -!19 = !DIExpression() -!20 = !DILocation(line: 10, column: 10, scope: !12) -!21 = !DILocalVariable(name: "xxx", scope: !12, file: !1, line: 11, type: !4) -!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) Index: llvm/trunk/test/Transforms/SafeStack/debug-loc2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/debug-loc2.ll +++ llvm/trunk/test/Transforms/SafeStack/debug-loc2.ll @@ -1,98 +0,0 @@ -; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s - -; Test llvm.dbg.value for the local variables moved onto the unsafe stack. -; SafeStack rewrites them relative to the unsafe stack pointer (base address of -; the unsafe stack frame). - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -; Function Attrs: noinline safestack uwtable -define void @f() #0 !dbg !6 { -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - %x1 = alloca i32, align 4 - %x2 = alloca i32, align 4 - %0 = bitcast i32* %x1 to i8*, !dbg !13 - %1 = bitcast i32* %x2 to i8*, !dbg !14 - -; Unhandled dbg.value: expression does not start with OP_DW_deref -; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY:.*]], i64 0, metadata !{{.*}}, metadata !{{.*}}) - tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !23), !dbg !16 - -; Unhandled dbg.value: expression does not start with OP_DW_deref -; CHECK: call void @llvm.dbg.value(metadata ![[EMPTY]], i64 0, metadata !{{.*}}, metadata !{{.*}}) - tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !24), !dbg !16 - -; Supported dbg.value: rewritted based on the [[USP]] value. -; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X1:.*]], metadata ![[X1_EXPR:.*]]) - tail call void @llvm.dbg.value(metadata i32* %x1, i64 0, metadata !10, metadata !15), !dbg !16 - call void @capture(i32* nonnull %x1), !dbg !17 - -; An extra non-dbg.value metadata use of %x2. Replaced with an empty metadata. -; CHECK: call void @llvm.random.metadata.use(metadata ![[EMPTY]]) - call void @llvm.random.metadata.use(metadata i32* %x2) - -; CHECK: call void @llvm.dbg.value(metadata i8* %[[USP]], i64 0, metadata ![[X2:.*]], metadata ![[X2_EXPR:.*]]) - call void @llvm.dbg.value(metadata i32* %x2, i64 0, metadata !12, metadata !15), !dbg !18 - call void @capture(i32* nonnull %x2), !dbg !19 - ret void, !dbg !20 -} - -; Function Attrs: argmemonly nounwind -declare void @llvm.lifetime.start(i64, i8* nocapture) #1 - -declare void @capture(i32*) #2 - -; Function Attrs: argmemonly nounwind -declare void @llvm.lifetime.end(i64, i8* nocapture) #1 - -; Function Attrs: nounwind readnone -declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #3 - -declare void @llvm.random.metadata.use(metadata) - -attributes #0 = { noinline safestack uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #1 = { argmemonly nounwind } -attributes #2 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "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,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } -attributes #3 = { nounwind readnone } -attributes #4 = { nounwind } - -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4} -!llvm.ident = !{!5} - -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) -!1 = !DIFile(filename: "../llvm/2.cc", directory: "/code/build-llvm") - -; CHECK-DAG: ![[EMPTY]] = !{} -!2 = !{} -!3 = !{i32 2, !"Dwarf Version", i32 4} -!4 = !{i32 2, !"Debug Info Version", i32 3} -!5 = !{!"clang version 3.9.0 (trunk 271022) (llvm/trunk 271027)"} -!6 = distinct !DISubprogram(name: "f", linkageName: "_Z1fv", scope: !1, file: !1, line: 4, type: !7, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !9) -!7 = !DISubroutineType(types: !8) -!8 = !{null} -!9 = !{!10, !12} - -; CHECK-DAG: ![[X1]] = !DILocalVariable(name: "x1", -!10 = !DILocalVariable(name: "x1", scope: !6, file: !1, line: 5, type: !11) -!11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) - -; CHECK-DAG: ![[X2]] = !DILocalVariable(name: "x2", -!12 = !DILocalVariable(name: "x2", scope: !6, file: !1, line: 6, type: !11) -!13 = !DILocation(line: 5, column: 3, scope: !6) -!14 = !DILocation(line: 6, column: 3, scope: !6) - -; CHECK-DAG: ![[X1_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 4) -; CHECK-DAG: ![[X2_EXPR]] = !DIExpression(DW_OP_deref, DW_OP_minus, 8) -!15 = !DIExpression(DW_OP_deref) -!16 = !DILocation(line: 5, column: 7, scope: !6) -!17 = !DILocation(line: 8, column: 3, scope: !6) -!18 = !DILocation(line: 6, column: 7, scope: !6) -!19 = !DILocation(line: 9, column: 3, scope: !6) -!20 = !DILocation(line: 10, column: 1, scope: !6) -!21 = !DILocation(line: 10, column: 1, scope: !22) -!22 = !DILexicalBlockFile(scope: !6, file: !1, discriminator: 1) -!23 = !DIExpression() -!24 = !DIExpression(DW_OP_minus, 42) Index: llvm/trunk/test/Transforms/SafeStack/dynamic-alloca.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/dynamic-alloca.ll +++ llvm/trunk/test/Transforms/SafeStack/dynamic-alloca.ll @@ -1,22 +0,0 @@ -; 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 - -; Variable sized alloca -; safestack attribute -; Requires protector. -define void @foo(i32 %n) nounwind uwtable safestack { -entry: - ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - %n.addr = alloca i32, align 4 - %a = alloca i32*, align 8 - store i32 %n, i32* %n.addr, align 4 - %0 = load i32, i32* %n.addr, align 4 - %conv = sext i32 %0 to i64 - %1 = alloca i8, i64 %conv - %2 = bitcast i8* %1 to i32* - store i32* %2, i32** %a, align 8 - ; CHECK: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr - ret void -} Index: llvm/trunk/test/Transforms/SafeStack/escape-addr-pointer.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-addr-pointer.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-addr-pointer.ll @@ -1,23 +0,0 @@ -; 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 - -; Addr-of a pointer -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %a = alloca i32*, align 8 - %b = alloca i32**, align 8 - %call = call i32* @getp() - store i32* %call, i32** %a, align 8 - store i32** %a, i32*** %b, align 8 - %0 = load i32**, i32*** %b, align 8 - call void @funcall2(i32** %0) - ret void -} - -declare void @funcall2(i32**) -declare i32* @getp() Index: llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store.ll @@ -1,23 +0,0 @@ -; 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 - -; Addr-of a local cast to a ptr of a different type -; (e.g., int a; ... ; float *b = &a;) -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %a = alloca i32, align 4 - %b = alloca float*, align 8 - store i32 0, i32* %a, align 4 - %0 = bitcast i32* %a to float* - store float* %0, float** %b, align 8 - %1 = load float*, float** %b, align 8 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), float* %1) - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store2.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-bitcast-store2.ll @@ -1,20 +0,0 @@ -; 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 - -; Addr-of a local cast to a ptr of a different type (optimized) -; (e.g., int a; ... ; float *b = &a;) -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %a = alloca i32, align 4 - store i32 0, i32* %a, align 4 - %0 = bitcast i32* %a to float* - call void @funfloat(float* %0) nounwind - ret void -} - -declare void @funfloat(float*) Index: llvm/trunk/test/Transforms/SafeStack/escape-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-call.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-call.ll @@ -1,16 +0,0 @@ -; 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 - -; Passing addr-of to function call -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %b = alloca i32, align 4 - call void @funcall(i32* %b) nounwind - ret void -} - -declare void @funcall(i32*) Index: llvm/trunk/test/Transforms/SafeStack/escape-casted-pointer.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-casted-pointer.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-casted-pointer.ll @@ -1,24 +0,0 @@ -; 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 - -; Addr-of a casted pointer -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %a = alloca i32*, align 8 - %b = alloca float**, align 8 - %call = call i32* @getp() - store i32* %call, i32** %a, align 8 - %0 = bitcast i32** %a to float** - store float** %0, float*** %b, align 8 - %1 = load float**, float*** %b, align 8 - call void @funfloat2(float** %1) - ret void -} - -declare void @funfloat2(float**) -declare i32* @getp() Index: llvm/trunk/test/Transforms/SafeStack/escape-gep-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-gep-call.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-gep-call.ll @@ -1,20 +0,0 @@ -; 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 - -%struct.pair = type { i32, i32 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Addr-of struct element, GEP followed by callinst. -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %c = alloca %struct.pair, align 4 - %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i64 0, i32 1 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %y) nounwind - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-gep-invoke.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-gep-invoke.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-gep-invoke.ll @@ -1,34 +0,0 @@ -; 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 - -%struct.pair = type { i32, i32 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Addr-of a struct element passed into an invoke instruction. -; (GEP followed by an invoke) -; safestack attribute -; Requires protector. -define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %c = alloca %struct.pair, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - %a = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0 - store i32 0, i32* %a, align 4 - %a1 = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 0 - invoke void @_Z3exceptPi(i32* %a1) - to label %invoke.cont unwind label %lpad - -invoke.cont: - ret i32 0 - -lpad: - %0 = landingpad { i8*, i32 } - catch i8* null - ret i32 0 -} - -declare void @_Z3exceptPi(i32*) -declare i32 @__gxx_personality_v0(...) Index: llvm/trunk/test/Transforms/SafeStack/escape-gep-negative.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-gep-negative.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-gep-negative.ll @@ -1,18 +0,0 @@ -; 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 - -; Addr-of a local, optimized into a GEP (e.g., &a - 12) -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %a = alloca i32, align 4 - %add.ptr5 = getelementptr inbounds i32, i32* %a, i64 -12 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32* %add.ptr5) nounwind - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-gep-ptrtoint.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-gep-ptrtoint.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-gep-ptrtoint.ll @@ -1,22 +0,0 @@ -; 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 - -%struct.pair = type { i32, i32 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Addr-of struct element, GEP followed by ptrtoint. -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %c = alloca %struct.pair, align 4 - %b = alloca i32*, align 8 - %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1 - %0 = ptrtoint i32* %y to i64 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i64 %0) - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-gep-store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-gep-store.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-gep-store.ll @@ -1,23 +0,0 @@ -; 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 - -%struct.pair = type { i32, i32 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Addr-of struct element. (GEP followed by store). -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %c = alloca %struct.pair, align 4 - %b = alloca i32*, align 8 - %y = getelementptr inbounds %struct.pair, %struct.pair* %c, i32 0, i32 1 - store i32* %y, i32** %b, align 8 - %0 = load i32*, i32** %b, align 8 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32* %0) - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-phi-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-phi-call.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-phi-call.ll @@ -1,36 +0,0 @@ -; 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 - -; Addr-of in phi instruction -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %x = alloca double, align 8 - %call = call double @testi_aux() nounwind - store double %call, double* %x, align 8 - %cmp = fcmp ogt double %call, 3.140000e+00 - br i1 %cmp, label %if.then, label %if.else - -if.then: ; preds = %entry - %call1 = call double @testi_aux() nounwind - store double %call1, double* %x, align 8 - br label %if.end4 - -if.else: ; preds = %entry - %cmp2 = fcmp ogt double %call, 1.000000e+00 - br i1 %cmp2, label %if.then3, label %if.end4 - -if.then3: ; preds = %if.else - br label %if.end4 - -if.end4: ; preds = %if.else, %if.then3, %if.then - %y.0 = phi double* [ null, %if.then ], [ %x, %if.then3 ], [ null, %if.else ] - %call5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double* %y.0) nounwind - ret void -} - -declare double @testi_aux() -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-select-call.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-select-call.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-select-call.ll @@ -1,22 +0,0 @@ -; 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 - -; Addr-of in select instruction -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %x = alloca double, align 8 - %call = call double @testi_aux() nounwind - store double %call, double* %x, align 8 - %cmp2 = fcmp ogt double %call, 0.000000e+00 - %y.1 = select i1 %cmp2, double* %x, double* null - %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), double* %y.1) - ret void -} - -declare double @testi_aux() -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/escape-vector.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/escape-vector.ll +++ llvm/trunk/test/Transforms/SafeStack/escape-vector.ll @@ -1,21 +0,0 @@ -; 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 - -%struct.vec = type { <4 x i32> } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Addr-of a vector nested in a struct -; safestack attribute -; Requires protector. -define void @foo() nounwind uwtable safestack { -entry: - ; CHECK: __safestack_unsafe_stack_ptr - %c = alloca %struct.vec, align 16 - %y = getelementptr inbounds %struct.vec, %struct.vec* %c, i64 0, i32 0 - %add.ptr = getelementptr inbounds <4 x i32>, <4 x i32>* %y, i64 -12 - %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), <4 x i32>* %add.ptr) nounwind - ret void -} - -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/invoke.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/invoke.ll +++ llvm/trunk/test/Transforms/SafeStack/invoke.ll @@ -1,33 +0,0 @@ -; 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 - -; Addr-of a variable passed into an invoke instruction. -; safestack attribute -; Requires protector and stack restore after landing pad. -define i32 @foo() uwtable safestack personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { -entry: - ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16 - %a = alloca i32, align 4 - %exn.slot = alloca i8* - %ehselector.slot = alloca i32 - store i32 0, i32* %a, align 4 - invoke void @_Z3exceptPi(i32* %a) - to label %invoke.cont unwind label %lpad - -invoke.cont: - ret i32 0 - -lpad: - ; CHECK: landingpad - ; CHECK-NEXT: catch - %0 = landingpad { i8*, i32 } - catch i8* null - ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr - ret i32 0 -} - -declare void @_Z3exceptPi(i32*) -declare i32 @__gxx_personality_v0(...) Index: llvm/trunk/test/Transforms/SafeStack/layout-frag.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/layout-frag.ll +++ llvm/trunk/test/Transforms/SafeStack/layout-frag.ll @@ -1,39 +0,0 @@ -; Test that safestack layout reuses a region w/o fragmentation. -; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s - -define void @f() safestack { -; CHECK-LABEL: define void @f -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - - %x0 = alloca i64, align 8 - %x1 = alloca i8, align 1 - %x2 = alloca i64, align 8 - - %x0a = bitcast i64* %x0 to i8* - %x2a = bitcast i64* %x2 to i8* - - call void @llvm.lifetime.start(i64 4, i8* %x0a) - call void @capture64(i64* %x0) - call void @llvm.lifetime.end(i64 4, i8* %x0a) - - call void @llvm.lifetime.start(i64 4, i8* %x1) - call void @llvm.lifetime.start(i64 4, i8* %x2a) - call void @capture8(i8* %x1) - call void @capture64(i64* %x2) - call void @llvm.lifetime.end(i64 4, i8* %x1) - call void @llvm.lifetime.end(i64 4, i8* %x2a) - -; Test that i64 allocas share space. -; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8 -; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -9 -; CHECK: getelementptr i8, i8* %unsafe_stack_ptr, i32 -8 - - ret void -} - -declare void @llvm.lifetime.start(i64, i8* nocapture) -declare void @llvm.lifetime.end(i64, i8* nocapture) -declare void @capture8(i8*) -declare void @capture64(i64*) Index: llvm/trunk/test/Transforms/SafeStack/layout-region-split.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/layout-region-split.ll +++ llvm/trunk/test/Transforms/SafeStack/layout-region-split.ll @@ -1,84 +0,0 @@ -; Regression test for safestack layout. Used to fail with asan. -; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s - -define void @f() safestack { -; CHECK-LABEL: define void @f -entry: -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK: getelementptr i8, i8* %[[USP]], i32 -224 - - %x0 = alloca i8, align 16 - %x1 = alloca i8, align 16 - %x2 = alloca i8, align 16 - %x3 = alloca i8, align 16 - %x4 = alloca i8, align 16 - %x5 = alloca i8, align 16 - %x6 = alloca i8, align 16 - %x7 = alloca i8, align 16 - %x8 = alloca i8, align 16 - %x9 = alloca i8, align 16 - %x10 = alloca i8, align 16 - %x11 = alloca i8, align 16 - %x12 = alloca i8, align 16 - %x13 = alloca i8, align 16 - %y0 = alloca i8, align 2 - %y1 = alloca i8, align 2 - %y2 = alloca i8, align 2 - %y3 = alloca i8, align 2 - %y4 = alloca i8, align 2 - %y5 = alloca i8, align 2 - %y6 = alloca i8, align 2 - %y7 = alloca i8, align 2 - %y8 = alloca i8, align 2 - -; CHECK: getelementptr i8, i8* %[[USP]], i32 -16 - call void @capture8(i8* %x0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -32 - call void @capture8(i8* %x1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -48 - call void @capture8(i8* %x2) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -64 - call void @capture8(i8* %x3) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -80 - call void @capture8(i8* %x4) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -96 - call void @capture8(i8* %x5) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -112 - call void @capture8(i8* %x6) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -128 - call void @capture8(i8* %x7) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -144 - call void @capture8(i8* %x8) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -160 - call void @capture8(i8* %x9) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -176 - call void @capture8(i8* %x10) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -192 - call void @capture8(i8* %x11) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -208 - call void @capture8(i8* %x12) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -224 - call void @capture8(i8* %x13) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -2 - call void @capture8(i8* %y0) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -4 - call void @capture8(i8* %y1) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -6 - call void @capture8(i8* %y2) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -8 - call void @capture8(i8* %y3) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -10 - call void @capture8(i8* %y4) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -12 - call void @capture8(i8* %y5) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -14 - call void @capture8(i8* %y6) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -18 - call void @capture8(i8* %y7) -; CHECK: getelementptr i8, i8* %[[USP]], i32 -20 - call void @capture8(i8* %y8) - - ret void -} - -declare void @capture8(i8*) Index: llvm/trunk/test/Transforms/SafeStack/no-attr.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/no-attr.ll +++ llvm/trunk/test/Transforms/SafeStack/no-attr.ll @@ -1,27 +0,0 @@ -; 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 - -; no safestack attribute -; Requires no protector. - -; CHECK-NOT: __safestack_unsafe_stack_ptr - -; CHECK: @foo -define void @foo(i8* %a) nounwind uwtable { -entry: - ; CHECK-NOT: __safestack_unsafe_stack_ptr - %a.addr = alloca i8*, align 8 - %buf = alloca [16 x i8], align 16 - store i8* %a, i8** %a.addr, align 8 - %arraydecay = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 - %0 = load i8*, i8** %a.addr, align 8 - %call = call i8* @strcpy(i8* %arraydecay, i8* %0) - %arraydecay1 = getelementptr inbounds [16 x i8], [16 x i8]* %buf, i32 0, i32 0 - %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i8* %arraydecay1) - ret void -} - -declare i8* @strcpy(i8*, i8*) -declare i32 @printf(i8*, ...) Index: llvm/trunk/test/Transforms/SafeStack/phi-cycle.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/phi-cycle.ll +++ llvm/trunk/test/Transforms/SafeStack/phi-cycle.ll @@ -1,50 +0,0 @@ -; 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 - -%struct.small = type { i8 } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; Address-of a structure taken in a function with a loop where -; the alloca is an incoming value to a PHI node and a use of that PHI -; node is also an incoming value. -; Verify that the address-of analysis does not get stuck in infinite -; recursion when chasing the alloca through the PHI nodes. -; Requires protector. -define i32 @foo(i32 %arg) nounwind uwtable safestack { -bb: - ; CHECK: __safestack_unsafe_stack_ptr - %tmp = alloca %struct.small*, align 8 - %tmp1 = call i32 (...) @dummy(%struct.small** %tmp) nounwind - %tmp2 = load %struct.small*, %struct.small** %tmp, align 8 - %tmp3 = ptrtoint %struct.small* %tmp2 to i64 - %tmp4 = trunc i64 %tmp3 to i32 - %tmp5 = icmp sgt i32 %tmp4, 0 - br i1 %tmp5, label %bb6, label %bb21 - -bb6: ; preds = %bb17, %bb - %tmp7 = phi %struct.small* [ %tmp19, %bb17 ], [ %tmp2, %bb ] - %tmp8 = phi i64 [ %tmp20, %bb17 ], [ 1, %bb ] - %tmp9 = phi i32 [ %tmp14, %bb17 ], [ %tmp1, %bb ] - %tmp10 = getelementptr inbounds %struct.small, %struct.small* %tmp7, i64 0, i32 0 - %tmp11 = load i8, i8* %tmp10, align 1 - %tmp12 = icmp eq i8 %tmp11, 1 - %tmp13 = add nsw i32 %tmp9, 8 - %tmp14 = select i1 %tmp12, i32 %tmp13, i32 %tmp9 - %tmp15 = trunc i64 %tmp8 to i32 - %tmp16 = icmp eq i32 %tmp15, %tmp4 - br i1 %tmp16, label %bb21, label %bb17 - -bb17: ; preds = %bb6 - %tmp18 = getelementptr inbounds %struct.small*, %struct.small** %tmp, i64 %tmp8 - %tmp19 = load %struct.small*, %struct.small** %tmp18, align 8 - %tmp20 = add i64 %tmp8, 1 - br label %bb6 - -bb21: ; preds = %bb6, %bb - %tmp22 = phi i32 [ %tmp1, %bb ], [ %tmp14, %bb6 ] - %tmp23 = call i32 (...) @dummy(i32 %tmp22) nounwind - ret i32 undef -} - -declare i32 @dummy(...) Index: llvm/trunk/test/Transforms/SafeStack/phi.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/phi.ll +++ llvm/trunk/test/Transforms/SafeStack/phi.ll @@ -1,35 +0,0 @@ -; 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 - -define void @f(i1 %d1, i1 %d2) safestack { -entry: -; CHECK-LABEL: define void @f( -; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr -; CHECK-NEXT: getelementptr i8, i8* %[[USP]], i32 -16 -; CHECK: br i1 %d1, label %[[BB0:.*]], label %[[BB1:.*]] - %a = alloca i32, align 8 - %b = alloca i32, align 8 - br i1 %d1, label %bb0, label %bb1 - -bb0: -; CHECK: [[BB0]]: -; CHECK: %[[Ai8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32 -; CHECK: %[[AUNSAFE:.*]] = bitcast i8* %[[Ai8]] to i32* -; CHECK: br i1 - br i1 %d2, label %bb2, label %bb2 - -bb1: -; CHECK: [[BB1]]: -; CHECK: %[[Bi8:.*]] = getelementptr i8, i8* %unsafe_stack_ptr, i32 -; CHECK: %[[BUNSAFE:.*]] = bitcast i8* %[[Bi8]] to i32* -; CHECK: br label - br label %bb2 - -bb2: -; CHECK: phi i32* [ %[[AUNSAFE]], %[[BB0]] ], [ %[[AUNSAFE]], %[[BB0]] ], [ %[[BUNSAFE]], %[[BB1]] ] - %c = phi i32* [ %a, %bb0 ], [ %a, %bb0 ], [ %b, %bb1 ] - call void @capture(i32* %c) - ret void -} - -declare void @capture(i32*) Index: llvm/trunk/test/Transforms/SafeStack/ret.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/ret.ll +++ llvm/trunk/test/Transforms/SafeStack/ret.ll @@ -1,17 +0,0 @@ -; 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 -} Index: llvm/trunk/test/Transforms/SafeStack/setjmp.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/setjmp.ll +++ llvm/trunk/test/Transforms/SafeStack/setjmp.ll @@ -1,37 +0,0 @@ -; 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 - -%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t } -%struct.__sigset_t = type { [16 x i64] } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 -@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16 - -; setjmp/longjmp test. -; Requires protector. -define i32 @foo() nounwind uwtable safestack { -entry: - ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - ; CHECK: %[[STATICTOP:.*]] = getelementptr i8, i8* %[[SP]], i32 -16 - %retval = alloca i32, align 4 - %x = alloca i32, align 4 - store i32 0, i32* %retval - store i32 42, i32* %x, align 4 - %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice - ; CHECK: setjmp - ; CHECK-NEXT: store i8* %[[STATICTOP]], i8** @__safestack_unsafe_stack_ptr - %tobool = icmp ne i32 %call, 0 - br i1 %tobool, label %if.else, label %if.then -if.then: ; preds = %entry - call void @funcall(i32* %x) - br label %if.end -if.else: ; preds = %entry - call i32 (...) @dummy() - br label %if.end -if.end: ; preds = %if.else, %if.then - ret i32 0 -} - -declare i32 @_setjmp(%struct.__jmp_buf_tag*) -declare void @funcall(i32*) -declare i32 @dummy(...) Index: llvm/trunk/test/Transforms/SafeStack/setjmp2.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/setjmp2.ll +++ llvm/trunk/test/Transforms/SafeStack/setjmp2.ll @@ -1,43 +0,0 @@ -; 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 - -%struct.__jmp_buf_tag = type { [8 x i64], i32, %struct.__sigset_t } -%struct.__sigset_t = type { [16 x i64] } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 -@buf = internal global [1 x %struct.__jmp_buf_tag] zeroinitializer, align 16 - -; setjmp/longjmp test with dynamically sized array. -; Requires protector. -; CHECK: @foo(i32 %[[ARG:.*]]) -define i32 @foo(i32 %size) nounwind uwtable safestack { -entry: - ; CHECK: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - ; CHECK-NEXT: %[[DYNPTR:.*]] = alloca i8* - ; CHECK-NEXT: store i8* %[[SP]], i8** %[[DYNPTR]] - - ; CHECK-NEXT: %[[ZEXT:.*]] = zext i32 %[[ARG]] to i64 - ; CHECK-NEXT: %[[MUL:.*]] = mul i64 %[[ZEXT]], 4 - ; CHECK-NEXT: %[[SP2:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - ; CHECK-NEXT: %[[PTRTOINT:.*]] = ptrtoint i8* %[[SP2]] to i64 - ; CHECK-NEXT: %[[SUB:.*]] = sub i64 %[[PTRTOINT]], %[[MUL]] - ; CHECK-NEXT: %[[AND:.*]] = and i64 %[[SUB]], -16 - ; 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:.*]] = bitcast i8* %[[INTTOPTR]] to i32* - %a = alloca i32, i32 %size - - ; CHECK: setjmp - ; CHECK-NEXT: %[[LOAD:.*]] = load i8*, i8** %[[DYNPTR]] - ; CHECK-NEXT: store i8* %[[LOAD]], i8** @__safestack_unsafe_stack_ptr - %call = call i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @buf, i32 0, i32 0)) returns_twice - - ; CHECK: call void @funcall(i32* %[[ALLOCA]]) - call void @funcall(i32* %a) - ; CHECK-NEXT: store i8* %[[SP:.*]], i8** @__safestack_unsafe_stack_ptr - ret i32 0 -} - -declare i32 @_setjmp(%struct.__jmp_buf_tag*) -declare void @funcall(i32*) Index: llvm/trunk/test/Transforms/SafeStack/sink-to-use.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/sink-to-use.ll +++ llvm/trunk/test/Transforms/SafeStack/sink-to-use.ll @@ -1,22 +0,0 @@ -; Test that unsafe alloca address calculation is done immediately before each use. -; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s -; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s - -define void @f() safestack { -entry: - %x0 = alloca i32, align 4 - %x1 = alloca i32, align 4 - -; CHECK: %[[A:.*]] = getelementptr i8, i8* %{{.*}}, i32 -4 -; CHECK: %[[X0:.*]] = bitcast i8* %[[A]] to i32* -; CHECK: call void @use(i32* %[[X0]]) - call void @use(i32* %x0) - -; CHECK: %[[B:.*]] = getelementptr i8, i8* %{{.*}}, i32 -8 -; CHECK: %[[X1:.*]] = bitcast i8* %[[B]] to i32* -; CHECK: call void @use(i32* %[[X1]]) - call void @use(i32* %x1) - ret void -} - -declare void @use(i32*) Index: llvm/trunk/test/Transforms/SafeStack/store.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/store.ll +++ llvm/trunk/test/Transforms/SafeStack/store.ll @@ -1,63 +0,0 @@ -; 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 -} Index: llvm/trunk/test/Transforms/SafeStack/struct.ll =================================================================== --- llvm/trunk/test/Transforms/SafeStack/struct.ll +++ llvm/trunk/test/Transforms/SafeStack/struct.ll @@ -1,40 +0,0 @@ -; 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 - -%struct.foo = type { [16 x i8] } - -@.str = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1 - -; struct { [16 x i8] } - -define void @foo(i8* %a) nounwind uwtable safestack { -entry: - ; CHECK: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr - - ; CHECK: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - - ; CHECK: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr - - %a.addr = alloca i8*, align 8 - %buf = alloca %struct.foo, align 1 - - ; CHECK: %[[AADDR:.*]] = alloca i8*, align 8 - ; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8 - store i8* %a, i8** %a.addr, align 8 - - ; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16 - ; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo* - ; CHECK: %[[GEP:.*]] = getelementptr inbounds %struct.foo, %struct.foo* %[[BUFPTR2]], i32 0, i32 0, i32 0 - %gep = getelementptr inbounds %struct.foo, %struct.foo* %buf, i32 0, i32 0, i32 0 - - ; CHECK: %[[A:.*]] = load i8*, i8** %[[AADDR]], align 8 - %a2 = load i8*, i8** %a.addr, align 8 - - ; CHECK: call i8* @strcpy(i8* %[[GEP]], i8* %[[A]]) - %call = call i8* @strcpy(i8* %gep, i8* %a2) - - ; CHECK: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr - ret void -} - -declare i8* @strcpy(i8*, i8*)