1 /* PR middle-end/81117 - Improve buffer overflow checking in strncpy 2 { dg-do compile } 3 { dg-options "-O2 -Wstringop-overflow -Wno-stringop-truncation -ftrack-macro-expansion=0" } */ 4 5 typedef __SIZE_TYPE__ size_t; 6 7 #if __cplusplus 8 extern "C" { 9 #endif 10 11 size_t strlen (const char*); 12 char* strncat (char*, const char*, size_t); 13 char* strncpy (char*, const char*, size_t); 14 #if __cplusplus 15 } 16 #endif 17 18 const char ar[] = "123"; 19 20 void test_strncat (char **d, const char* s, int i) 21 { 22 /* Use a fresh pointer for each test to prevent the optimizer from 23 eliminating redundant writes into the same destination. Avoid 24 calling functions like sink() on the result that would have to 25 be assumed to change the source string by the alias oracle. */ 26 #define T(d, s, len) strncat (*d++, (s), (len)) 27 28 T (d, "", 0); 29 T (d, "", 1); 30 T (d, "", 2); 31 T (d, "", 3); 32 T (d, "123", 0); 33 /* The following two calls truncate the copy and are diagnosed test_string_literal(char * dst)34 by -Wstringop-truncation but there is evidence of overflow so 35 they're not diagnosed by -Wstringop-overflow. */ 36 T (d, "123", 1); 37 T (d, "123", 2); 38 39 T (d, "123", 3); /* { dg-warning ".strncat\[^\n\r\]* specified bound 3 equals source length" } */ 40 T (d, "123", 4); 41 T (d, "123", 9); 42 43 T (d, s, strlen (s)); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 44 T (d, s, strlen (s) + 1); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 45 /* The following could also be diagnosed by -Wstringop-truncation 46 (with some effort to distinguish the pattern from others like 47 the one above. */ 48 T (d, s, strlen (s) - 1); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 49 T (d, s, strlen (s) - i); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 50 51 /* The following is dubious but not necessarily a smoking gun. */ 52 T (d, s, strlen (s) - strlen (s)); 53 54 { 55 signed char n = strlen (s); /* { dg-message "length computed here" } */ 56 T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 57 } 58 59 { 60 short n = strlen (s); /* { dg-message "length computed here" } */ 61 T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 62 } 63 64 { 65 int n = strlen (s); /* { dg-message "length computed here" } */ test_char_array(char * dst)66 T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 67 } 68 69 { 70 unsigned n = strlen (s); /* { dg-message "length computed here" } */ 71 T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 72 } 73 74 { 75 size_t n; 76 n = strlen (s); /* { dg-message "length computed here" } */ 77 T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 78 } 79 80 { 81 size_t n; 82 n = strlen (s) - 1; /* { dg-message "length computed here" } */ 83 T (d, s, n); /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 84 } 85 86 { 87 /* This doesn't overflow so iit should not be diagnosed. */ 88 size_t n = strlen (s) - strlen (s); 89 T (d, s, n); 90 } test_char_array_chk(char * dst)91 92 { 93 size_t n = i < strlen (s) ? i : strlen (s); /* { dg-message "length computed here" } */ 94 T (d, s, n); /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ 95 } 96 } 97 98 99 void test_strncpy (char **d, const char* s, int i) 100 { 101 #undef T 102 #define T(d, s, len) strncpy (*d++, (s), (len)) 103 104 T (d, "", 0); 105 T (d, "", 1); 106 T (d, "", 2); 107 T (d, "", 3); 108 T (d, "123", 0); 109 T (d, "123", 1); 110 T (d, "123", 2); 111 T (d, "123", 3); 112 T (d, "123", 4); test_string_literal_chk(char * dst)113 T (d, "123", 9); 114 115 T (d, "123", sizeof "123"); 116 T (d, ar, sizeof ar); 117 118 /* There is no overflow in the following calls but they are diagnosed 119 by -Wstringop-truncation. Verify that they aren'y also diagnosed 120 by -Wstringop-overflow. */ 121 T (d, s, strlen (s)); 122 123 { 124 int n = strlen (s); 125 T (d, s, n); 126 } 127 128 { 129 unsigned n = strlen (s); 130 T (d, s, n); 131 } 132 133 { 134 size_t n; 135 n = strlen (s); 136 T (d, s, n); 137 } 138 139 { 140 size_t n; 141 n = strlen (s) - 1; 142 T (d, s, n); 143 } 144 145 { 146 /* This is diagnosed by -Wstringop-truncation. Verify that it isn't 147 also diagnosed by -Wstringop-overflow. */ 148 size_t n = strlen (s) - strlen (s); 149 T (d, s, n); 150 } 151 152 { 153 /* This use of strncpy is certainly dubious and it could well be 154 diagnosed by -Wstringop-truncation but it isn't. */ 155 size_t n = i < strlen (s) ? i : strlen (s); /* { dg-message "length computed here" "note" { xfail *-*-* } } */ 156 T (d, s, n); /* { dg-message ".strncpy\[^\n\r]* specified bound depends on the length of the source argument" "pr?????" { xfail *-*-* } } */ 157 } 158 } 159