expand: Fix up ICE on VCE from _Complex types to _BitInt [PR117458]
[official-gcc.git] / libgcc / strub.c
blob789e92920eafdee2eca0e87f1db51275135b8e73
1 /* Stack scrubbing infrastructure
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 Contributed by Alexandre Oliva <oliva@adacore.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "tconfig.h"
27 #include "tsystem.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "libgcc_tm.h"
31 #include "libgcc2.h"
33 #if ! STACK_GROWS_DOWNWARD
34 # define TOPS >
35 #else
36 # define TOPS <
37 #endif
39 /* Make sure these builtins won't be inlined, even with LTO. */
40 #define ATTRIBUTE_NOINLINE \
41 __attribute__ ((__noinline__, __noclone__, __noipa__))
43 #define ATTRIBUTE_STRUB_CALLABLE \
44 __attribute__ ((__strub__ ("callable"))) ATTRIBUTE_NOINLINE
46 /* Enter a stack scrubbing context, initializing the watermark to the caller's
47 stack address. */
48 void ATTRIBUTE_STRUB_CALLABLE
49 __strub_enter (void **watermark)
51 *watermark = __builtin_frame_address (0);
54 /* Update the watermark within a stack scrubbing context with the current stack
55 pointer. */
56 void ATTRIBUTE_STRUB_CALLABLE
57 __strub_update (void **watermark)
59 void *sp = __builtin_frame_address (0);
61 if (sp TOPS *watermark)
62 *watermark = sp;
65 #if TARGET_STRUB_USE_DYNAMIC_ARRAY && ! defined TARGET_STRUB_MAY_USE_MEMSET
66 # define TARGET_STRUB_MAY_USE_MEMSET 1
67 #endif
69 #if defined __x86_64__ && __OPTIMIZE__
70 # define TARGET_STRUB_DISABLE_RED_ZONE \
71 /* __attribute__ ((__target__ ("no-red-zone"))) // not needed when optimizing */
72 #elif !defined RED_ZONE_SIZE || defined __i386__
73 # define TARGET_STRUB_DISABLE_RED_ZONE
74 #endif
76 #ifndef TARGET_STRUB_DISABLE_RED_ZONE
77 /* Dummy function, called to force the caller to not be a leaf function, so
78 that it can't use the red zone. */
79 static void ATTRIBUTE_STRUB_CALLABLE
80 __strub_dummy_force_no_leaf (void)
83 #endif
85 /* Leave a stack scrubbing context, clearing the stack between its top and
86 *MARK. */
87 void ATTRIBUTE_STRUB_CALLABLE
88 #if ! TARGET_STRUB_MAY_USE_MEMSET
89 __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
90 #endif
91 #ifdef TARGET_STRUB_DISABLE_RED_ZONE
92 TARGET_STRUB_DISABLE_RED_ZONE
93 #endif
94 __strub_leave (void **mark)
96 void *sp = __builtin_stack_address ();
98 void **base, **end;
99 #if ! STACK_GROWS_DOWNWARD
100 base = sp; /* ??? Do we need an offset here? */
101 end = *mark;
102 #else
103 base = *mark;
104 end = sp; /* ??? Does any platform require an offset here? */
105 #endif
107 if (! (base < end))
108 return;
110 #if TARGET_STRUB_USE_DYNAMIC_ARRAY
111 /* Compute the length without assuming the pointers are both sufficiently
112 aligned. They should be, but pointer differences expected to be exact may
113 yield unexpected results when the assumption doesn't hold. Given the
114 potential security implications, compute the length without that
115 expectation. If the pointers are misaligned, we may leave a partial
116 unscrubbed word behind. */
117 ptrdiff_t len = ((char *)end - (char *)base) / sizeof (void *);
118 /* Allocate a dynamically-sized array covering the desired range, so that we
119 can safely call memset on it. */
120 void *ptr[len];
121 base = &ptr[0];
122 end = &ptr[len];
123 #elifndef TARGET_STRUB_DISABLE_RED_ZONE
124 /* Prevent the use of the red zone, by making this function non-leaf through
125 an unreachable call that, because of the asm stmt, the compiler will
126 consider reachable. */
127 asm goto ("" : : : : no_leaf);
128 if (0)
130 no_leaf:
131 __strub_dummy_force_no_leaf ();
132 return;
134 #endif
136 /* ldist may turn these loops into a memset (thus the conditional
137 -fno-tree-loop-distribute-patterns above). Without the dynamic array
138 above, that call would likely be unsafe: possibly tail-called, and likely
139 scribbling over its own stack frame. */
140 #if ! STACK_GROWS_DOWNWARD
142 *base++ = 0;
143 while (base < end);
144 /* Make sure the stack overwrites are not optimized away. */
145 asm ("" : : "m" (end[0]));
146 #else
148 *--end = 0;
149 while (base < end);
150 /* Make sure the stack overwrites are not optimized away. */
151 asm ("" : : "m" (base[0]));
152 #endif