Mercurial > hg > CbC > CbC_gcc
diff gcc/testsuite/c-c++-common/Wstringop-truncation.c @ 131:84e7813d76e9
gcc-8.2
author | mir3636 |
---|---|
date | Thu, 25 Oct 2018 07:37:49 +0900 |
parents | |
children | 1830386684a0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc/testsuite/c-c++-common/Wstringop-truncation.c Thu Oct 25 07:37:49 2018 +0900 @@ -0,0 +1,451 @@ +/* PR middle-end/81117 - Improve buffer overflow checking in strncpy + { dg-do compile } + { dg-options "-O2 -Wstringop-truncation -Wno-stringop-overflow -ftrack-macro-expansion=0" } + { dg-require-effective-target alloca } */ + + +typedef __SIZE_TYPE__ size_t; + +#if __cplusplus +extern "C" { +#endif + +size_t strlen (const char*); +char* strncat (char*, const char*, size_t); +char* strncpy (char*, const char*, size_t); + +#if __cplusplus +} +#endif + +static size_t unsigned_value (void) +{ + extern volatile size_t unsigned_value_source; + return unsigned_value_source; +} + +static size_t unsigned_range (size_t min, size_t max) +{ + size_t val = unsigned_value (); + return val < min || max < val ? min : val; +} + +#define UR(min, max) unsigned_range (min, max) + +void sink (void*); + +#define S4 "123" +const char a4[] = "123"; + +#define CHOOSE(a, b) (unsigned_value () & 1 ? a : b) + + +typedef struct Dest +{ + char a5[5]; + char b7[7]; + char c3ns[3] __attribute__ ((nonstring)); +} Dest; + +char dst7[7]; +char dst2_5[2][5]; + +/* Verify strncat warnings for arrays of known bounds. */ + +void test_strncat_array (Dest *pd) +{ +#define CAT(d, s, len) (strncat ((d), (s), (len)), sink (d)) + + CAT (dst7, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (dst7, a4, 1); /* { dg-warning "output truncated copying 1 byte from a string of length 3" } */ + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (dst7, S4, 3); + CAT (dst7, a4, 3); + */ + + CAT (pd->a5, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + CAT (pd->a5, S4, 1); /* { dg-warning "output truncated copying 1 byte from a string of length 3" } */ +} + +/* Verify strncat warnings for arrays of known bounds and a non-const + character count in some range. */ + +void test_strncat_array_range (Dest *pd) +{ + CAT (dst7, S4, UR (0, 1)); /* { dg-warning "output truncated copying between 0 and 1 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (0, 2)); /* { dg-warning "output truncated copying between 0 and 2 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (1, 3)); /* { dg-warning "output truncated copying between 1 and 3 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (2, 4)); /* { dg-warning "output may be truncated copying between 2 and 4 bytes from a string of length 3" } */ + + CAT (dst7, S4, UR (0, 7)); + CAT (dst7, S4, UR (1, 7)); + CAT (dst7, S4, UR (6, 7)); + + CAT (dst7, S4, UR (0, 99)); + + CAT (dst7, S4, UR (0, 99)); +} + +/* Verify strncat warnings for arrays of unknown bounds. */ + +void test_strncat_vla (char *d, unsigned n) +{ + CAT (d, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + CAT (d, S4, 4); + + CAT (d, a4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (d, S4, 3); + CAT (d, a4, 3); + */ + CAT (d, a4, 4); + + char vla[n]; + + CAT (vla, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (vla, S4, 4); + CAT (vla, S4, n); + + CAT (vla, a4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (vla, a4, 4); + CAT (vla, a4, n); + + CAT (d, vla, 1); + CAT (d, vla, 3); + CAT (d, vla, 4); + CAT (d, vla, n); + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (vla, S4, 3); + CAT (vla, a4, 3); + */ +} + +/* Verify strncpy warnings with at least one pointer to an object + or string of unknown size (destination) or length (source). */ + +void test_strncpy_ptr (char *d, const char* s, const char *t, int i) +{ +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + /* Strncpy doesn't nul-terminate so the following is diagnosed. */ + CPY (d, "", 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (d, s, 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + /* This is safe. */ + CPY (d, "", 1); + CPY (d, "", 2); + + /* This could be safe. */ + CPY (d, s, 1); + CPY (d, s, 2); + + /* Truncation. */ + CPY (d, "123", 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 3" } */ + CPY (d, "123", 2); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 2 bytes from a string of length 3" } */ + CPY (d, "123", 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (d, "123", 4); + CPY (d, "123", 9); + + CPY (d, S4, sizeof S4); /* Covered by -Wsizeof-pointer-memaccess. */ + CPY (d, S4, sizeof S4 - 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + + CPY (d, a4, sizeof a4); /* Covered by -Wsizeof-pointer-memaccess. */ + CPY (d, a4, sizeof a4 - 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (d, a4, sizeof a4 - 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 3" } */ + CPY (d, a4, sizeof a4 - 4); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes from a string of length 3" } */ + + CPY (d, S4, strlen (S4)); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + /* Likely buggy but no truncation. Diagnosed by -Wstringop-overflow. */ + CPY (d, a4, strlen (a4) + 1); + CPY (d, S4, strlen (S4) + i); + + CPY (d, a4, strlen (a4)); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + /* As above, buggy but no evidence of truncation. */ + CPY (d, S4, strlen (S4) + 1); + + CPY (d, CHOOSE ("", "1"), 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (d, CHOOSE ("1", "12"), 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + CPY (d, CHOOSE ("", "1"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE ("1", ""), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE (s, "1"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE (s, t), 1); + + CPY (d, CHOOSE ("", "1"), 2); + CPY (d, CHOOSE ("1", ""), 2); + CPY (d, CHOOSE ("1", "2"), 2); + CPY (d, CHOOSE ("1", s), 2); + CPY (d, CHOOSE (s, "1"), 2); + CPY (d, CHOOSE (s, t), 2); + + CPY (d, CHOOSE ("", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 3" } */ + CPY (d, CHOOSE ("1", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 1 byte from a string of the same length" } */ + CPY (d, CHOOSE ("12", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ + CPY (d, CHOOSE ("123", "12"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ + + { + signed char n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + short n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + int n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + unsigned n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + size_t n; + n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + size_t n; + char *dp2 = d + 1; + n = strlen (s); /* { dg-message "length computed here" } */ + CPY (dp2, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + /* The following is likely buggy but there's no apparent truncation + so it's not diagnosed by -Wstringop-truncation. Instead, it is + diagnosed by -Wstringop-overflow (tested elsewhere). */ + int n; + n = strlen (s) - 1; + CPY (d, s, n); + } + + { + /* Same as above. */ + size_t n; + n = strlen (s) - 1; + CPY (d, s, n); + } + + { + size_t n = strlen (s) - strlen (s); + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + } + + { + /* This use of strncpy is dubious but it's probably not worth + worrying about (truncation may not actually take place when + i is the result). It is diagnosed with -Wstringop-overflow + (although more by accident than by design). + + size_t n = i < strlen (s) ? i : strlen (s); + CPY (d, s, n); + */ + } +} + + +/* Verify strncpy warnings for arrays of known bounds. */ + +void test_strncpy_array (Dest *pd, int i, const char* s) +{ +#undef CPY +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + CPY (dst7, s, 7); /* { dg-warning "specified bound 7 equals destination size" } */ + CPY (dst7, s, sizeof dst7); /* { dg-warning "specified bound 7 equals destination size" } */ + + CPY (dst2_5[0], s, sizeof dst2_5[0]); /* { dg-warning "specified bound 5 equals destination size" "bug 77293" { xfail *-*-* } } */ + CPY (dst2_5[1], s, sizeof dst2_5[1]); /* { dg-warning "specified bound 5 equals destination size" } */ + + /* Verify that copies that nul-terminate are not diagnosed. */ + CPY (dst7, "", sizeof dst7); + CPY (dst7 + 6, "", sizeof dst7 - 6); + CPY (dst7, "1", sizeof dst7); + CPY (dst7 + 1, "1", sizeof dst7 - 1); + CPY (dst7, "123456", sizeof dst7); + CPY (dst7 + 1, "12345", sizeof dst7 - 1); + + CPY (dst7 + i, s, 6); + CPY (dst7 + i, s, 7); /* { dg-warning "specified bound 7 equals destination size" } */ + /* The following two calls are diagnosed by -Wstringop-overflow. */ + CPY (dst7 + i, s, 8); + CPY (dst7 + i, s, UR (8, 9)); + + /* No nul-termination here. */ + CPY (dst7 + 2, "12345", sizeof dst7 - 2); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + + /* Because strnlen appends as many NULs as necessary to write the specified + number of byts the following doesn't (necessarily) truncate but rather + overflow, and so is diagnosed by -Wstringop-overflow. */ + CPY (dst7, s, 8); + + CPY (dst7 + 1, s, 6); /* { dg-warning "specified bound 6 equals destination size" } */ + CPY (dst7 + 6, s, 1); /* { dg-warning "specified bound 1 equals destination size" } */ + + CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */ + CPY (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ + + /* The following is not yet handled. */ + CPY (pd->a5 + i, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" "member array" { xfail *-*-* } } */ + + /* Verify that a copy that nul-terminates is not diagnosed. */ + CPY (pd->a5, "1234", sizeof pd->a5); + + /* Same above, diagnosed by -Wstringop-overflow. */ + CPY (pd->a5, s, 6); + + /* Exercise destination with attribute "nonstring". */ + CPY (pd->c3ns, "", 3); + CPY (pd->c3ns, "", 1); + /* It could be argued that truncation in the literal case should be + diagnosed even for non-strings. Using strncpy in this case is + pointless and should be replaced with memcpy. But it would likely + be viewed as a false positive. */ + CPY (pd->c3ns, "12", 1); + CPY (pd->c3ns, "12", 2); + CPY (pd->c3ns, "12", 3); + CPY (pd->c3ns, "123", 3); + CPY (pd->c3ns, s, 3); + CPY (pd->c3ns, s, sizeof pd->c3ns); + + /* Verify that the idiom of calling strncpy with a bound equal to + the size of the destination (and thus potentially without NUL- + terminating it) immediately followed by setting the last element + of the array to NUL is not diagnosed. */ + { + /* This might be better written using memcpy() but it's safe so + it probably shouldn't be diagnosed. It currently triggers + a warning because of bug 81704. */ + strncpy (dst7, "0123456", sizeof dst7); /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */ + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + const char a[] = "0123456789"; + strncpy (dst7, a, sizeof dst7); + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + strncpy (dst7, s, sizeof dst7); + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + strncpy (pd->a5, "01234", sizeof pd->a5); /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */ + pd->a5[sizeof pd->a5 - 1] = '\0'; + sink (pd); + } + + { + strncpy (pd->a5, s, sizeof pd->a5); + pd->a5[sizeof pd->a5 - 1] = '\0'; + sink (pd); + } + + { + unsigned n = 7; + char *p = (char*)__builtin_malloc (n); + strncpy (p, s, n); + p[n - 1] = '\0'; + sink (p); + } + + { + /* This should be diagnosed because the NUL-termination doesn't + immediately follow the strncpy call (sink may expect pd->a5 + to be NUL-terminated). */ + strncpy (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ + sink (pd); + pd->a5[sizeof pd->a5] = '\0'; + sink (pd); + } +} + +typedef struct Flex +{ + size_t n; + char a0[0]; + char ax[]; +} Flex; + +extern char array[]; + +/* Verify that no warning is issued for array of unknown bound, flexible + array members, or zero-length arrays, except when the source is definitely + truncated. */ + +void test_strncpy_flexarray (Flex *pf, const char* s) +{ +#undef CPY +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + CPY (array, "12345", 7); + CPY (array, "12345", 123); + + CPY (array, s, 7); + CPY (array, s, 123); + + CPY (pf->a0, s, 1); + CPY (pf->a0, s, 1234); + + CPY (pf->a0, "", 1); + CPY (pf->a0, "12345", 5); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + CPY (pf->a0, "12345", 1234); + + CPY (pf->ax, s, 5); + CPY (pf->ax, s, 12345); + + CPY (pf->ax, "1234", 5); + CPY (pf->ax, "12345", 5); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + CPY (pf->ax, "12345", 12345); +} + +/* Verify warnings for dynamically allocated objects. */ + +void test_strncpy_alloc (const char* s) +{ + size_t n = 7; + char *d = (char *)__builtin_malloc (n); + + CPY (d, s, n); /* { dg-warning "specified bound 7 equals destination size" "bug 79016" { xfail *-*-* } } */ + + Dest *pd = (Dest *)__builtin_malloc (sizeof *pd * n); + CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */ + CPY (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ +} + +/* Verify warnings for VLAs. */ + +void test_strncpy_vla (unsigned n, const char* s) +{ + char vla[n]; + CPY (vla, s, 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + CPY (vla, s, 1); + CPY (vla, s, 2); + CPY (vla, s, n); + + CPY (vla, "", 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (vla, "", 1); + CPY (vla, S4, 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (vla, S4, n); +}