aboutsummaryrefslogtreecommitdiff
path: root/lang/gcc48/files/patch-stackprotector-gcc
blob: fb5780bdbeb377529cd80ca94ccadbc2405ea337 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
--- UTC
--- gcc/cfgexpand.c.orig
+++ gcc/cfgexpand.c
@@ -1291,6 +1291,12 @@
     clear_tree_used (t);
 }
 
+ enum {
+   SPCT_FLAG_DEFAULT = 1,
+   SPCT_FLAG_ALL = 2,
+   SPCT_FLAG_STRONG = 3
+ };
+
 /* Examine TYPE and determine a bit mask of the following features.  */
 
 #define SPCT_HAS_LARGE_CHAR_ARRAY	1
@@ -1360,7 +1366,8 @@
   if (bits & SPCT_HAS_SMALL_CHAR_ARRAY)
     has_short_buffer = true;
 
-  if (flag_stack_protect == 2)
+  if (flag_stack_protect == SPCT_FLAG_ALL
+      || flag_stack_protect == SPCT_FLAG_STRONG)
     {
       if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
 	  && !(bits & SPCT_HAS_AGGREGATE))
@@ -1514,6 +1521,27 @@
   return size;
 }
 
+/* Helper routine to check if a record or union contains an array field. */
+
+static int
+record_or_union_type_has_array_p (const_tree tree_type)
+{
+  tree fields = TYPE_FIELDS (tree_type);
+  tree f;
+
+  for (f = fields; f; f = DECL_CHAIN (f))
+    if (TREE_CODE (f) == FIELD_DECL)
+	  {
+	    tree field_type = TREE_TYPE (f);
+	    if (RECORD_OR_UNION_TYPE_P (field_type)
+	        && record_or_union_type_has_array_p (field_type))
+		  return 1;
+	    if (TREE_CODE (field_type) == ARRAY_TYPE)
+	      return 1;
+	  }
+  return 0;
+}
+
 /* Expand all variables used in the function.  */
 
 static rtx
@@ -1525,6 +1553,7 @@
   struct pointer_map_t *ssa_name_decls;
   unsigned i;
   unsigned len;
+  bool gen_stack_protect_signal = false;
 
   /* Compute the phase of the stack frame for this function.  */
   {
@@ -1575,6 +1604,24 @@
 	}
     }
   pointer_map_destroy (ssa_name_decls);
+   
+  if (flag_stack_protect == SPCT_FLAG_STRONG)
+    FOR_EACH_LOCAL_DECL (cfun, i, var)
+      if (!is_global_var (var))
+        {
+	      tree var_type = TREE_TYPE (var);
+	      /* Examine local referenced variables that have their addresses taken,
+	         contain an array, or are arrays.  */
+	      if (TREE_CODE (var) == VAR_DECL
+	          && (TREE_CODE (var_type) == ARRAY_TYPE
+	          || TREE_ADDRESSABLE (var)
+	          || (RECORD_OR_UNION_TYPE_P (var_type)
+	          && record_or_union_type_has_array_p (var_type))))
+	        {
+	          gen_stack_protect_signal = true;
+	          break;
+	        }
+        }
 
   /* At this point all variables on the local_decls with TREE_USED
      set are not associated with any block scope.  Lay them out.  */
@@ -1662,12 +1709,32 @@
 	dump_stack_var_partition ();
     }
 
-  /* There are several conditions under which we should create a
-     stack guard: protect-all, alloca used, protected decls present.  */
-  if (flag_stack_protect == 2
-      || (flag_stack_protect
-	  && (cfun->calls_alloca || has_protected_decls)))
-    create_stack_guard ();
+  /* Create stack guard, if
+     a) "-fstack-protector-all" - always;
+     b) "-fstack-protector-strong" - if there are arrays, memory
+     references to local variables, alloca used, or protected decls present;
+     c) "-fstack-protector" - if alloca used, or protected decls present  */
+	 
+  switch (flag_stack_protect)
+    {
+    case SPCT_FLAG_ALL:
+      create_stack_guard ();
+      break;
+
+    case SPCT_FLAG_STRONG:
+      if (gen_stack_protect_signal
+	      || cfun->calls_alloca || has_protected_decls)
+	    create_stack_guard ();
+      break;
+
+    case SPCT_FLAG_DEFAULT:
+      if (cfun->calls_alloca || has_protected_decls)
+	    create_stack_guard ();
+      break;
+
+    default:
+      ;
+    }
 
   /* Assign rtl to each variable based on these partitions.  */
   if (stack_vars_num > 0)
@@ -1688,7 +1755,7 @@
 	  expand_stack_vars (stack_protect_decl_phase_1, &data);
 
 	  /* Phase 2 contains other kinds of arrays.  */
-	  if (flag_stack_protect == 2)
+	  if (flag_stack_protect == SPCT_FLAG_ALL)
 	    expand_stack_vars (stack_protect_decl_phase_2, &data);
 	}
 
--- gcc/common.opt.orig
+++ gcc/common.opt
@@ -1942,6 +1942,10 @@ fstack-protector-all
 Common Report RejectNegative Var(flag_stack_protect, 2)
 Use a stack protection method for every function
 
+fstack-protector-strong
+Common Report RejectNegative Var(flag_stack_protect, 3)
+Use a smart stack protection method for certain functions
+
 fstack-usage
 Common RejectNegative Var(flag_stack_usage)
 Output stack usage information on a per-function basis
--- gcc/gcc.c.orig
+++ gcc/gcc.c
@@ -655,7 +655,7 @@ proper position among the other output files.  */
 #ifdef TARGET_LIBC_PROVIDES_SSP
 #define LINK_SSP_SPEC "%{fstack-protector:}"
 #else
-#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}"
+#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-strong|fstack-protector-all:-lssp_nonshared -lssp}"
 #endif
 #endif