diff options
Diffstat (limited to 'clang-tools-extra/test/clang-tidy')
10 files changed, 954 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-c.h b/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-c.h new file mode 100644 index 00000000000..9a291124a32 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-c.h @@ -0,0 +1,39 @@ +//===- not-null-terminated-result-c.h - Helper header -------------*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header helps to maintain every function call checked by the +// NotNullTerminatedResult checker. +// +//===----------------------------------------------------------------------===// + +#pragma clang system_header + +typedef unsigned int size_t; +typedef int errno_t; + +size_t strlen(const char *str); +void *malloc(size_t size); +char *strerror(int errnum); +errno_t strerror_s(char *buffer, size_t bufferSize, int errnum); + +char *strcpy(char *dest, const char *src); +errno_t strcpy_s(char *dest, size_t destSize, const char *src); +char *strncpy(char *dest, const char *src, size_t count); +errno_t strncpy_s(char *dest, size_t destSize, const char *src, size_t count); + +void *memcpy(void *dest, const void *src, size_t count); +errno_t memcpy_s(void *dest, size_t destSize, const void *src, size_t count); + +char *strchr(char *str, int c); +int strncmp(const char *str1, const char *str2, size_t count); +size_t strxfrm(char *dest, const char *src, size_t count); + +void *memchr(const void *buffer, int c, size_t count); +void *memmove(void *dest, const void *src, size_t count); +errno_t memmove_s(void *dest, size_t destSize, const void *src, size_t count); +void *memset(void *dest, int c, size_t count); diff --git a/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-cxx.h b/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-cxx.h new file mode 100644 index 00000000000..814c5b5e0f4 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/Inputs/bugprone-not-null-terminated-result/not-null-terminated-result-cxx.h @@ -0,0 +1,65 @@ +//===- not-null-terminated-result-cxx.h - Helper header ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header helps to maintain every function call checked by the +// NotNullTerminatedResult checker. +// +//===----------------------------------------------------------------------===// + +#pragma clang system_header + +#include "not-null-terminated-result-c.h" + +namespace std { +template <typename T> +struct basic_string { + basic_string(); + const T *data() const; + unsigned long size() const; + unsigned long length() const; +}; +typedef basic_string<char> string; +} // namespace std + +size_t wcslen(const wchar_t *str); + +template <size_t size> +char *strcpy(char (&dest)[size], const char *src); +template <size_t size> +wchar_t *wcscpy(wchar_t (&dest)[size], const wchar_t *src); +wchar_t *wcscpy(wchar_t *dest, const wchar_t *src); + +template <size_t size> +errno_t strcpy_s(char (&dest)[size], const char *src); +template <size_t size> +errno_t wcscpy_s(wchar_t (&dest)[size], const wchar_t *src); +errno_t wcscpy_s(wchar_t *dest, size_t destSize, const wchar_t *src); + +template <size_t size> +char *strncpy(char (&dest)[size], const char *src, size_t count); +template <size_t size> +wchar_t *wcsncpy(wchar_t (&dest)[size], const wchar_t *src, size_t count); +wchar_t *wcsncpy(wchar_t *dest, const wchar_t *src, size_t count); + +template <size_t size> +errno_t strncpy_s(char (&dest)[size], const char *src, size_t count); +template <size_t size> +errno_t wcsncpy_s(wchar_t (&dest)[size], const wchar_t *src, size_t length); +errno_t wcsncpy_s(wchar_t *dest, size_t destSize, const wchar_t *src, size_t c); + +wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t count); +errno_t wmemcpy_s(wchar_t *dest, size_t destSize, const wchar_t *src, size_t c); + +wchar_t *wcschr(const wchar_t *str, int c); +int wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t count); +size_t wcsxfrm(wchar_t *dest, const wchar_t *src, size_t count); + +void *wmemchr(const void *buffer, int c, size_t count); +void *wmemmove(void *dest, const void *src, size_t count); +errno_t wmemmove_s(void *dest, size_t destSize, const void *src, size_t count); +void *wmemset(void *dest, int c, size_t count); diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-in-initialization-strlen.c b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-in-initialization-strlen.c new file mode 100644 index 00000000000..259427e3bce --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-in-initialization-strlen.c @@ -0,0 +1,84 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-c.h" + +void path_sensitive_unknown_length(char *position, const char *src) { + int length; + length = strlen(src); + position = (char *)memchr(src, '\0', length); +} + +void bad_memchr(char *position, const char *src) { + int length = strlen(src); + position = (char *)memchr(src, '\0', length); + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] + // CHECK-FIXES: position = strchr(src, '\0'); +} + +void good_memchr(char *pos, const char *src) { + pos = strchr(src, '\0'); +} + +void bad_strerror_s(int errno) { + char dest[13]; + int length = strlen(strerror(errno)); + strerror_s(dest, length, errno); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'strerror_s' is not null-terminated and missing the last character of the error message [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest[14]; + // CHECK-FIXES-NEXT: int length = strlen(strerror(errno)); + // CHECK-FIXES-NEXT: strerror_s(dest, length + 1, errno); +} + +void good_strerror_s(int errno) { + char dst[14]; + int length = strlen(strerror(errno)); + strerror_s(dst, length + 1, errno); +} + +int bad_strncmp_1(char *str1, const char *str2) { + int length = strlen(str1) + 1; + return strncmp(str1, str2, length); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str1, str2, length - 1); +} + +int good_strncmp_1(char *str1, const char *str2) { + int length = strlen(str1) + 1; + return strncmp(str1, str2, length - 1); +} + +int bad_strncmp_2(char *str2) { + return strncmp(str2, "foobar", (strlen("foobar") + 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str2, "foobar", (strlen("foobar"))); +} + +int bad_strncmp_3(char *str3) { + return strncmp(str3, "foobar", 1 + strlen("foobar")); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str3, "foobar", strlen("foobar")); +} + +int good_strncmp_2_3(char *str) { + return strncmp(str, "foobar", strlen("foobar")); +} + +void bad_strxfrm(const char *long_source_name) { + char long_destination_name[13]; + int very_long_length_definition_name = strlen(long_source_name); + strxfrm(long_destination_name, long_source_name, + very_long_length_definition_name); + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: the result from calling 'strxfrm' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char long_destination_name[14]; + // CHECK-FIXES-NEXT: int very_long_length_definition_name = strlen(long_source_name); + // CHECK-FIXES-NEXT: strxfrm(long_destination_name, long_source_name, + // CHECK-FIXES-NEXT: very_long_length_definition_name + 1); +} + +void good_strxfrm(const char *long_source_name) { + char long_destination_name[14]; + int very_long_length_definition_name = strlen(long_source_name); + strxfrm(long_destination_name, long_source_name, + very_long_length_definition_name + 1); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-before-safe.c b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-before-safe.c new file mode 100644 index 00000000000..0217a77d81a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-before-safe.c @@ -0,0 +1,71 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -config="{CheckOptions: \ +// RUN: [{key: bugprone-not-null-terminated-result.WantToUseSafeFunctions, \ +// RUN: value: 1}]}" \ +// RUN: -- -std=c11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-c.h" + +// The following is not defined therefore the safe functions are unavailable. +// #define __STDC_LIB_EXT1__ 1 + +#define __STDC_WANT_LIB_EXT1__ 1 + +//===----------------------------------------------------------------------===// +// memcpy() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_not_just_char_dest(const char *src) { + unsigned char dest00[13]; + memcpy(dest00, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: unsigned char dest00[14]; + // CHECK-FIXES-NEXT: strcpy((char *)dest00, src); +} + +void good_memcpy_not_just_char_dest(const char *src) { + unsigned char dst00[14]; + strcpy((char *)dst00, src); +} + +void bad_memcpy_known_dest(const char *src) { + char dest01[13]; + memcpy(dest01, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy(dest01, src); +} + +void good_memcpy_known_dest(const char *src) { + char dst01[13]; + strcpy(dst01, src); +} + +//===----------------------------------------------------------------------===// +// memcpy() - length tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_full_source_length(const char *src) { + char dest20[13]; + memcpy(dest20, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy(dest20, src); +} + +void good_memcpy_full_source_length(const char *src) { + char dst20[13]; + strcpy(dst20, src); +} + +void bad_memcpy_partial_source_length(const char *src) { + char dest21[13]; + memcpy(dest21, src, strlen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncpy(dest21, src, strlen(src) - 1); + // CHECK-FIXES-NEXT: dest21[strlen(src) - 1] = '\0'; +} + +void good_memcpy_partial_source_length(const char *src) { + char dst21[13]; + strncpy(dst21, src, strlen(src) - 1); + dst21[strlen(src) - 1] = '\0'; +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-cxx.cpp b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-cxx.cpp new file mode 100644 index 00000000000..747bbc308b5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-cxx.cpp @@ -0,0 +1,124 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c++11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-cxx.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +//===----------------------------------------------------------------------===// +// memcpy() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_not_just_char_dest(const char *src) { + unsigned char dest00[13]; + memcpy(dest00, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: unsigned char dest00[14]; + // CHECK-FIXES-NEXT: strcpy_s((char *)dest00, 14, src); +} + +void good_memcpy_not_just_char_dest(const char *src) { + unsigned char dst00[14]; + strcpy_s((char *)dst00, 14, src); +} + +void bad_memcpy_known_dest(const char *src) { + char dest01[13]; + memcpy(dest01, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: dest01[14]; + // CHECK-FIXES-NEXT: strcpy_s(dest01, src); +} + +void good_memcpy_known_dest(const char *src) { + char dst01[14]; + strcpy_s(dst01, src); +} + +//===----------------------------------------------------------------------===// +// memcpy() - length tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_full_source_length(std::string src) { + char *dest20 = reinterpret_cast<char *>(malloc(src.size())); + memcpy(dest20, src.data(), src.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: dest20 = reinterpret_cast<char *>(malloc(src.size() + 1)); + // CHECK-FIXES-NEXT: strcpy(dest20, src.data()); +} + +void good_memcpy_full_source_length(std::string src) { + char dst20[14]; + strcpy_s(dst20, src.data()); +} + +void bad_memcpy_partial_source_length(const char *src) { + char dest21[13]; + memcpy(dest21, src, strlen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest21[14]; + // CHECK-FIXES-NEXT: strncpy_s(dest21, src, strlen(src) - 1); +} + +void good_memcpy_partial_source_length(const char *src) { + char dst21[14]; + strncpy_s(dst21, src, strlen(src) - 1); +} + +//===----------------------------------------------------------------------===// +// memcpy_s() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_s_unknown_dest(char *dest40, const char *src) { + memcpy_s(dest40, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy_s(dest40, 13, src); +} + +void good_memcpy_s_unknown_dest(char *dst40, const char *src) { + strcpy_s(dst40, 13, src); +} + +void bad_memcpy_s_known_dest(const char *src) { + char dest41[13]; + memcpy_s(dest41, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest41[14]; + // CHECK-FIXES: strcpy_s(dest41, src); +} + +void good_memcpy_s_known_dest(const char *src) { + char dst41[14]; + strcpy_s(dst41, src); +} + +//===----------------------------------------------------------------------===// +// memcpy_s() - length tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_s_full_source_length(const char *src) { + char dest60[13]; + memcpy_s(dest60, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest60[14]; + // CHECK-FIXES-NEXT: strcpy_s(dest60, src); +} + +void good_memcpy_s_full_source_length(const char *src) { + char dst60[14]; + strcpy_s(dst60, src); +} + +void bad_memcpy_s_partial_source_length(const char *src) { + char dest61[13]; + memcpy_s(dest61, 13, src, strlen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest61[14]; + // CHECK-FIXES-NEXT: strncpy_s(dest61, src, strlen(src) - 1); +} + +void good_memcpy_s_partial_source_length(const char *src) { + char dst61[14]; + strncpy_s(dst61, src, strlen(src) - 1); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-other.c b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-other.c new file mode 100644 index 00000000000..0a4a45994fd --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe-other.c @@ -0,0 +1,112 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-c.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +#define SRC_LENGTH 3 +#define SRC "foo" + +//===----------------------------------------------------------------------===// +// False positive suppression. +//===----------------------------------------------------------------------===// + +void good_memcpy_known_src() { + char dest[13]; + char src[] = "foobar"; + memcpy(dest, src, sizeof(src)); +} + +void good_memcpy_null_terminated(const char *src) { + char dest[13]; + const int length = strlen(src); + memcpy(dest, src, length); + dest[length] = '\0'; +} + +void good_memcpy_proper_length(const char *src) { + char *dest = 0; + int length = strlen(src) + 1; + dest = (char *)malloc(length); + memcpy(dest, src, length); +} + +void may_bad_memcpy_unknown_length(const char *src, int length) { + char dest[13]; + memcpy(dest, src, length); +} + +void may_bad_memcpy_const_length(const char *src) { + char dest[13]; + memcpy(dest, src, 12); +} + +//===----------------------------------------------------------------------===// +// Special cases. +//===----------------------------------------------------------------------===// + +void bad_memcpy_unknown_dest(char *dest01, const char *src) { + memcpy(dest01, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy(dest01, src); +} + +void good_memcpy_unknown_dest(char *dst01, const char *src) { + strcpy(dst01, src); +} + +void bad_memcpy_variable_array(int dest_length) { + char dest02[dest_length + 1]; + memcpy(dest02, "foobarbazqux", strlen("foobarbazqux")); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy(dest02, "foobarbazqux"); +} + +void good_memcpy_variable_array(int dest_length) { + char dst02[dest_length + 1]; + strcpy(dst02, "foobarbazqux"); +} + +void bad_memcpy_equal_src_length_and_length() { + char dest03[13]; + const char *src = "foobarbazqux"; + memcpy(dest03, src, 12); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy(dest03, src); +} + +void good_memcpy_equal_src_length_and_length() { + char dst03[13]; + const char *src = "foobarbazqux"; + strcpy(dst03, src); +} + +void bad_memcpy_dest_size_overflows(const char *src) { + const int length = strlen(src); + char *dest04 = (char *)malloc(length); + memcpy(dest04, src, length); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char *dest04 = (char *)malloc(length + 1); + // CHECK-FIXES-NEXT: strcpy(dest04, src); +} + +void good_memcpy_dest_size_overflows(const char *src) { + const int length = strlen(src); + char *dst04 = (char *)malloc(length + 1); + strcpy(dst04, src); +} + +void bad_memcpy_macro() { + char dest05[SRC_LENGTH]; + memcpy(dest05, SRC, SRC_LENGTH); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest05[SRC_LENGTH + 1]; + // CHECK-FIXES-NEXT: strcpy(dest05, SRC); +} + +void good_memcpy_macro() { + char dst05[SRC_LENGTH + 1]; + strcpy(dst05, SRC); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe.c b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe.c new file mode 100644 index 00000000000..9a2d48fcae2 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-memcpy-safe.c @@ -0,0 +1,124 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-c.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +//===----------------------------------------------------------------------===// +// memcpy() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_not_just_char_dest(const char *src) { + unsigned char dest00[13]; + memcpy(dest00, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: unsigned char dest00[14]; + // CHECK-FIXES-NEXT: strcpy_s((char *)dest00, 14, src); +} + +void good_memcpy_not_just_char_dest(const char *src) { + unsigned char dst00[14]; + strcpy_s((char *)dst00, 14, src); +} + +void bad_memcpy_known_dest(const char *src) { + char dest01[13]; + memcpy(dest01, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest01[14]; + // CHECK-FIXES: strcpy_s(dest01, 14, src); +} + +void good_memcpy_known_dest(const char *src) { + char dst01[14]; + strcpy_s(dst01, 14, src); +} + +//===----------------------------------------------------------------------===// +// memcpy() - length tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_full_source_length(const char *src) { + char dest20[13]; + memcpy(dest20, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest20[14]; + // CHECK-FIXES-NEXT: strcpy_s(dest20, 14, src); +} + +void good_memcpy_full_source_length(const char *src) { + char dst20[14]; + strcpy_s(dst20, 14, src); +} + +void bad_memcpy_partial_source_length(const char *src) { + char dest21[13]; + memcpy(dest21, src, strlen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest21[14]; + // CHECK-FIXES-NEXT: strncpy_s(dest21, 14, src, strlen(src) - 1); +} + +void good__memcpy_partial_source_length(const char *src) { + char dst21[14]; + strncpy_s(dst21, 14, src, strlen(src) - 1); +} + +//===----------------------------------------------------------------------===// +// memcpy_s() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_s_unknown_dest(char *dest40, const char *src) { + memcpy_s(dest40, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: strcpy_s(dest40, 13, src); +} + +void good_memcpy_s_unknown_dest(char *dst40, const char *src) { + strcpy_s(dst40, 13, src); +} + +void bad_memcpy_s_known_dest(const char *src) { + char dest41[13]; + memcpy_s(dest41, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest41[14]; + // CHECK-FIXES-NEXT: strcpy_s(dest41, 14, src); +} + +void good_memcpy_s_known_dest(const char *src) { + char dst41[14]; + strcpy_s(dst41, 14, src); +} + +//===----------------------------------------------------------------------===// +// memcpy_s() - length tests +//===----------------------------------------------------------------------===// + +void bad_memcpy_s_full_source_length(const char *src) { + char dest60[13]; + memcpy_s(dest60, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest60[14]; + // CHECK-FIXES-NEXT: strcpy_s(dest60, 14, src); +} + +void good_memcpy_s_full_source_length(const char *src) { + char dst60[14]; + strcpy_s(dst60, 14, src); +} + +void bad_memcpy_s_partial_source_length(const char *src) { + char dest61[13]; + memcpy_s(dest61, 13, src, strlen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest61[14]; + // CHECK-FIXES-NEXT: strncpy_s(dest61, 14, src, strlen(src) - 1); +} + +void good_memcpy_s_partial_source_length(const char *src) { + char dst61[14]; + strncpy_s(dst61, 14, src, strlen(src) - 1); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-strlen.c b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-strlen.c new file mode 100644 index 00000000000..48f8c278c86 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-strlen.c @@ -0,0 +1,118 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-c.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +void bad_memchr_1(char *position, const char *src) { + position = (char *)memchr(src, '\0', strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] + // CHECK-FIXES: position = strchr(src, '\0'); +} + +void good_memchr_1(char *pos, const char *src) { + pos = strchr(src, '\0'); +} + +void bad_memchr_2(char *position) { + position = (char *)memchr("foobar", '\0', 6); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] + // CHECK-FIXES: position = strchr("foobar", '\0'); +} + +void good_memchr_2(char *pos) { + pos = strchr("foobar", '\0'); +} + +void bad_memmove(const char *src) { + char dest[13]; + memmove(dest, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memmove' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest[14]; + // CHECK-FIXES-NEXT: memmove_s(dest, 14, src, strlen(src) + 1); +} + +void good_memmove(const char *src) { + char dst[14]; + memmove_s(dst, 13, src, strlen(src) + 1); +} + +void bad_memmove_s(char *dest, const char *src) { + memmove_s(dest, 13, src, strlen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'memmove_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: memmove_s(dest, 13, src, strlen(src) + 1); +} + +void good_memmove_s_1(char *dest, const char *src) { + memmove_s(dest, 13, src, strlen(src) + 1); +} + +void bad_strerror_s(int errno) { + char dest[13]; + strerror_s(dest, strlen(strerror(errno)), errno); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'strerror_s' is not null-terminated and missing the last character of the error message [bugprone-not-null-terminated-result] + // CHECK-FIXES: char dest[14]; + // CHECK-FIXES-NEXT: strerror_s(dest, strlen(strerror(errno)) + 1, errno); +} + +void good_strerror_s(int errno) { + char dst[14]; + strerror_s(dst, strlen(strerror(errno)) + 1, errno); +} + +int bad_strncmp_1(char *str0, const char *str1) { + return strncmp(str0, str1, (strlen(str0) + 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str0, str1, (strlen(str0))); +} + +int bad_strncmp_2(char *str2, const char *str3) { + return strncmp(str2, str3, 1 + strlen(str2)); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str2, str3, strlen(str2)); +} + +int good_strncmp_1_2(char *str4, const char *str5) { + return strncmp(str4, str5, strlen(str4)); +} + +int bad_strncmp_3(char *str6) { + return strncmp(str6, "string", 7); + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: strncmp(str6, "string", 6); +} + +int good_strncmp_3(char *str7) { + return strncmp(str7, "string", 6); +} + +void bad_strxfrm_1(const char *long_source_name) { + char long_destination_array_name[13]; + strxfrm(long_destination_array_name, long_source_name, + strlen(long_source_name)); + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: the result from calling 'strxfrm' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char long_destination_array_name[14]; + // CHECK-FIXES-NEXT: strxfrm(long_destination_array_name, long_source_name, + // CHECK-FIXES-NEXT: strlen(long_source_name) + 1); +} + +void good_strxfrm_1(const char *long_source_name) { + char long_destination_array_name[14]; + strxfrm(long_destination_array_name, long_source_name, + strlen(long_source_name) + 1); +} + +void bad_strxfrm_2() { + char long_destination_array_name1[16]; + strxfrm(long_destination_array_name1, "long_source_name", 16); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'strxfrm' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: char long_destination_array_name1[17]; + // CHECK-FIXES: strxfrm(long_destination_array_name1, "long_source_name", 17); +} + +void good_strxfrm_2() { + char long_destination_array_name2[17]; + strxfrm(long_destination_array_name2, "long_source_name", 17); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wcslen.cpp b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wcslen.cpp new file mode 100644 index 00000000000..b8ac76cc901 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wcslen.cpp @@ -0,0 +1,106 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c++11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-cxx.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +void bad_wmemchr_1(wchar_t *position, const wchar_t *src) { + position = (wchar_t *)wmemchr(src, L'\0', wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:45: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] + // CHECK-FIXES: position = wcschr(src, L'\0'); +} + +void good_wmemchr_1(wchar_t *pos, const wchar_t *src) { + pos = wcschr(src, L'\0'); +} + +void bad_wmemchr_2(wchar_t *position) { + position = (wchar_t *)wmemchr(L"foobar", L'\0', 6); + // CHECK-MESSAGES: :[[@LINE-1]]:51: warning: the length is too short to include the null terminator [bugprone-not-null-terminated-result] + // CHECK-FIXES: position = wcschr(L"foobar", L'\0'); +} + +void good_wmemchr_2(wchar_t *pos) { + pos = wcschr(L"foobar", L'\0'); +} + + +void bad_wmemmove(const wchar_t *src) { + wchar_t dest[13]; + wmemmove(dest, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemmove' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest[14]; + // CHECK-FIXES-NEXT: wmemmove_s(dest, 14, src, wcslen(src) + 1); +} + +void good_wmemmove(const wchar_t *src) { + wchar_t dst[14]; + wmemmove_s(dst, 13, src, wcslen(src) + 1); +} + +void bad_wmemmove_s(wchar_t *dest, const wchar_t *src) { + wmemmove_s(dest, 13, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemmove_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wmemmove_s(dest, 13, src, wcslen(src) + 1); +} + +void good_wmemmove_s_1(wchar_t *dest, const wchar_t *src) { + wmemmove_s(dest, 13, src, wcslen(src) + 1); +} + +int bad_wcsncmp_1(wchar_t *wcs0, const wchar_t *wcs1) { + return wcsncmp(wcs0, wcs1, (wcslen(wcs0) + 1)); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: wcsncmp(wcs0, wcs1, (wcslen(wcs0))); +} + +int bad_wcsncmp_2(wchar_t *wcs2, const wchar_t *wcs3) { + return wcsncmp(wcs2, wcs3, 1 + wcslen(wcs2)); + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: wcsncmp(wcs2, wcs3, wcslen(wcs2)); +} + +int good_wcsncmp_1_2(wchar_t *wcs4, const wchar_t *wcs5) { + return wcsncmp(wcs4, wcs5, wcslen(wcs4)); +} + +int bad_wcsncmp_3(wchar_t *wcs6) { + return wcsncmp(wcs6, L"string", 7); + // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: comparison length is too long and might lead to a buffer overflow [bugprone-not-null-terminated-result] + // CHECK-FIXES: wcsncmp(wcs6, L"string", 6); +} + +int good_wcsncmp_3(wchar_t *wcs7) { + return wcsncmp(wcs7, L"string", 6); +} + +void bad_wcsxfrm_1(const wchar_t *long_source_name) { + wchar_t long_destination_array_name[13]; + wcsxfrm(long_destination_array_name, long_source_name, + wcslen(long_source_name)); + // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: the result from calling 'wcsxfrm' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t long_destination_array_name[14]; + // CHECK-FIXES-NEXT: wcsxfrm(long_destination_array_name, long_source_name, + // CHECK-FIXES-NEXT: wcslen(long_source_name) + 1); +} + +void good_wcsxfrm_1(const wchar_t *long_source_name) { + wchar_t long_destination_array_name[14]; + wcsxfrm(long_destination_array_name, long_source_name, + wcslen(long_source_name) + 1); +} + +void bad_wcsxfrm_2() { + wchar_t long_destination_array_name1[16]; + wcsxfrm(long_destination_array_name1, L"long_source_name", 16); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wcsxfrm' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t long_destination_array_name1[17]; + // CHECK-FIXES: wcsxfrm(long_destination_array_name1, L"long_source_name", 17); +} + +void good_wcsxfrm_2() { + wchar_t long_destination_array_name2[17]; + wcsxfrm(long_destination_array_name2, L"long_source_name", 17); +} diff --git a/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wmemcpy-safe-cxx.cpp b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wmemcpy-safe-cxx.cpp new file mode 100644 index 00000000000..6c8aee0af13 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-not-null-terminated-result-wmemcpy-safe-cxx.cpp @@ -0,0 +1,111 @@ +// RUN: %check_clang_tidy %s bugprone-not-null-terminated-result %t -- \ +// RUN: -- -std=c++11 -I %S/Inputs/bugprone-not-null-terminated-result + +#include "not-null-terminated-result-cxx.h" + +#define __STDC_LIB_EXT1__ 1 +#define __STDC_WANT_LIB_EXT1__ 1 + +//===----------------------------------------------------------------------===// +// wmemcpy() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_wmemcpy_known_dest(const wchar_t *src) { + wchar_t dest01[13]; + wmemcpy(dest01, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest01[14]; + // CHECK-FIXES-NEXT: wcscpy_s(dest01, src); +} + +void good_wmemcpy_known_dest(const wchar_t *src) { + wchar_t dst01[14]; + wcscpy_s(dst01, src); +} + +//===----------------------------------------------------------------------===// +// wmemcpy() - length tests +//===----------------------------------------------------------------------===// + +void bad_wmemcpy_full_source_length(const wchar_t *src) { + wchar_t dest20[13]; + wmemcpy(dest20, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest20[14]; + // CHECK-FIXES-NEXT: wcscpy_s(dest20, src); +} + +void good_wmemcpy_full_source_length(const wchar_t *src) { + wchar_t dst20[14]; + wcscpy_s(dst20, src); +} + +void bad_wmemcpy_partial_source_length(const wchar_t *src) { + wchar_t dest21[13]; + wmemcpy(dest21, src, wcslen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest21[14]; + // CHECK-FIXES-NEXT: wcsncpy_s(dest21, src, wcslen(src) - 1); +} + +void good_wmemcpy_partial_source_length(const wchar_t *src) { + wchar_t dst21[14]; + wcsncpy_s(dst21, src, wcslen(src) - 1); +} + +//===----------------------------------------------------------------------===// +// wmemcpy_s() - destination array tests +//===----------------------------------------------------------------------===// + +void bad_wmemcpy_s_unknown_dest(wchar_t *dest40, const wchar_t *src) { + wmemcpy_s(dest40, 13, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wcscpy_s(dest40, 13, src); +} + +void good_wmemcpy_s_unknown_dest(wchar_t *dst40, const wchar_t *src) { + wcscpy_s(dst40, 13, src); +} + +void bad_wmemcpy_s_known_dest(const wchar_t *src) { + wchar_t dest41[13]; + wmemcpy_s(dest41, 13, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest41[14]; + // CHECK-FIXES-NEXT: wcscpy_s(dest41, src); +} + +void good_wmemcpy_s_known_dest(const wchar_t *src) { + wchar_t dst41[13]; + wcscpy_s(dst41, src); +} + +//===----------------------------------------------------------------------===// +// wmemcpy_s() - length tests +//===----------------------------------------------------------------------===// + +void bad_wmemcpy_s_full_source_length(const wchar_t *src) { + wchar_t dest60[13]; + wmemcpy_s(dest60, 13, src, wcslen(src)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest60[14]; + // CHECK-FIXES-NEXT: wcscpy_s(dest60, src); +} + +void good_wmemcpy_s_full_source_length(const wchar_t *src) { + wchar_t dst60[13]; + wcscpy_s(dst60, src); +} + +void bad_wmemcpy_s_partial_source_length(const wchar_t *src) { + wchar_t dest61[13]; + wmemcpy_s(dest61, 13, src, wcslen(src) - 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: the result from calling 'wmemcpy_s' is not null-terminated [bugprone-not-null-terminated-result] + // CHECK-FIXES: wchar_t dest61[14]; + // CHECK-FIXES-NEXT: wcsncpy_s(dest61, src, wcslen(src) - 1); +} + +void good_wmemcpy_s_partial_source_length(const wchar_t *src) { + wchar_t dst61[13]; + wcsncpy_s(dst61, src, wcslen(src) - 1); +} |