Yoorkin created this revision.
Yoorkin added a reviewer: clang-tools-extra.
Yoorkin added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun, mgorny.
Herald added a project: All.
Yoorkin requested review of this revision.
Herald added a subscriber: cfe-commits.
Hi, I have added a clang-tidy check which proposed in this issue
<https://github.com/llvm/llvm-project/issues/40511>.
The check can finds sprintf usage like:
char buff[50];
sprintf(buff,"Hello, %s!\n","world");
And suggest counted version function instead:
warning: string to be written may exceeds the size of buffer; use snprintf
instead [bugprone-sprintf-with-fixed-size-buffer]
sprintf(buff,"Hello, %s!\n","world");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
snprintf(buff, sizeof(buff), "Hello, %s!\n", "world")
https://reviews.llvm.org/D132294
Files:
clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.cpp
clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.h
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-with-fixed-size-buffer.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-with-fixed-size-buffer.cpp
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-with-fixed-size-buffer.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-with-fixed-size-buffer.cpp
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s bugprone-sprintf-with-fixed-size-buffer %t
+
+#include <stdio.h>
+
+void f(){
+ char buff[80];
+ sprintf(buff, "Hello, %s!\n", "world");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: string to be written may exceeds the size of buffer; use snprintf instead [bugprone-sprintf-with-fixed-size-buffer]
+ // CHECK-FIXES: snprintf(buff, sizeof(buff), "Hello, %s!\n", "world");
+}
+
+
+char sbuff[80];
+
+void f2(){
+ sprintf(sbuff, "Hello, %s!\n", "world");
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: string to be written may exceeds the size of buffer; use snprintf instead [bugprone-sprintf-with-fixed-size-buffer]
+ // CHECK-FIXES: snprintf(sbuff, sizeof(sbuff), "Hello, %s!\n", "world");
+}
+
+void f3(){
+ char *dynamic_sized_buff = nullptr;
+ sprintf(dynamic_sized_buff, "Hello, %s!\n", "world");
+}
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -114,6 +114,7 @@
`bugprone-signed-char-misuse <bugprone/signed-char-misuse.html>`_,
`bugprone-sizeof-container <bugprone/sizeof-container.html>`_,
`bugprone-sizeof-expression <bugprone/sizeof-expression.html>`_,
+ `bugprone-sprintf-with-fixed-size-buffer <bugprone/sprintf-with-fixed-size-buffer.html>`_, "Yes"
`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions.html>`_,
`bugprone-string-constructor <bugprone/string-constructor.html>`_, "Yes"
`bugprone-string-integer-assignment <bugprone/string-integer-assignment.html>`_, "Yes"
Index: clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-with-fixed-size-buffer.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-with-fixed-size-buffer.rst
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - bugprone-sprintf-with-fixed-size-buffer
+
+bugprone-sprintf-with-fixed-size-buffer
+=======================================
+
+The check finds usage of `sprintf`, which write output string into a fixed-size
+array. It will suggest `snprintf` instead.
+
+It's a common idiom to have a fixed-size buffer of characters allocated on
+the stack and then to printf into the buffer. It may be leading to errors if the
+string to be written exceeds the size of the array pointed to by buffer.
+
+Example:
+.. code-block:: c++
+ void f(){
+ char buff[80];
+ sprintf(buff, "Hello, %s!\n", "world");
+ }
+
+Becomes:
+.. code-block:: c++
+ void f(){
+ char buff[80];
+ snprintf(buff, sizeof(buff), "Hello, %s!\n", "world");
+ }
\ No newline at end of file
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -99,6 +99,11 @@
New checks
^^^^^^^^^^
+- New :doc:`bugprone-sprintf-with-fixed-size-buffer
+ <clang-tidy/checks/bugprone/sprintf-with-fixed-size-buffer>` check.
+
+ FIXME: add release notes.
+
- New :doc:`cppcoreguidelines-avoid-const-or-ref-data-members
<clang-tidy/checks/cppcoreguidelines/avoid-const-or-ref-data-members>` check.
Index: clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.h
@@ -0,0 +1,35 @@
+//===--- SprintfWithFixedSizeBufferCheck.h - clang-tidy ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFWITHFIXEDSIZEBUFFERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFWITHFIXEDSIZEBUFFERCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Check if `sprintf` is called with a fixed size buffer. Replaced with counted
+/// version `snprintf`.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-with-fixed-size-buffer.html
+class SprintfWithFixedSizeBufferCheck : public ClangTidyCheck {
+public:
+ SprintfWithFixedSizeBufferCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFWITHFIXEDSIZEBUFFERCHECK_H
Index: clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/SprintfWithFixedSizeBufferCheck.cpp
@@ -0,0 +1,73 @@
+//===--- SprintfWithFixedSizeBufferCheck.cpp - clang-tidy -----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "SprintfWithFixedSizeBufferCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SprintfWithFixedSizeBufferCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ callExpr(allOf(hasArgument(0, declRefExpr(hasType(constantArrayType()))
+ .bind("ConstantArray")),
+ callee(functionDecl(hasName("::sprintf")))))
+ .bind("sprintf"),
+ this);
+}
+
+void SprintfWithFixedSizeBufferCheck::check(
+ const MatchFinder::MatchResult &Result) {
+ const DeclRefExpr *CA = Result.Nodes.getNodeAs<DeclRefExpr>("ConstantArray");
+ const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("sprintf");
+
+ std::string ReplacementText = "snprintf(";
+ auto arg = Call->getArgs();
+
+ // Get first argument.
+ SourceRange SrcRange = arg[0]->getSourceRange();
+ ReplacementText +=
+ Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange),
+ *Result.SourceManager, getLangOpts());
+
+ // Insert the size of buffer after first argument.
+ ReplacementText += ", sizeof(";
+ ReplacementText +=
+ Lexer::getSourceText(CharSourceRange::getTokenRange(CA->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ ReplacementText += ")";
+
+ // Process the remaining arguments.
+ for (unsigned i = 1; i < Call->getNumArgs(); i++) {
+ ReplacementText += ", ";
+ ReplacementText += Lexer::getSourceText(
+ CharSourceRange::getTokenRange(arg[i]->getSourceRange()),
+ *Result.SourceManager, getLangOpts());
+ }
+
+ ReplacementText += ')';
+
+ FixItHint hint =
+ FixItHint::CreateReplacement(Call->getSourceRange(), ReplacementText);
+
+ diag(Call->getBeginLoc(), "string to be written may exceeds the size of "
+ "buffer; use snprintf instead")
+ << SourceRange(Call->getBeginLoc(), Call->getEndLoc()) << hint;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -44,6 +44,7 @@
SignedCharMisuseCheck.cpp
SizeofContainerCheck.cpp
SizeofExpressionCheck.cpp
+ SprintfWithFixedSizeBufferCheck.cpp
SpuriouslyWakeUpFunctionsCheck.cpp
StringConstructorCheck.cpp
StringIntegerAssignmentCheck.cpp
Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -48,6 +48,7 @@
#include "SignedCharMisuseCheck.h"
#include "SizeofContainerCheck.h"
#include "SizeofExpressionCheck.h"
+#include "SprintfWithFixedSizeBufferCheck.h"
#include "SpuriouslyWakeUpFunctionsCheck.h"
#include "StringConstructorCheck.h"
#include "StringIntegerAssignmentCheck.h"
@@ -153,6 +154,8 @@
"bugprone-sizeof-container");
CheckFactories.registerCheck<SizeofExpressionCheck>(
"bugprone-sizeof-expression");
+ CheckFactories.registerCheck<SprintfWithFixedSizeBufferCheck>(
+ "bugprone-sprintf-with-fixed-size-buffer");
CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
"bugprone-spuriously-wake-up-functions");
CheckFactories.registerCheck<StringConstructorCheck>(
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits