608 changes: 608 additions & 0 deletions llvm/lib/Transforms/Instrumentation/SafeStack.cpp

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions llvm/test/Transforms/SafeStack/addr-taken.ll
Original file line number Diff line number Diff line change
@@ -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
}

39 changes: 39 additions & 0 deletions llvm/test/Transforms/SafeStack/array-aligned.ll
Original file line number Diff line number Diff line change
@@ -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

; 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

; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8

; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [16 x i8]*
%buf = alloca [16 x i8], align 16

; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8

; 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*)
38 changes: 38 additions & 0 deletions llvm/test/Transforms/SafeStack/array.ll
Original file line number Diff line number Diff line change
@@ -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

; array [4 x i8]
; Requires protector.

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

; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8

; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -4
; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to [4 x i8]*
%buf = alloca [4 x i8], align 1

; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8

; 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
}

declare i8* @strcpy(i8*, i8*)
20 changes: 20 additions & 0 deletions llvm/test/Transforms/SafeStack/call.ll
Original file line number Diff line number Diff line change
@@ -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

; no arrays / no nested arrays
; Requires no protector.

; CHECK-LABEL: @foo(
define void @foo(i8* %a) nounwind uwtable safestack {
entry:
; CHECK-NOT: __safestack_unsafe_stack_ptr
%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*, ...)
17 changes: 17 additions & 0 deletions llvm/test/Transforms/SafeStack/cast.ll
Original file line number Diff line number Diff line change
@@ -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

; PtrToInt/IntToPtr Cast
; Requires no protector.

; CHECK-LABEL: @foo(
define void @foo() nounwind uwtable safestack {
entry:
; CHECK-NOT: __safestack_unsafe_stack_ptr
%a = alloca i32, align 4
%0 = ptrtoint i32* %a to i64
%1 = inttoptr i64 %0 to i32*
ret void
}
26 changes: 26 additions & 0 deletions llvm/test/Transforms/SafeStack/constant-gep-call.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
20 changes: 20 additions & 0 deletions llvm/test/Transforms/SafeStack/constant-gep.ll
Original file line number Diff line number Diff line change
@@ -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
}
28 changes: 28 additions & 0 deletions llvm/test/Transforms/SafeStack/constant-geps.ll
Original file line number Diff line number Diff line change
@@ -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
}
21 changes: 21 additions & 0 deletions llvm/test/Transforms/SafeStack/dynamic-alloca.ll
Original file line number Diff line number Diff line change
@@ -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

@.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: __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
ret void
}
23 changes: 23 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-addr-pointer.ll
Original file line number Diff line number Diff line change
@@ -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()
23 changes: 23 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-bitcast-store.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
20 changes: 20 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-bitcast-store2.ll
Original file line number Diff line number Diff line change
@@ -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*)
16 changes: 16 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-call.ll
Original file line number Diff line number Diff line change
@@ -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*)
24 changes: 24 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-casted-pointer.ll
Original file line number Diff line number Diff line change
@@ -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()
20 changes: 20 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-gep-call.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
34 changes: 34 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-gep-invoke.ll
Original file line number Diff line number Diff line change
@@ -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 {
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 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
catch i8* null
ret i32 0
}

declare void @_Z3exceptPi(i32*)
declare i32 @__gxx_personality_v0(...)
18 changes: 18 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-gep-negative.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
22 changes: 22 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-gep-ptrtoint.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
23 changes: 23 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-gep-store.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
36 changes: 36 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-phi-call.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
22 changes: 22 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-select-call.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
21 changes: 21 additions & 0 deletions llvm/test/Transforms/SafeStack/escape-vector.ll
Original file line number Diff line number Diff line change
@@ -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*, ...)
33 changes: 33 additions & 0 deletions llvm/test/Transforms/SafeStack/invoke.ll
Original file line number Diff line number Diff line change
@@ -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 {
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 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
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(...)
25 changes: 25 additions & 0 deletions llvm/test/Transforms/SafeStack/no-attr.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
; 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: @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*, ...)
50 changes: 50 additions & 0 deletions llvm/test/Transforms/SafeStack/phi-cycle.ll
Original file line number Diff line number Diff line change
@@ -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(...)
37 changes: 37 additions & 0 deletions llvm/test/Transforms/SafeStack/setjmp.ll
Original file line number Diff line number Diff line change
@@ -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(...)
42 changes: 42 additions & 0 deletions llvm/test/Transforms/SafeStack/setjmp2.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
; 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: %[[DYNPTR:.*]] = alloca i8*
; CHECK-NEXT: %[[SP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
; 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:.*]] = inttoptr i64 %[[SUB]] 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)
ret i32 0
}

declare i32 @_setjmp(%struct.__jmp_buf_tag*)
declare void @funcall(i32*)
41 changes: 41 additions & 0 deletions llvm/test/Transforms/SafeStack/struct.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
; 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

; CHECK: %[[AADDR:.*]] = alloca i8*, align 8
%a.addr = alloca i8*, align 8

; CHECK: %[[BUFPTR:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
; CHECK: %[[BUFPTR2:.*]] = bitcast i8* %[[BUFPTR]] to %struct.foo*
%buf = alloca %struct.foo, align 1

; CHECK: store i8* {{.*}}, i8** %[[AADDR]], align 8
store i8* %a, i8** %a.addr, align 8

; 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*)