Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -23,6 +23,7 @@ #include "LimitedRandomnessCheck.h" #include "PostfixOperatorCheck.h" #include "ProperlySeededRandomGeneratorCheck.h" +#include "PutenvWithAutoCheck.h" #include "SetLongJmpCheck.h" #include "StaticObjectExceptionCheck.h" #include "StrToNumCheck.h" @@ -82,6 +83,8 @@ CheckFactories.registerCheck("cert-msc30-c"); CheckFactories.registerCheck( "cert-msc32-c"); + // POS + CheckFactories.registerCheck("cert-pos34-c"); } ClangTidyOptions getModuleOptions() override { Index: clang-tools-extra/clang-tidy/cert/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-tidy/cert/CMakeLists.txt +++ clang-tools-extra/clang-tidy/cert/CMakeLists.txt @@ -8,6 +8,7 @@ LimitedRandomnessCheck.cpp PostfixOperatorCheck.cpp ProperlySeededRandomGeneratorCheck.cpp + PutenvWithAutoCheck.cpp SetLongJmpCheck.cpp StaticObjectExceptionCheck.cpp StrToNumCheck.cpp Index: clang-tools-extra/clang-tidy/cert/PutenvWithAutoCheck.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/cert/PutenvWithAutoCheck.h @@ -0,0 +1,34 @@ +//===--- PutenvWithAutoCheck.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_CERT_PUTENV_WITH_AUTO_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_PUTENV_WITH_AUTO_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace cert { + +/// Finds calls of putenv function with automatic variable as the argument. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cert-pos34-c.html +class PutenvWithAutoCheck : public ClangTidyCheck { +public: + PutenvWithAutoCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cert +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_PUTENV_WITH_AUTO_H Index: clang-tools-extra/clang-tidy/cert/PutenvWithAutoCheck.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/cert/PutenvWithAutoCheck.cpp @@ -0,0 +1,42 @@ +//===--- PutenvWithAutoCheck.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 "PutenvWithAutoCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cert { + +void PutenvWithAutoCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr( + callee(functionDecl(hasName("::putenv"))), + hasArgument( + 0, + declRefExpr(hasDeclaration(varDecl( + hasAutomaticStorageDuration(), + unless(hasDescendant(callExpr(callee(functionDecl(hasAnyName( + "::alloc", "::malloc", "::realloc", "::calloc"))))))))))) + .bind("func"), + this); +} + +void PutenvWithAutoCheck::check(const MatchFinder::MatchResult &Result) { + const auto *PutenvCall = Result.Nodes.getNodeAs("func"); + + diag(PutenvCall->getBeginLoc(), + "'putenv' function should not be called with auto variables"); +} + +} // namespace cert +} // namespace tidy +} // namespace clang Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -194,6 +194,11 @@ against self-assignment either by checking self-assignment explicitly or using the copy-and-swap or the copy-and-move method. +- New :doc:`cert-pos34-c + ` check. + + Finds calls of ``putenv`` function with automatic variable as the argument. + - New :doc:`fuchsia-default-arguments-calls ` check. Index: clang-tools-extra/docs/clang-tidy/checks/cert-pos34-c.rst =================================================================== --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/cert-pos34-c.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - cert-pos34-c + +cert-pos34-c +===================== + +Finds calls of ``putenv`` function with automatic variable as the argument. + +.. code-block:: c + + #include + + int func(const char *var) { + char env[1024]; + int retval = snprintf(env, sizeof(env),"TEST=%s", var); + if (retval < 0 || (size_t)retval >= sizeof(env)) { + /* Handle error */ + } + + return putenv(env); // putenv function should not be called with auto variables + } + + +This check corresponds to the CERT Standard rule +`POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument. +`_. 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 @@ -102,6 +102,7 @@ cert-msc51-cpp cert-oop11-cpp (redirects to performance-move-constructor-init) cert-oop54-cpp (redirects to bugprone-unhandled-self-assignment) + cert-pos34-c cppcoreguidelines-avoid-c-arrays (redirects to modernize-avoid-c-arrays) cppcoreguidelines-avoid-goto cppcoreguidelines-avoid-magic-numbers (redirects to readability-magic-numbers) Index: clang-tools-extra/test/clang-tidy/cert-pos34-c.cpp =================================================================== --- /dev/null +++ clang-tools-extra/test/clang-tidy/cert-pos34-c.cpp @@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s cert-pos34-c %t +#include +#include + +namespace test_auto_var_used_bad { + +int func1(const char *var) { + char env[1024]; + /* + Do Something + */ + return putenv(env); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'putenv' function should not be called with auto variables [cert-pos34-c] +} + +int func2(char *a) { + return putenv(a); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: 'putenv' function should not be called with auto variables [cert-pos34-c] +} + +void func3(char *a) { + putenv(a); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'putenv' function should not be called with auto variables [cert-pos34-c] +} + +} // namespace test_auto_var_used_bad + +namespace test_auto_var_used_good { + +int func4(const char *var) { + static char env[1024]; + /* + Do Something + */ + return putenv(env); // no-warning: env is static. +} + +// example from cert +int func5(const char *var) { + static char *oldenv; + const char *env_format = "TEST=%s"; + const size_t len = strlen(var) + strlen(env_format); + char *env = (char *)malloc(len); + if (env == NULL) { + return -1; + } + if (putenv(env) != 0) { // no-warning: env was dynamically allocated. + free(env); + return -1; + } + if (oldenv != NULL) { + free(oldenv); /* avoid memory leak */ + } + oldenv = env; + return 0; +} + +extern char *testExt; +int func6() { + return putenv(testExt); // no-warning: extern storage class. +} + +} // namespace test_auto_var_used_good