[clang-tidy] Add module for llvm-libc and restrict-system-libc-header-check.

Summary: This adds a new module to enforce standards specific to the llvm-libc project. This change also adds the first check which restricts user from including system libc headers accidentally which can lead to subtle bugs that would be a challenge to detect.

Reviewers: alexfh, hokein, aaron.ballman

Reviewed By: aaron.ballman

Subscribers: juliehockett, arphaman, jfb, abrachet, sivachandra, Eugene.Zelenko, njames93, mgorny, xazax.hun, MaskRay, cfe-commits

Tags: #clang-tools-extra, #libc-project, #clang

Differential Revision: https://reviews.llvm.org/D75332
This commit is contained in:
Paula Toth 2020-03-12 11:38:05 -07:00
parent 360aff0493
commit eb41cc6198
19 changed files with 223 additions and 0 deletions

View File

@ -51,6 +51,7 @@ add_subdirectory(google)
add_subdirectory(hicpp) add_subdirectory(hicpp)
add_subdirectory(linuxkernel) add_subdirectory(linuxkernel)
add_subdirectory(llvm) add_subdirectory(llvm)
add_subdirectory(llvmlibc)
add_subdirectory(misc) add_subdirectory(misc)
add_subdirectory(modernize) add_subdirectory(modernize)
if(CLANG_ENABLE_STATIC_ANALYZER) if(CLANG_ENABLE_STATIC_ANALYZER)
@ -75,6 +76,7 @@ set(ALL_CLANG_TIDY_CHECKS
clangTidyHICPPModule clangTidyHICPPModule
clangTidyLinuxKernelModule clangTidyLinuxKernelModule
clangTidyLLVMModule clangTidyLLVMModule
clangTidyLLVMLibcModule
clangTidyMiscModule clangTidyMiscModule
clangTidyModernizeModule clangTidyModernizeModule
clangTidyObjCModule clangTidyObjCModule

View File

@ -45,6 +45,11 @@ extern volatile int LLVMModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination = static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
LLVMModuleAnchorSource; LLVMModuleAnchorSource;
// This anchor is used to force the linker to link the LLVMLibcModule.
extern volatile int LLVMLibcModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED LLVMLibcModuleAnchorDestination =
LLVMLibcModuleAnchorSource;
// This anchor is used to force the linker to link the CppCoreGuidelinesModule. // This anchor is used to force the linker to link the CppCoreGuidelinesModule.
extern volatile int CppCoreGuidelinesModuleAnchorSource; extern volatile int CppCoreGuidelinesModuleAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination = static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =

View File

@ -0,0 +1,15 @@
set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyLLVMLibcModule
LLVMLibcTidyModule.cpp
RestrictSystemLibcHeadersCheck.cpp
LINK_LIBS
clangAST
clangASTMatchers
clangBasic
clangLex
clangTidy
clangTidyUtils
clangTooling
)

View File

@ -0,0 +1,37 @@
//===--- LLVMLibcTidyModule.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 "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "RestrictSystemLibcHeadersCheck.h"
namespace clang {
namespace tidy {
namespace llvm_libc {
class LLVMLibcModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<RestrictSystemLibcHeadersCheck>(
"llvmlibc-restrict-system-libc-headers");
}
};
// Register the LLVMLibcTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<LLVMLibcModule>
X("llvmlibc-module", "Adds LLVM libc standards checks.");
} // namespace llvm_libc
// This anchor is used to force the linker to link in the generated object file
// and thus register the LLVMLibcModule.
volatile int LLVMLibcModuleAnchorSource = 0;
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,73 @@
//===--- RestrictSystemLibcHeadersCheck.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 "RestrictSystemLibcHeadersCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
namespace clang {
namespace tidy {
namespace llvm_libc {
namespace {
class RestrictedIncludesPPCallbacks : public PPCallbacks {
public:
explicit RestrictedIncludesPPCallbacks(
RestrictSystemLibcHeadersCheck &Check, const SourceManager &SM,
const SmallString<128> CompilerIncudeDir)
: Check(Check), SM(SM), CompilerIncudeDir(CompilerIncudeDir) {}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
private:
RestrictSystemLibcHeadersCheck &Check;
const SourceManager &SM;
const SmallString<128> CompilerIncudeDir;
};
} // namespace
void RestrictedIncludesPPCallbacks::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
if (SrcMgr::isSystem(FileType)) {
// Compiler provided headers are allowed (e.g stddef.h).
if (SearchPath == CompilerIncudeDir) return;
if (!SM.isInMainFile(HashLoc)) {
Check.diag(
HashLoc,
"system libc header %0 not allowed, transitively included from %1")
<< FileName << SM.getFilename(HashLoc);
} else {
Check.diag(HashLoc, "system libc header %0 not allowed") << FileName;
}
}
}
void RestrictSystemLibcHeadersCheck::registerPPCallbacks(
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
SmallString<128> CompilerIncudeDir =
StringRef(PP->getHeaderSearchInfo().getHeaderSearchOpts().ResourceDir);
llvm::sys::path::append(CompilerIncudeDir, "include");
PP->addPPCallbacks(std::make_unique<RestrictedIncludesPPCallbacks>(
*this, SM, CompilerIncudeDir));
}
} // namespace llvm_libc
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,35 @@
//===--- RestrictSystemLibcHeadersCheck.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_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H
#include "../ClangTidyCheck.h"
namespace clang {
namespace tidy {
namespace llvm_libc {
/// Warns of accidental inclusions of system libc headers that aren't
/// compiler provided.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/llvmlibc-restrict-system-libc-headers.html
class RestrictSystemLibcHeadersCheck : public ClangTidyCheck {
public:
RestrictSystemLibcHeadersCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override;
};
} // namespace llvm_libc
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H

View File

@ -67,6 +67,12 @@ The improvements are...
Improvements to clang-tidy Improvements to clang-tidy
-------------------------- --------------------------
New module
^^^^^^^^^^
- New module `llvmlibc`.
This module contains checks related to the LLVM-libc coding standards.
New checks New checks
^^^^^^^^^^ ^^^^^^^^^^
@ -95,6 +101,12 @@ New checks
Flags use of the `C` standard library functions ``memset``, ``memcpy`` and Flags use of the `C` standard library functions ``memset``, ``memcpy`` and
``memcmp`` and similar derivatives on non-trivial types. ``memcmp`` and similar derivatives on non-trivial types.
- New :doc:`llvmlibc-restrict-system-libc-headers
<clang-tidy/checks/llvmlibc-restrict-system-libc-headers>` check.
Finds includes of system libc headers not provided by the compiler within
llvm-libc implementations.
- New :doc:`objc-dealloc-in-category - New :doc:`objc-dealloc-in-category
<clang-tidy/checks/objc-dealloc-in-category>` check. <clang-tidy/checks/objc-dealloc-in-category>` check.

View File

@ -187,6 +187,7 @@ Clang-Tidy Checks
`llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm-prefer-isa-or-dyn-cast-in-conditionals.html>`_, "Yes" `llvm-prefer-isa-or-dyn-cast-in-conditionals <llvm-prefer-isa-or-dyn-cast-in-conditionals.html>`_, "Yes"
`llvm-prefer-register-over-unsigned <llvm-prefer-register-over-unsigned.html>`_, "Yes" `llvm-prefer-register-over-unsigned <llvm-prefer-register-over-unsigned.html>`_, "Yes"
`llvm-twine-local <llvm-twine-local.html>`_, "Yes" `llvm-twine-local <llvm-twine-local.html>`_, "Yes"
`llvmlibc-restrict-system-libc-headers <llvmlibc-restrict-system-libc-headers.html>`_,
`misc-definitions-in-headers <misc-definitions-in-headers.html>`_, "Yes" `misc-definitions-in-headers <misc-definitions-in-headers.html>`_, "Yes"
`misc-misplaced-const <misc-misplaced-const.html>`_, `misc-misplaced-const <misc-misplaced-const.html>`_,
`misc-new-delete-overloads <misc-new-delete-overloads.html>`_, `misc-new-delete-overloads <misc-new-delete-overloads.html>`_,

View File

@ -0,0 +1,20 @@
.. title:: clang-tidy - llvmlibc-restrict-system-libc-headers
llvmlibc-restrict-system-libc-headers
=====================================
Finds includes of system libc headers not provided by the compiler within
llvm-libc implementations.
.. code-block:: c++
#include <stdio.h> // Not allowed because it is part of system libc.
#include <stddef.h> // Allowed because it is provided by the compiler.
#include "internal/stdio.h" // Allowed because it is NOT part of system libc.
This check is necessary because accidentally including system libc headers can
lead to subtle and hard to detect bugs. For example consider a system libc
whose ``dirent`` struct has slightly different field ordering than llvm-libc.
While this will compile successfully, this can cause issues during runtime
because they are ABI incompatible.

View File

@ -68,6 +68,7 @@ Name prefix Description
``google-`` Checks related to Google coding conventions. ``google-`` Checks related to Google coding conventions.
``hicpp-`` Checks related to High Integrity C++ Coding Standard. ``hicpp-`` Checks related to High Integrity C++ Coding Standard.
``llvm-`` Checks related to the LLVM coding conventions. ``llvm-`` Checks related to the LLVM coding conventions.
``llvmlibc-`` Checks related to the LLVM-libc coding standards.
``misc-`` Checks that we didn't have a better category for. ``misc-`` Checks that we didn't have a better category for.
``modernize-`` Checks that advocate usage of modern (currently "modern" ``modernize-`` Checks that advocate usage of modern (currently "modern"
means "C++11") language constructs. means "C++11") language constructs.

View File

@ -0,0 +1 @@
#include <math.h>

View File

@ -0,0 +1,8 @@
// RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \
// RUN: -- -header-filter=.* \
// RUN: -- -I %S/Inputs/llvmlibc \
// RUN: -isystem %S/Inputs/llvmlibc/system \
// RUN: -resource-dir %S/Inputs/llvmlibc/resource
#include "transitive.h"
// CHECK-MESSAGES: :1:1: warning: system libc header math.h not allowed, transitively included from {{.*}}

View File

@ -0,0 +1,13 @@
// RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \
// RUN: -- -- -isystem %S/Inputs/llvmlibc/system \
// RUN: -resource-dir %S/Inputs/llvmlibc/resource
#include <stdio.h>
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header stdio.h not allowed
#include <stdlib.h>
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header stdlib.h not allowed
#include "string.h"
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header string.h not allowed
#include "stdatomic.h"
#include <stddef.h>
// Compiler provided headers should not throw warnings.