CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
482 lines
20 KiB
C++
482 lines
20 KiB
C++
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -Wno-gcc-compat\
|
|
// RUN: -verify %s
|
|
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -Wno-gcc-compat\
|
|
// RUN: -verify %s -x objective-c++
|
|
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
|
|
// RUN: -Wunsafe-buffer-usage-in-format-attr-call -Wno-gcc-compat \
|
|
// RUN: -verify %s
|
|
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
|
|
// RUN: -Wunsafe-buffer-usage-in-format-attr-call -Wno-gcc-compat \
|
|
// RUN: -verify %s -DTEST_STD_NS
|
|
|
|
typedef struct {} FILE;
|
|
typedef unsigned int size_t;
|
|
|
|
#ifdef TEST_STD_NS
|
|
namespace std {
|
|
#endif
|
|
|
|
void memcpy();
|
|
void __asan_memcpy();
|
|
void *memset(void *s, int c, size_t n);
|
|
void strcpy();
|
|
void strcpy_s();
|
|
void wcscpy_s();
|
|
unsigned strlen( const char* str );
|
|
int fprintf( FILE* stream, const char* format, ... );
|
|
int printf( const char* format, ... );
|
|
int sprintf( char* buffer, const char* format, ... );
|
|
int swprintf( char* buffer, const char* format, ... );
|
|
int snprintf( char* buffer, unsigned buf_size, const char* format, ... );
|
|
int snwprintf( char* buffer, unsigned buf_size, const char* format, ... );
|
|
int snwprintf_s( char* buffer, unsigned buf_size, const char* format, ... );
|
|
int vsnprintf( char* buffer, unsigned buf_size, const char* format, ... );
|
|
int sscanf_s(const char * buffer, const char * format, ...);
|
|
int sscanf(const char * buffer, const char * format, ... );
|
|
int wprintf(const wchar_t* format, ... );
|
|
int __asan_printf();
|
|
|
|
#ifdef TEST_STD_NS
|
|
} //namespace std
|
|
using namespace std;
|
|
#endif
|
|
|
|
namespace std {
|
|
template< class InputIt, class OutputIt >
|
|
OutputIt copy( InputIt first, InputIt last,
|
|
OutputIt d_first );
|
|
|
|
struct iterator{};
|
|
template<typename T>
|
|
struct span {
|
|
T * ptr;
|
|
T * data();
|
|
unsigned size_bytes();
|
|
unsigned size();
|
|
iterator begin() const noexcept;
|
|
iterator end() const noexcept;
|
|
};
|
|
|
|
template<typename T>
|
|
struct basic_string {
|
|
T* p;
|
|
T *c_str();
|
|
T *data();
|
|
unsigned size_bytes();
|
|
unsigned size();
|
|
};
|
|
|
|
typedef basic_string<char> string;
|
|
typedef basic_string<wchar_t> wstring;
|
|
|
|
template<typename T>
|
|
struct basic_string_view {
|
|
T *c_str() const noexcept;
|
|
T *data() const noexcept;
|
|
unsigned size();
|
|
const T* begin() const noexcept;
|
|
const T* end() const noexcept;
|
|
};
|
|
|
|
typedef basic_string_view<char> string_view;
|
|
typedef basic_string_view<wchar_t> wstring_view;
|
|
|
|
|
|
template <typename T>
|
|
T *addressof(T& arg);
|
|
}
|
|
|
|
void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
|
|
typedef FILE * _Nullable aligned_file_ptr_t __attribute__((align_value(64)));
|
|
typedef char * _Nullable aligned_char_ptr_t __attribute__((align_value(64)));
|
|
aligned_file_ptr_t fp;
|
|
aligned_char_ptr_t cp;
|
|
|
|
memcpy(); // expected-warning{{function 'memcpy' is unsafe}}
|
|
__builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' is unsafe}}
|
|
__builtin___memcpy_chk(p, q, 8, 64); // expected-warning{{function '__builtin___memcpy_chk' is unsafe}}
|
|
__asan_memcpy(); // expected-warning{{function '__asan_memcpy' is unsafe}}
|
|
strcpy(); // expected-warning{{function 'strcpy' is unsafe}}
|
|
strcpy_s(); // expected-warning{{function 'strcpy_s' is unsafe}}
|
|
wcscpy_s(); // expected-warning{{function 'wcscpy_s' is unsafe}}
|
|
#ifdef TEST_STD_NS
|
|
std::strcpy(); // expected-warning{{function 'strcpy' is unsafe}}
|
|
std::memcpy(); // expected-warning{{function 'memcpy' is unsafe}}
|
|
#endif
|
|
|
|
/* Test printfs */
|
|
fprintf((FILE*)p, "%s%d", p, *p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
printf("%s%d", // expected-warning{{function 'printf' is unsafe}}
|
|
p, // expected-note{{string argument is not guaranteed to be null-terminated}} note attached to the unsafe argument
|
|
*p);
|
|
printf(cp, p, *p); // expected-warning{{function 'printf' is unsafe}} // expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
sprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'sprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
|
|
swprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'swprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
|
|
snprintf(q, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
snprintf(cp, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
snprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
printf(nullptr); // expected-warning{{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
printf("%s", nullptr); // expected-warning{{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
snwprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snwprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
snwprintf_s( // expected-warning{{function 'snwprintf_s' is unsafe}}
|
|
s.data(), // expected-note{{buffer pointer and size may not match}} // note attached to the buffer
|
|
s2.size(),
|
|
"%s%d", "hello", *p);
|
|
vsnprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // expected-warning{{function 'vsnprintf' is unsafe}} expected-note{{'va_list' is unsafe}}
|
|
sscanf(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf' is unsafe}}
|
|
sscanf_s(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf_s' is unsafe}}
|
|
fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
wprintf(L"hello %s", p); // expected-warning{{function 'wprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
|
|
char a[10], b[11];
|
|
int c[10];
|
|
std::wstring WS;
|
|
|
|
snprintf(a, sizeof(b), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
snprintf((char*)c, sizeof(c), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
|
|
fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn
|
|
fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn
|
|
printf("%s%d", "hello", *p); // no warn
|
|
snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn
|
|
snprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
|
|
snwprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
|
|
snwprintf_s(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
|
|
snprintf(s.data(), s.size_bytes(), "%s%d"); // no warn
|
|
snprintf(s.data(), s.size_bytes(), "%s%d"); // no warn
|
|
snwprintf(s.data(), s.size_bytes(), "%s%d"); // no warn
|
|
snwprintf_s(s.data(), s.size_bytes(), "%s%d"); // no warn
|
|
wprintf(L"hello %ls", L"world"); // no warn
|
|
wprintf(L"hello %ls", WS.c_str()); // no warn
|
|
strlen("hello");// no warn
|
|
__asan_printf();// a printf but no argument, so no warn
|
|
}
|
|
|
|
void safe_examples(std::string s1, int *p) {
|
|
snprintf(s1.data(), s1.size_bytes(), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn
|
|
snprintf(s1.data(), s1.size_bytes(), s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
printf("%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn
|
|
printf(s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
fprintf((FILE*)0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn
|
|
fprintf((FILE*)0, s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
|
|
char a[10];
|
|
char c = 'c';
|
|
|
|
snprintf(a, sizeof a, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
snprintf(a, sizeof(decltype(a)), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
snprintf(a, 10, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
snprintf(&c, 1, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
snprintf(nullptr, 0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn
|
|
|
|
strlen(s1.c_str());
|
|
}
|
|
|
|
void test_sarg_precision(std::string Str, std::string_view Sv, std::wstring_view WSv,
|
|
std::span<char> SpC, std::span<int> SpI) {
|
|
printf("%.*s");
|
|
printf("%.*s", (int)Str.size(), Str.data());
|
|
printf("%.*s", (int)Str.size_bytes(), Str.data());
|
|
printf("%.*s", (int)Sv.size(), Sv.data());
|
|
printf("%.*s", (int)SpC.size(), SpC.data());
|
|
printf("%.*s", SpC.size(), SpC.data());
|
|
printf("%.*ls", WSv.size(), WSv.data());
|
|
printf("%.*s", SpC.data()); // no warn because `SpC.data()` is passed to the precision while the actually string pointer is not given
|
|
|
|
printf("%.*s", SpI.size(), SpI.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
printf("%.*s", SpI.size(), SpC.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
printf("%.*s", WSv.size(), WSv.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
char a[10];
|
|
int b[10];
|
|
|
|
printf("%.10s", a);
|
|
printf("%.11s", a); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
printf("%.10s", b); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
}
|
|
|
|
|
|
void g(char *begin, char *end, char *p, std::span<char> s) {
|
|
std::copy(begin, end, p); // no warn
|
|
std::copy(s.begin(), s.end(), s.begin()); // no warn
|
|
}
|
|
|
|
// warning gets turned off
|
|
void ff(char * p, char * q, std::span<char> s, std::span<char> s2) {
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
memcpy();
|
|
__builtin_memcpy(p, q, 64);
|
|
__builtin___memcpy_chk(p, q, 8, 64);
|
|
__asan_memcpy();
|
|
strcpy();
|
|
#ifdef TEST_STD_NS
|
|
std::strcpy();
|
|
std::memcpy();
|
|
#endif
|
|
strcpy_s();
|
|
wcscpy_s();
|
|
#pragma clang diagnostic pop
|
|
}
|
|
|
|
|
|
|
|
// functions not in global scope or std:: namespace are not libc
|
|
// functions regardless of their names:
|
|
struct StrBuff
|
|
{
|
|
void strcpy();
|
|
void strcpy(char* dst);
|
|
void memcpy(void *dst, const void *src, size_t size);
|
|
};
|
|
|
|
namespace NS {
|
|
void strcpy();
|
|
void strcpy(char* dst);
|
|
void memcpy(void *dst, const void *src, size_t size);
|
|
}
|
|
|
|
namespace std {
|
|
// class methods even in std namespace cannot be libc functions:
|
|
struct LibC
|
|
{
|
|
void strcpy();
|
|
void strcpy(char* dst);
|
|
void memcpy(void *dst, const void *src, size_t size);
|
|
};
|
|
}
|
|
|
|
void test(StrBuff& str)
|
|
{
|
|
char buff[64];
|
|
str.strcpy();
|
|
str.strcpy(buff);
|
|
str.memcpy(buff, buff, 64);
|
|
NS::strcpy();
|
|
NS::strcpy(buff);
|
|
NS::memcpy(buff, buff, 64);
|
|
|
|
std::LibC LibC;
|
|
|
|
LibC.strcpy();
|
|
LibC.strcpy(buff);
|
|
LibC.memcpy(buff, buff, 64);
|
|
}
|
|
|
|
void dontCrashForInvalidFormatString() {
|
|
snprintf((char*)0, 0, "%");
|
|
snprintf((char*)0, 0, "\0");
|
|
}
|
|
|
|
|
|
// Also warn about unsafe printf/scanf-like functions:
|
|
void myprintf(const char *, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
|
void myprintf_2(const char *, int, const char *) __attribute__((__format__ (__printf__, 1, 3)));
|
|
void myprintf_3(const char *, const char *, int, const char *) __attribute__((__format__ (__printf__, 2, 4)));
|
|
void myscanf(const char *, ...) __attribute__((__format__ (__scanf__, 1, 2)));
|
|
|
|
void myprintf_default(const char *, const char * Fmt = "hello %s",
|
|
int X = 0, const char * Str = "world") __attribute__((__format__ (__printf__, 2, 4)));
|
|
|
|
struct FormatAttrTestMember {
|
|
void myprintf(const char *, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
|
void myprintf_2(const char *, int, const char *) __attribute__((__format__ (__printf__, 2, 4)));
|
|
void myprintf_3(const char *, const char *, int, const char *) __attribute__((__format__ (__printf__, 3, 5)));
|
|
void myscanf(const char *, ...) __attribute__((__format__ (__scanf__, 2, 3)));
|
|
|
|
void operator()(const char * Fmt, ...) __attribute__((__format__ (__printf__, 2, 3)));
|
|
void operator[](const char * Fmt) __attribute__((__format__ (__printf__, 2, 3)));
|
|
|
|
|
|
static const char * StrField;
|
|
|
|
void myprintf_default(const char *, const char * Fmt = "hello %s",
|
|
int X = 0, const char * Str = StrField) __attribute__((__format__ (__printf__, 3, 5)));
|
|
};
|
|
|
|
struct FormatAttrTestMember2 {
|
|
void operator()(const char * Fmt, char *) __attribute__((__format__ (__printf__, 2, 3)));
|
|
};
|
|
|
|
void test_format_attr(char * Str, std::string StdStr) {
|
|
myprintf("hello", Str);
|
|
myprintf("hello %s", StdStr.c_str());
|
|
myprintf("hello %s", Str); // expected-warning{{formatting function 'myprintf' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
extern int errno;
|
|
extern char *strerror(int errnum);
|
|
myprintf("errno: %s", strerror(errno));
|
|
|
|
myprintf_2("hello", 0, Str);
|
|
myprintf_2("hello %s", 0, StdStr.c_str());
|
|
myprintf_2("hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_2' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
myprintf_3("irrelevant", "hello", 0, Str);
|
|
myprintf_3("irrelevant", "hello %s", 0, StdStr.c_str());
|
|
myprintf_3("irrelevant", "hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_3' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
myscanf("hello %s");
|
|
myscanf("hello %s", Str); // expected-warning{{function 'myscanf' is unsafe}}
|
|
|
|
myprintf_default("irrelevant");
|
|
|
|
int X;
|
|
|
|
myscanf("hello %d", &X); // expected-warning{{function 'myscanf' is unsafe}}
|
|
|
|
// Test member functions:
|
|
FormatAttrTestMember Obj;
|
|
|
|
Obj.myprintf("hello", Str);
|
|
Obj.myprintf("hello %s", StdStr.c_str());
|
|
Obj.myprintf("hello %s", Str); // expected-warning{{formatting function 'myprintf' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
Obj.myprintf_2("hello", 0, Str);
|
|
Obj.myprintf_2("hello %s", 0, StdStr.c_str());
|
|
Obj.myprintf_2("hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_2' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
Obj.myprintf_3("irrelevant", "hello", 0, Str);
|
|
Obj.myprintf_3("irrelevant", "hello %s", 0, StdStr.c_str());
|
|
Obj.myprintf_3("irrelevant", "hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_3' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
Obj.myscanf("hello %s");
|
|
Obj.myscanf("hello %s", Str); // expected-warning{{formatting function 'myscanf' is unsafe}}
|
|
|
|
Obj.myscanf("hello %d", &X); // expected-warning{{formatting function 'myscanf' is unsafe}}
|
|
|
|
Obj.myprintf_default("irrelevant"); // expected-warning{{formatting function 'myprintf_default' is unsafe}}
|
|
// expected-note@*{{string argument is not guaranteed to be null-terminated}}
|
|
|
|
Obj("hello", Str);
|
|
Obj("hello %s", StdStr.c_str());
|
|
Obj("hello %s", Str); // expected-warning{{formatting function 'operator()' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
Obj["hello"];
|
|
Obj["hello %s"];
|
|
|
|
FormatAttrTestMember2 Obj2;
|
|
|
|
Obj2("hello", Str);
|
|
Obj2("hello %s", StdStr.c_str());
|
|
Obj2("hello %s", Str); // expected-warning{{formatting function 'operator()' is unsafe}} \
|
|
expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
}
|
|
|
|
// The second attribute argument, which points the starting index of
|
|
// format string arguments, may not be a valid argument index:
|
|
void myprintf_arg_idx_oob(const char *) __attribute__((__format__ (__printf__, 1, 2)));
|
|
|
|
void test_format_attr_invalid_arg_idx(char * Str, std::string StdStr) {
|
|
myprintf_arg_idx_oob("hello");
|
|
myprintf_arg_idx_oob(Str); // expected-warning{{formatting function 'myprintf_arg_idx_oob' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
myprintf_arg_idx_oob(StdStr.c_str());
|
|
myprintf("hello");
|
|
myprintf(Str); // expected-warning{{formatting function 'myprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
|
|
myprintf(StdStr.c_str());
|
|
}
|
|
|
|
|
|
void memset_address_of_operator() {
|
|
int i = 0;
|
|
|
|
// memory-safe and considered safe by the check
|
|
memset(&i, 0, sizeof(i));
|
|
memset(&i, 0, sizeof i);
|
|
memset(&(i), 0, sizeof(i));
|
|
memset(&(i), 0, sizeof i);
|
|
|
|
// memory-safe but considered unsafe by the check
|
|
memset(&i, 0, 0); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(&i, 0, 1); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(&i, 0, sizeof(int)); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(&(++i), 0, sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
|
|
// unsafe
|
|
memset(nullptr, 0, 10); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(&i, 0, 10); // expected-warning{{function 'memset' is unsafe}}
|
|
}
|
|
|
|
void memset_address_of_function() {
|
|
int i = 0;
|
|
|
|
// memory-safe and considered safe by the check
|
|
memset(std::addressof(i), 0, sizeof(i));
|
|
memset(std::addressof(i), 0, sizeof i);
|
|
memset(std::addressof((i)), 0, sizeof(i));
|
|
memset(std::addressof((i)), 0, sizeof i);
|
|
|
|
// memory-safe but considered unsafe by the check
|
|
memset(std::addressof(i), 0, 0); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(std::addressof(i), 0, 1); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(std::addressof(i), 0, sizeof(int)); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(std::addressof(++i), 0, sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
|
|
// unsafe
|
|
memset(std::addressof(i), 0, 10); // expected-warning{{function 'memset' is unsafe}}
|
|
}
|
|
|
|
// Unknown `memset`s with more or less parameters.
|
|
void *memset(void *s, size_t n);
|
|
void *memset(void *s, int c, size_t n, size_t destlen);
|
|
|
|
void unknown_memset_unsafe() {
|
|
int i = 0;
|
|
|
|
memset(&i, sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(&i, 0, sizeof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(std::addressof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
memset(std::addressof(i), 0, sizeof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}}
|
|
}
|
|
|
|
void builtin_memset() {
|
|
int i = 0;
|
|
|
|
// memory-safe and considered safe by the check
|
|
__builtin_memset(&i, 0, sizeof(i));
|
|
|
|
// may be memory-safe but considered unsafe by the check
|
|
__builtin_memset(&i, 0 , 4); // expected-warning{{function '__builtin_memset' is unsafe}}
|
|
__builtin___memset_chk(&i, 0 , 4, 4); // expected-warning{{function '__builtin___memset_chk' is unsafe}}
|
|
__builtin___memset_chk(&i, 0 , sizeof(i), sizeof(i)); // expected-warning{{function '__builtin___memset_chk' is unsafe}}
|
|
}
|
|
|
|
namespace ms {
|
|
void memset(void *s, int c, size_t n);
|
|
void __builtin_memset(void *s, int c, size_t n);
|
|
}
|
|
|
|
// Custom-written `memset` functions are not included in the check.
|
|
// Note: `using namespace ms;` results in compilation errors
|
|
// ("call to 'memset' is ambiguous") which block other warnings,
|
|
// so we don't include a test for it.
|
|
void using_custom_memset_safe() {
|
|
int i = 0;
|
|
|
|
ms::memset(&i, 0, 10);
|
|
ms::__builtin_memset(&i, 0, 10);
|
|
|
|
using ms::memset;
|
|
memset(&i, 0, 10);
|
|
using ms::__builtin_memset;
|
|
__builtin_memset(&i, 0, 10);
|
|
}
|
|
|
|
#ifdef TEST_STD_NS
|
|
void qualified_std_memset() {
|
|
int i = 0;
|
|
|
|
// memory-safe and considered safe by the check
|
|
std::memset(&i, 0, sizeof(i));
|
|
|
|
// unsafe
|
|
std::memset(&i, 0 , 10); // expected-warning{{function 'memset' is unsafe}}
|
|
}
|
|
#endif
|
|
|