1 /* { dg-do compile } */
2 /* { dg-require-effective-target fstack_protector }*/
3 /* { dg-require-effective-target fpic }*/
4 /* { dg-additional-options "-Os -fpic -fstack-protector-strong" } */
5
6 #include <stddef.h>
7 #include <stdint.h>
8
9
10 static const unsigned char base64_enc_map[64] =
11 {
12 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
13 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
14 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
15 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
16 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
17 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
18 '8', '9', '+', '/'
19 };
20
21 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
22
23
24 void doSmth(void *x);
25
26 #include <string.h>
27
28
29 void check(int n) {
30
31 if (!(n % 2 && n % 3 && n % 5)) {
32 __asm__ ( "add r8, r8, #1;" );
33 }
34 }
35
36 uint32_t test(
37 uint32_t a1,
38 uint32_t a2,
39 size_t a3,
40 size_t a4,
41 size_t a5,
42 size_t a6)
43 {
44 uint32_t nResult = 0;
45 uint8_t* h = 0L;
46 uint8_t X[128];
47 uint8_t mac[64];
48 size_t len;
49
50 doSmth(&a1);
51 doSmth(&a2);
52 doSmth(&a3);
53 doSmth(&a4);
54 doSmth(&a5);
55 doSmth(&a6);
56
57 if (a1 && a2 && a3 && a4 && a5 && a6) {
58 nResult = 1;
59 h = (void*)X;
60 len = sizeof(X);
61 memset(X, a2, len);
62 len -= 64;
63 memcpy(mac ,X, len);
64 *(h + len) = a6;
65
66 {
67
68
69 unsigned char *dst = X;
70 size_t dlen = a3;
71 size_t *olen = &a6;
72 const unsigned char *src = mac;
73 size_t slen = a4;
74 size_t i, n;
75 int C1, C2, C3;
76 unsigned char *p;
77
78 if( slen == 0 )
79 {
80 *olen = 0;
81 return( 0 );
82 }
83
84 n = slen / 3 + ( slen % 3 != 0 );
85
86 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
87 {
88 *olen = BASE64_SIZE_T_MAX;
89 return( 0 );
90 }
91
92 n *= 4;
93
94 if( ( dlen < n + 1 ) || ( NULL == dst ) )
95 {
96 *olen = n + 1;
97 return( 0 );
98 }
99
100 n = ( slen / 3 ) * 3;
101
102 for( i = 0, p = dst; i < n; i += 3 )
103 {
104 C1 = *src++;
105 C2 = *src++;
106 C3 = *src++;
107
108 check(i);
109
110 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
111 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
112 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
113 *p++ = base64_enc_map[C3 & 0x3F];
114 }
115
116 if( i < slen )
117 {
118 C1 = *src++;
119 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
120
121 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
122 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
123
124 if( ( i + 1 ) < slen )
125 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
126 else *p++ = '=';
127
128 *p++ = '=';
129 }
130
131 *olen = p - dst;
132 *p = 0;
133
134 }
135
136 __asm__ ("mov r8, %0;" : "=r" ( nResult ));
137 }
138 else
139 {
140 nResult = 2;
141 }
142
143 doSmth(X);
144 doSmth(mac);
145
146
147 return nResult;
148 }
149
150 /* The pattern below catches sequences of instructions that were generated
151 for ARM and Thumb-2 before the fix for this PR. They are of the form:
152
153 ldr rX, <offset from sp or fp>
154 <optional non ldr instructions>
155 ldr rY, <offset from sp or fp>
156 ldr rZ, [rX]
157 <optional non ldr instructions>
158 cmp rY, rZ
159 <optional non cmp instructions>
160 bl __stack_chk_fail
161
162 Ideally the optional block would check for the various rX, rY and rZ
163 registers not being set but this is not possible due to back references
164 being illegal in lookahead expression in Tcl, thus preventing to use the
165 only construct that allow to negate a regexp from using the backreferences
166 to those registers. Instead we go for the heuristic of allowing non ldr/cmp
167 instructions with the assumptions that (i) those are not part of the stack
168 protector sequences and (ii) they would only be scheduled here if they don't
169 conflict with registers used by stack protector.
170
171 Note on the regexp logic:
172 Allowing non X instructions (where X is ldr or cmp) is done by looking for
173 some non newline spaces, followed by something which is not X, followed by
174 an alphanumeric character followed by anything but a newline and ended by a
175 newline the whole thing an undetermined number of times. The alphanumeric
176 character is there to force the match of the negative lookahead for X to
177 only happen after all the initial spaces and thus to check the mnemonic.
178 This prevents it to match one of the initial space. */
179 /* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\1\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\2, \3(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */
180
181 /* Likewise for Thumb-1 sequences of instructions prior to the fix for this PR
182 which had the form:
183
184 ldr rS, <offset from sp or fp>
185 <optional non ldr instructions>
186 ldr rT, <PC relative offset>
187 <optional non ldr instructions>
188 ldr rX, [rS, rT]
189 <optional non ldr instructions>
190 ldr rY, <offset from sp or fp>
191 ldr rZ, [rX]
192 <optional non ldr instructions>
193 cmp rY, rZ
194 <optional non cmp instructions>
195 bl __stack_chk_fail
196
197 Note on the regexp logic:
198 PC relative offset is checked by looking for a source operand that does not
199 contain [ or ]. */
200 /* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), [^][\n]*(?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[\1, \2\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\3\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\4, \5(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */