From b6e16ea006a262c77ed44afc72b94a9b7c9cf440 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Mon, 18 Mar 2019 19:23:45 +0000 Subject: [Sema] Add some compile time _FORTIFY_SOURCE diagnostics These diagnose overflowing calls to subset of fortifiable functions. Some functions, like sprintf or strcpy aren't supported right not, but we should probably support these in the future. We previously supported this kind of functionality with -Wbuiltin-memcpy-chk-size, but that diagnostic doesn't work with _FORTIFY implementations that use wrapper functions. Also unlike that diagnostic, we emit these warnings regardless of whether _FORTIFY_SOURCE is actually enabled, which is nice for programs that don't enable the runtime checks. Why not just use diagnose_if, like Bionic does? We can get better diagnostics in the compiler (i.e. mention the sizes), and we have the potential to diagnose sprintf and strcpy which is impossible with diagnose_if (at least, in languages that don't support C++14 constexpr). This approach also saves standard libraries from having to add diagnose_if. rdar://48006655 Differential revision: https://reviews.llvm.org/D58797 llvm-svn: 356397 --- clang/test/Sema/warn-fortify-source.c | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 clang/test/Sema/warn-fortify-source.c (limited to 'clang/test/Sema/warn-fortify-source.c') diff --git a/clang/test/Sema/warn-fortify-source.c b/clang/test/Sema/warn-fortify-source.c new file mode 100644 index 00000000000..208ff6909f1 --- /dev/null +++ b/clang/test/Sema/warn-fortify-source.c @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_PASS_OBJECT_SIZE +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS + +typedef unsigned long size_t; + +#if defined(USE_PASS_OBJECT_SIZE) +void *memcpy(void *dst, const void *src, size_t c); +static void *memcpy(void *dst __attribute__((pass_object_size(1))), const void *src, size_t c) __attribute__((overloadable)) __asm__("merp"); +static void *memcpy(void *const dst __attribute__((pass_object_size(1))), const void *src, size_t c) __attribute__((overloadable)) { + return 0; +} +#elif defined(USE_BUILTINS) +#define memcpy(x,y,z) __builtin_memcpy(x,y,z) +#else +void *memcpy(void *dst, const void *src, size_t c); +#endif + +void call_memcpy() { + char dst[10]; + char src[20]; + memcpy(dst, src, 20); // expected-warning {{memcpy' will always overflow; destination buffer has size 10, but size argument is 20}} +} + +void call_memcpy_type() { + struct pair { + int first; + int second; + }; + struct pair p; + char buf[20]; + memcpy(&p.first, buf, 20); +#ifdef USE_PASS_OBJECT_SIZE + // Use the more strict checking mode on the pass_object_size attribute: + // expected-warning@-3 {{memcpy' will always overflow; destination buffer has size 4, but size argument is 20}} +#else + // Or just fallback to type 0: + // expected-warning@-6 {{memcpy' will always overflow; destination buffer has size 8, but size argument is 20}} +#endif +} + +void call_strncat() { + char s1[10], s2[20]; + __builtin_strncat(s2, s1, 20); + __builtin_strncat(s1, s2, 20); // expected-warning {{'strncat' size argument is too large; destination buffer has size 10, but size argument is 20}} +} + +void call_strncpy() { + char s1[10], s2[20]; + __builtin_strncpy(s2, s1, 20); + __builtin_strncpy(s1, s2, 20); // expected-warning {{'strncpy' size argument is too large; destination buffer has size 10, but size argument is 20}} +} + +void call_stpncpy() { + char s1[10], s2[20]; + __builtin_stpncpy(s2, s1, 20); + __builtin_stpncpy(s1, s2, 20); // expected-warning {{'stpncpy' size argument is too large; destination buffer has size 10, but size argument is 20}} +} + +void call_memmove() { + char s1[10], s2[20]; + __builtin_memmove(s2, s1, 20); + __builtin_memmove(s1, s2, 20); // expected-warning {{'memmove' will always overflow; destination buffer has size 10, but size argument is 20}} +} + +void call_memset() { + char buf[10]; + __builtin_memset(buf, 0xff, 10); + __builtin_memset(buf, 0xff, 11); // expected-warning {{'memset' will always overflow; destination buffer has size 10, but size argument is 11}} +} + +void call_snprintf() { + char buf[10]; + __builtin_snprintf(buf, 10, "merp"); + __builtin_snprintf(buf, 11, "merp"); // expected-warning {{'snprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} +} + +void call_vsnprintf() { + char buf[10]; + __builtin_va_list list; + __builtin_vsnprintf(buf, 10, "merp", list); + __builtin_vsnprintf(buf, 11, "merp", list); // expected-warning {{'vsnprintf' size argument is too large; destination buffer has size 10, but size argument is 11}} +} -- cgit v1.2.3