1/* Copyright (C) 2004, 2005 Free Software Foundation. 2 3 Ensure builtin __strncpy_chk performs correctly. */ 4 5extern void abort (void); 6typedef __SIZE_TYPE__ size_t; 7extern size_t strlen(const char *); 8extern void *memcpy (void *, const void *, size_t); 9extern char *strncpy (char *, const char *, size_t); 10extern int memcmp (const void *, const void *, size_t); 11extern int strcmp (const char *, const char *); 12extern int strncmp (const char *, const char *, size_t); 13extern void *memset (void *, int, size_t); 14 15#include "chk.h" 16 17const char s1[] = "123"; 18char p[32] = ""; 19char *s2 = "defg"; 20char *s3 = "FGH"; 21char *s4; 22size_t l1 = 1; 23int i; 24 25void 26__attribute__((noinline)) 27test1 (void) 28{ 29 const char *const src = "hello world"; 30 const char *src2; 31 char dst[64], *dst2; 32 33 strncpy_disallowed = 1; 34 chk_calls = 0; 35 36 memset (dst, 0, sizeof (dst)); 37 if (strncpy (dst, src, 4) != dst || strncmp (dst, src, 4)) 38 abort(); 39 40 memset (dst, 0, sizeof (dst)); 41 if (strncpy (dst+16, src, 4) != dst+16 || strncmp (dst+16, src, 4)) 42 abort(); 43 44 memset (dst, 0, sizeof (dst)); 45 if (strncpy (dst+32, src+5, 4) != dst+32 || strncmp (dst+32, src+5, 4)) 46 abort(); 47 48 memset (dst, 0, sizeof (dst)); 49 dst2 = dst; 50 if (strncpy (++dst2, src+5, 4) != dst+1 || strncmp (dst2, src+5, 4) 51 || dst2 != dst+1) 52 abort(); 53 54 memset (dst, 0, sizeof (dst)); 55 if (strncpy (dst, src, 0) != dst || strcmp (dst, "")) 56 abort(); 57 58 memset (dst, 0, sizeof (dst)); 59 dst2 = dst; src2 = src; 60 if (strncpy (++dst2, ++src2, 0) != dst+1 || strcmp (dst2, "") 61 || dst2 != dst+1 || src2 != src+1) 62 abort(); 63 64 memset (dst, 0, sizeof (dst)); 65 dst2 = dst; src2 = src; 66 if (strncpy (++dst2+5, ++src2+5, 0) != dst+6 || strcmp (dst2+5, "") 67 || dst2 != dst+1 || src2 != src+1) 68 abort(); 69 70 memset (dst, 0, sizeof (dst)); 71 if (strncpy (dst, src, 12) != dst || strcmp (dst, src)) 72 abort(); 73 74 /* Test at least one instance of the __builtin_ style. We do this 75 to ensure that it works and that the prototype is correct. */ 76 memset (dst, 0, sizeof (dst)); 77 if (__builtin_strncpy (dst, src, 4) != dst || strncmp (dst, src, 4)) 78 abort(); 79 80 memset (dst, 0, sizeof (dst)); 81 if (strncpy (dst, i++ ? "xfoo" + 1 : "bar", 4) != dst 82 || strcmp (dst, "bar") 83 || i != 1) 84 abort (); 85 86 if (chk_calls) 87 abort (); 88 strncpy_disallowed = 0; 89} 90 91void 92__attribute__((noinline)) 93test2 (void) 94{ 95 chk_calls = 0; 96 /* No runtime checking should be done here, both destination 97 and length are unknown. */ 98 strncpy (s4, "abcd", l1 + 1); 99 if (chk_calls) 100 abort (); 101} 102 103/* Test whether compile time checking is done where it should 104 and so is runtime object size checking. */ 105void 106__attribute__((noinline)) 107test3 (void) 108{ 109 struct A { char buf1[10]; char buf2[10]; } a; 110 char *r = l1 == 1 ? &a.buf1[5] : &a.buf2[4]; 111 char buf3[20]; 112 int i; 113 const char *l; 114 size_t l2; 115 116 /* The following calls should do runtime checking 117 - source length is not known, but destination is. */ 118 chk_calls = 0; 119 strncpy (a.buf1 + 2, s3 + 3, l1); 120 strncpy (r, s3 + 2, l1 + 2); 121 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; 122 strncpy (r, s2 + 2, l1 + 2); 123 strncpy (r + 2, s3 + 3, l1); 124 r = buf3; 125 for (i = 0; i < 4; ++i) 126 { 127 if (i == l1 - 1) 128 r = &a.buf1[1]; 129 else if (i == l1) 130 r = &a.buf2[7]; 131 else if (i == l1 + 1) 132 r = &buf3[5]; 133 else if (i == l1 + 2) 134 r = &a.buf1[9]; 135 } 136 strncpy (r, s2 + 4, l1); 137 if (chk_calls != 5) 138 abort (); 139 140 /* Following have known destination and known length, 141 so if optimizing certainly shouldn't result in the checking 142 variants. */ 143 chk_calls = 0; 144 strncpy (a.buf1 + 2, "", 3); 145 strncpy (a.buf1 + 2, "", 0); 146 strncpy (r, "a", 1); 147 strncpy (r, "a", 3); 148 r = l1 == 1 ? __builtin_alloca (4) : &a.buf2[7]; 149 strncpy (r, s1 + 1, 3); 150 strncpy (r, s1 + 1, 2); 151 r = buf3; 152 l = "abc"; 153 l2 = 4; 154 for (i = 0; i < 4; ++i) 155 { 156 if (i == l1 - 1) 157 r = &a.buf1[1], l = "e", l2 = 2; 158 else if (i == l1) 159 r = &a.buf2[7], l = "gh", l2 = 3; 160 else if (i == l1 + 1) 161 r = &buf3[5], l = "jkl", l2 = 4; 162 else if (i == l1 + 2) 163 r = &a.buf1[9], l = "", l2 = 1; 164 } 165 strncpy (r, "", 1); 166 /* Here, strlen (l) + 1 is known to be at most 4 and 167 __builtin_object_size (&buf3[16], 0) is 4, so this doesn't need 168 runtime checking. */ 169 strncpy (&buf3[16], l, l2); 170 strncpy (&buf3[15], "abc", l2); 171 strncpy (&buf3[10], "fghij", l2); 172 if (chk_calls) 173 abort (); 174 chk_calls = 0; 175} 176 177/* Test whether runtime and/or compile time checking catches 178 buffer overflows. */ 179void 180__attribute__((noinline)) 181test4 (void) 182{ 183 struct A { char buf1[10]; char buf2[10]; } a; 184 char buf3[20]; 185 186 chk_fail_allowed = 1; 187 /* Runtime checks. */ 188 if (__builtin_setjmp (chk_fail_buf) == 0) 189 { 190 strncpy (&a.buf2[9], s2 + 4, l1 + 1); 191 abort (); 192 } 193 if (__builtin_setjmp (chk_fail_buf) == 0) 194 { 195 strncpy (&a.buf2[7], s3, l1 + 4); 196 abort (); 197 } 198 /* This should be detectable at compile time already. */ 199 if (__builtin_setjmp (chk_fail_buf) == 0) 200 { 201 strncpy (&buf3[19], "abc", 2); 202 abort (); 203 } 204 if (__builtin_setjmp (chk_fail_buf) == 0) 205 { 206 strncpy (&buf3[18], "", 3); 207 abort (); 208 } 209 chk_fail_allowed = 0; 210} 211 212void 213main_test (void) 214{ 215#ifndef __OPTIMIZE__ 216 /* Object size checking is only intended for -O[s123]. */ 217 return; 218#endif 219 __asm ("" : "=r" (s2) : "0" (s2)); 220 __asm ("" : "=r" (s3) : "0" (s3)); 221 __asm ("" : "=r" (l1) : "0" (l1)); 222 test1 (); 223 s4 = p; 224 test2 (); 225 test3 (); 226 test4 (); 227} 228