├── .github
└── workflows
│ ├── ubuntu-20.04.yml
│ └── ubuntu-22.04.yml
├── .gitignore
├── CMakeLists.txt
├── README.md
├── clang-diff
├── CMakeLists.txt
└── ClangDiff.cpp
├── dockerfiles
├── ubuntu-20.04.dockerfile
└── ubuntu-22.04.dockerfile
├── grayc
├── CMakeLists.txt
├── GlobList.cpp
├── GlobList.h
├── GrayC.cpp
├── GrayC.h
├── GrayCCheck.cpp
├── GrayCCheck.h
├── GrayCDiagnosticConsumer.cpp
├── GrayCDiagnosticConsumer.h
├── GrayCForceLinker.h
├── GrayCModule.cpp
├── GrayCModule.h
├── GrayCModuleRegistry.h
├── GrayCOptions.cpp
├── GrayCOptions.h
├── GrayCProfiling.cpp
├── GrayCProfiling.h
├── add_new_mutator.py
├── cmutation
│ ├── AssignmentExpressionMutator.cpp
│ ├── AssignmentExpressionMutator.h
│ ├── CMakeLists.txt
│ ├── CMutationModule.cpp
│ ├── ConditionalExpressionMutator.cpp
│ ├── ConditionalExpressionMutator.h
│ ├── DuplicateStatementMutator.cpp
│ ├── DuplicateStatementMutator.h
│ ├── JumpMutator.cpp
│ ├── JumpMutator.h
│ ├── UnaryOperatorCheck.cpp
│ └── UnaryOperatorCheck.h
├── cxxmutation
│ ├── CMakeLists.txt
│ ├── CXXMutationModule.cpp
│ ├── CXXUnaryOperatorCheck.cpp
│ └── CXXUnaryOperatorCheck.h
├── run_clang_diff.py
├── tool
│ ├── CMakeLists.txt
│ ├── GrayCMain.cpp
│ ├── GrayCMain.h
│ └── GrayCToolMain.cpp
└── utils
│ ├── CMakeLists.txt
│ ├── FixItHintUtils.cpp
│ ├── FixItHintUtils.h
│ ├── GrayCRandomManager.cpp
│ ├── GrayCRandomManager.h
│ ├── LexerUtils.cpp
│ └── LexerUtils.h
├── img
├── grayc-logo.png
└── grayc.png
└── scripts
├── LLVM-Test-suite-coverage
├── 1-get-llvm-testsuite-single-source.sh
├── 2-llvm-testsuite-reg-cov.sh
├── README.md
└── llvm-cov-sub-folders
│ ├── get-backend-cov.sh
│ ├── get-frontend-cov.sh
│ └── get-middle-end-cov.sh
├── README.md
├── coverage
├── 0-install-gcc-cov.sh
├── 0-install-llvm-cov-rt.sh
├── 0-install-llvm-cov.sh
├── 0-set-gcov-version.sh
├── 1-wrapper-get-coverage.sh
├── 4-cov-stat.sh
├── README.md
└── coverage-sub-scripts
│ ├── 0-prepare-folder.sh
│ ├── 2-compute-coverage_DIR_gfauto.sh
│ ├── 2-post-gcc-cov-run.sh
│ ├── 2-pre-gcc-cov-run.sh
│ ├── 3-gen-statistic-gcov-diff-tab_gfauto.sh
│ ├── CF3-1_LH_file.sh
│ └── README.md
├── crash-testing
├── .DS_Store
├── 0-prepare-folder.sh
├── 10-get-res.sh
├── 11-run-all.sh
├── 12-filter-errors.sh
├── 8-testing_all.sh
├── 9-run-all-wrapper.sh
├── Frama-C-zone
│ ├── config.h
│ ├── csmith.h
│ ├── csmith_minimal.h
│ ├── platform_generic.h
│ ├── random_inc.h
│ └── safe_math.h
└── skip_me.log
├── enhanCer
├── 1-1-prepare-folder.sh
├── 1-2-filter-compiled.sh
├── 1-3-transform.py
├── 1-main-enhanCer-option-1.sh
├── 2-main-coverage-diff.sh
├── 2-reduce2func-instCombine.sh
├── README.md
└── examples
│ ├── A_013d6729c7184ba4be35f0909cbbe8e9_2801_test251877490_copy.c
│ ├── A_20010116-1_copy.c
│ └── README.md
└── general
├── 1-download-gcc.sh
├── 1-download-llvm.sh
└── README.md
/.github/workflows/ubuntu-20.04.yml:
--------------------------------------------------------------------------------
1 | name: Build Ubuntu 20.04
2 |
3 | # Controls when the workflow will run
4 | on:
5 | # Triggers the workflow on push or pull request events but only for the out-of-tree branch; change once this becomes main
6 | push:
7 | branches: [ out-of-tree ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | build-1:
17 | # The type of runner that the job will run on
18 | runs-on: ubuntu-20.04
19 |
20 | # Steps represent a sequence of tasks that will be executed as part of the job
21 | steps:
22 | - name: Check Out Repo
23 | uses: actions/checkout@v2
24 |
25 | - name: Login to Docker Hub
26 | uses: docker/login-action@v1
27 | with:
28 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
29 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
30 |
31 | - name: Set up Docker Buildx
32 | id: buildx
33 | uses: docker/setup-buildx-action@v1
34 |
35 | - name: Build and push
36 | id: docker_build
37 | uses: docker/build-push-action@v2
38 | with:
39 | context: ./
40 | file: ./dockerfiles/ubuntu-20.04.dockerfile
41 | push: false
42 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/grayc:latest
43 |
44 | - name: Image digest
45 | run: echo ${{ steps.docker_build.outputs.digest }}
--------------------------------------------------------------------------------
/.github/workflows/ubuntu-22.04.yml:
--------------------------------------------------------------------------------
1 | name: Build Ubuntu 22.04
2 |
3 | # Controls when the workflow will run
4 | on:
5 | # Triggers the workflow on push or pull request events but only for the out-of-tree branch; change once this becomes main
6 | push:
7 | branches: [ out-of-tree ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | build-1:
17 | # The type of runner that the job will run on
18 | runs-on: ubuntu-22.04
19 |
20 | # Steps represent a sequence of tasks that will be executed as part of the job
21 | steps:
22 | - name: Check Out Repo
23 | uses: actions/checkout@v2
24 |
25 | - name: Login to Docker Hub
26 | uses: docker/login-action@v1
27 | with:
28 | username: ${{ secrets.DOCKER_HUB_USERNAME }}
29 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
30 |
31 | - name: Set up Docker Buildx
32 | id: buildx
33 | uses: docker/setup-buildx-action@v1
34 |
35 | - name: Build and push
36 | id: docker_build
37 | uses: docker/build-push-action@v2
38 | with:
39 | context: ./
40 | file: ./dockerfiles/ubuntu-22.04.dockerfile
41 | push: false
42 | tags: ${{ secrets.DOCKER_HUB_USERNAME }}/grayc:latest
43 |
44 | - name: Image digest
45 | run: echo ${{ steps.docker_build.outputs.digest }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/*
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13.4)
2 | project(GrayC)
3 |
4 | #===============================================================================
5 | # 0. GET CLANG INSTALLATION DIR
6 | #===============================================================================
7 | # In GrayC, `CT_Clang_INSTALL_DIR` is the key CMake variable - it points
8 | # to a Clang installation directory. We, however, use `LLVM_CONFIG_BINARY` as
9 | # our primary source of truth.
10 |
11 |
12 | set(LLVM_CONFIG_BINARY "llvm-config" CACHE STRING
13 | "The path to a llvm-config binary which is used to find llvm tooling to duplicate libraries"
14 | )
15 | execute_process(
16 | COMMAND ${LLVM_CONFIG_BINARY} --prefix
17 | OUTPUT_VARIABLE LLVM_DIR
18 | )
19 | string(REGEX REPLACE "\n+$" "" LLVM_DIR "${LLVM_DIR}")
20 | mark_as_advanced(LLVM_DIR)
21 |
22 | set(CT_Clang_INSTALL_DIR "${LLVM_DIR}" CACHE PATH
23 | "Clang installation directory"
24 | )
25 |
26 | #===============================================================================
27 | # 1. VERIFY CLANG INSTALLATION DIR
28 | #===============================================================================
29 | set(CT_LLVM_INCLUDE_DIR "${CT_Clang_INSTALL_DIR}/include/llvm")
30 | if(NOT EXISTS "${CT_LLVM_INCLUDE_DIR}")
31 | message(FATAL_ERROR
32 | " CT_Clang_INSTALL_DIR (${CT_LLVM_INCLUDE_DIR}) is invalid.")
33 | endif()
34 |
35 | set(CT_LLVM_CMAKE_FILE
36 | "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/ClangConfig.cmake")
37 | if(NOT EXISTS "${CT_LLVM_CMAKE_FILE}")
38 | message(FATAL_ERROR
39 | " CT_LLVM_CMAKE_FILE (${CT_LLVM_CMAKE_FILE}) is invalid.")
40 | endif()
41 |
42 |
43 |
44 | #===============================================================================
45 | # 2. LOAD CLANG CONFIGURATION
46 | # Extracted from:
47 | # http://llvm.org/docs/CMake.html#embedding-llvm-in-your-project
48 | #===============================================================================
49 | list(APPEND CMAKE_PREFIX_PATH "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/")
50 |
51 | find_package(Clang REQUIRED CONFIG)
52 |
53 | # Sanity check. As Clang does not expose e.g. `CLANG_VERSION_MAJOR` through
54 | # AddClang.cmake, we have to use LLVM_VERSION_MAJOR instead.
55 | # TODO: Revisit when next version is released.
56 | if(NOT "12" VERSION_EQUAL "${LLVM_VERSION_MAJOR}")
57 | message(FATAL_ERROR "Found LLVM ${LLVM_VERSION_MAJOR}, but need LLVM 12")
58 | endif()
59 |
60 | message(STATUS "Found Clang ${LLVM_PACKAGE_VERSION}")
61 | message(STATUS "Using ClangConfig.cmake in: ${CT_Clang_INSTALL_DIR}")
62 |
63 | message("CLANG STATUS:
64 | Includes (clang) ${CLANG_INCLUDE_DIRS}
65 | Includes (llvm) ${LLVM_INCLUDE_DIRS}"
66 | )
67 |
68 |
69 | # Set the LLVM and Clang header and library paths
70 | include_directories(SYSTEM "${LLVM_INCLUDE_DIRS};${CLANG_INCLUDE_DIRS}")
71 |
72 | #===============================================================================
73 | # 3. GrayC BUILD CONFIGURATION
74 | #===============================================================================
75 | # Use the same C++ standard as LLVM does
76 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "")
77 |
78 | # Build type
79 | if(NOT CMAKE_BUILD_TYPE)
80 | set(CMAKE_BUILD_TYPE Debug CACHE
81 | STRING "Build type (default Debug):" FORCE)
82 | endif()
83 |
84 | # Compiler flags
85 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -DDEBUG \
86 | -fdiagnostics-color=always")
87 |
88 | # LLVM/Clang is normally built without RTTI. Be consistent with that.
89 | if(NOT LLVM_ENABLE_RTTI)
90 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
91 | endif()
92 |
93 | # -fvisibility-inlines-hidden is set when building LLVM and on Darwin warnings
94 | # are triggered if GrayC is built without this flag (though otherwise it
95 | # builds fine). For consistency, add it here too.
96 | include(CheckCXXCompilerFlag)
97 | link_libraries(stdc++fs)
98 | # Set the build directories
99 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
100 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
101 |
102 |
103 | #===============================================================================
104 | # 4. ADD SUB-TARGETS
105 | # Doing this at the end so that all definitions and link/include paths are
106 | # available for the sub-projects.
107 | #===============================================================================
108 |
109 |
110 | # add_subdirectory(Utils)
111 |
112 | add_subdirectory(clang-diff)
113 | add_subdirectory(grayc)
114 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Mutation-based Testing Tool for C Family Compilers and Code Analyzers
4 | The GrayC approach involves using mutation-based fuzzing as a program generation technique (as described in our [ISSTA '23 paper](https://srg.doc.ic.ac.uk/files/papers/grayc-issta-23.pdf)) and then using the generated programs to test compilers and analysers. It is currently usable for generating programs across the C family i.e. `C`,`C++`,`Objective C` and `Objective C++`. For replication of the results presented in our [ISSTA '23 paper](https://srg.doc.ic.ac.uk/files/papers/grayc-issta-23.pdf), please checkout and use the tool from the [issta-2023](https://github.com/srg-imperial/GrayC/tree/issta-2023) branch.
5 |
6 |
7 | ## Features
8 | This is the revamped version of the one presented in our ISSTA '23 paper. It contains the following enhancements:
9 |
10 | 1. Write-Your-Own-Mutator
11 | 2. Remove dependence on `libfuzzer`
12 | 3. Interface to extend the tool for the entire C-family
13 | 4. Out-of-tree implementation of the tool
14 | 5. Rewrite of the codebase which now heavily relies on the LLVM/Clang framework
15 | 6. Better debugging due to reliance on ASTMatchers and Clang's internal debugging framework
16 | 7. Per mutation profiling mechanism for long fuzzing runs (courtesy LLVM's `clang-tidy`)
17 |
18 | ## Installation
19 |
20 | ```
21 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
22 | sudo apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main"
23 | sudo apt-get update
24 | sudo apt-get install -y llvm-12 llvm-12-dev llvm-12-tools clang-12 libclang-common-12-dev libclang-12-dev
25 |
26 | This builds both LLVM and Clang on Ubuntu
27 |
28 | git clone https://github.com/srg-imperial/GrayC.git
29 | cd GrayC
30 | mkdir build
31 | cd build
32 | cmake -GNinja -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 -DLLVM_CONFIG_BINARY=llvm-config-12 ../
33 | ninja
34 | ```
35 |
36 | Check the installation in the build directory as
37 |
38 | ```
39 | bin/grayc --list-mutations
40 | ```
41 |
42 | which should produce the following output
43 | ```
44 | Enabled mutations:
45 | cmutation-assignment-expression-mutator
46 | cmutation-conditional-expression-mutator
47 | cmutation-duplicate-statement-mutator
48 | cmutation-jump-mutator
49 | cmutation-unary
50 | ```
51 | ## Example
52 |
53 | ```
54 | cd build
55 | echo "int main(){int a=0; ++a;return 0;}" > b.cpp
56 | bin/grayc -mutations="-*,cmutation-unary" --apply-mutation b.cpp --
57 | ```
58 |
59 | This should result in the following program
60 | ```
61 | int main()
62 | {
63 | int a = 0;
64 | --a;
65 | return 0;
66 | }
67 | ```
68 |
69 | ## GrayC: Write-Your-Own-Mutator (WYOM)
70 | The inspiration behind this functionality was the extensible framework introduced by `clang-tidy`. More technically, the `WYOM` functionality is realised by making use of the `add_new_mutator.py` script, which automatically updates the various files while providing the boilerplate code to write a new mutation.
71 |
72 | ### WYOM Example Usage
73 | Let's see the case for development of a simple mutator that converts a `+` to a `-`. For now, we would like the mutator to work on `C` programs. We will start off by calling the `add_new_mutator.py`, which sits in the `grayc` folder, as follows:
74 |
75 | ```
76 | ./add_new_mutator.py cmutation binary-operator-mutator
77 | ```
78 | The script does the following tasks:
79 |
80 | 1. Registers the `binary-operator-mutator` within the `cmutation` module
81 | 2. Provides `BinaryOperatorMutator.cpp` and `BinaryOperatorMutator.h` files
82 | 3. Provides a small implementation of the `BinaryOperatorMutator::registerMatchers` and the `BinaryOperatorMutator::check` containing a sample matcher and the correponsing callback function.
83 |
84 | The user is then expected to refine the `ASTMatcher` in the `BinaryOperatorMutator::registerMatchers` function and the callback code in the `BinaryOperatorMutator::check` function.
85 |
86 | Once refined, the check can be called on a sample file in the aforementioned manner.
87 |
88 | GrayC's mutators are divided into modules, based on the language that it targets. `cmutation` is the most general module corresponding to mutators applicable for the entire `C` family , while `cxxmutation` houses the `C++` specific mutators. We aim to extend this by having modules for Objective C and Objective C++ in the near future.
89 |
90 |
91 |
--------------------------------------------------------------------------------
/clang-diff/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.3)
2 | project(GrayC)
3 |
4 | #===============================================================================
5 | # 1. LOAD LLVM CONFIGURATION
6 | #===============================================================================
7 | # Set this to a valid LLVM installation dir
8 | set(CT_Clang_INSTALL_DIR "" CACHE PATH "LLVM installation directory")
9 |
10 | # Add the location of ClangConfig.cmake to CMake search paths (so that
11 | # find_package can locate it)
12 | list(APPEND CMAKE_PREFIX_PATH "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/")
13 |
14 | find_package(Clang REQUIRED CONFIG)
15 |
16 | # HelloWorld includes headers from LLVM and Clang - update the include paths
17 | # accordingly
18 | include_directories(SYSTEM "${LLVM_INCLUDE_DIRS};${CLANG_INCLUDE_DIRS}")
19 |
20 | #===============================================================================
21 | # 2. PRODUCT-PROGRAM BUILD CONFIGURATION
22 | #===============================================================================
23 | # Use the same C++ standard as LLVM does
24 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "")
25 |
26 | # LLVM is normally built without RTTI. Be consistent with that.
27 | if(NOT LLVM_ENABLE_RTTI)
28 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
29 | endif()
30 |
31 | #===============================================================================
32 | # 3. ADD THE TARGET
33 | #===============================================================================
34 | add_executable(clang-diff ClangDiff.cpp)
35 | target_link_libraries(clang-diff
36 | PRIVATE
37 | clangBasic
38 | clangFrontend
39 | clangSerialization
40 | clangTooling
41 | clangToolingASTDiff
42 | )
43 |
--------------------------------------------------------------------------------
/dockerfiles/ubuntu-20.04.dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/library/ubuntu:20.04 AS base
2 | ARG DEBIAN_FRONTEND=noninteractive
3 |
4 | RUN apt-get update && \
5 | apt-get install -y \
6 | autoconf \
7 | autopoint \
8 | gengetopt \
9 | build-essential \
10 | git \
11 | libtool \
12 | ninja-build \
13 | python3 \
14 | python3-pip \
15 | software-properties-common \
16 | wget \
17 | vim \
18 | pkg-config \
19 | make \
20 | bison \
21 | texinfo \
22 | help2man \
23 | gtk-doc-tools \
24 | valgrind \
25 | abigail-tools \
26 | cmake \
27 | && rm -rf /var/lib/apt/lists/*
28 |
29 | RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \
30 | && apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" \
31 | && apt-get update \
32 | && apt-get install -y llvm-12 llvm-12-dev llvm-12-tools clang-12 clang-format-12 clang-tidy-12 libclang-common-12-dev libclang-12-dev
33 |
34 |
35 |
36 | COPY ./ /GrayC/
37 | WORKDIR /GrayC
38 |
39 | ARG JOBS=$(nproc)
40 |
41 | RUN \
42 | mkdir build \
43 | && cd build \
44 | && cmake -GNinja \
45 | -DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=gold' \
46 | -DCMAKE_C_FLAGS='-Werror' \
47 | -DCMAKE_CXX_FLAGS='-Werror' \
48 | -DCMAKE_C_COMPILER=clang-12 \
49 | -DCMAKE_CXX_COMPILER=clang++-12 \
50 | -DLLVM_CONFIG_BINARY=$(which llvm-config-12) \
51 | ../ \
52 | && sh -c "ninja -j${JOBS}"
53 |
--------------------------------------------------------------------------------
/dockerfiles/ubuntu-22.04.dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/library/ubuntu:22.04 AS base
2 | ARG DEBIAN_FRONTEND=noninteractive
3 |
4 | RUN apt-get update && \
5 | apt-get install -y \
6 | autoconf \
7 | autopoint \
8 | gengetopt \
9 | build-essential \
10 | git \
11 | libtool \
12 | ninja-build \
13 | python3 \
14 | python3-pip \
15 | software-properties-common \
16 | wget \
17 | vim \
18 | pkg-config \
19 | make \
20 | bison \
21 | texinfo \
22 | help2man \
23 | gtk-doc-tools \
24 | valgrind \
25 | abigail-tools \
26 | cmake \
27 | && rm -rf /var/lib/apt/lists/*
28 |
29 | RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \
30 | && apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main" \
31 | && apt-get update \
32 | && apt-get install -y llvm-12 llvm-12-dev llvm-12-tools clang-12 clang-format-12 clang-tidy-12 libclang-common-12-dev libclang-12-dev
33 |
34 |
35 |
36 | COPY ./ /GrayC/
37 | WORKDIR /GrayC
38 |
39 | ARG JOBS=$(nproc)
40 |
41 | RUN \
42 | mkdir build \
43 | && cd build \
44 | && cmake -GNinja \
45 | -DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=gold' \
46 | -DCMAKE_C_FLAGS='-Werror' \
47 | -DCMAKE_CXX_FLAGS='-Werror' \
48 | -DCMAKE_C_COMPILER=clang-12 \
49 | -DCMAKE_CXX_COMPILER=clang++-12 \
50 | -DLLVM_CONFIG_BINARY=$(which llvm-config-12) \
51 | ../ \
52 | && sh -c "ninja -j${JOBS}"
53 |
--------------------------------------------------------------------------------
/grayc/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.3)
2 | project(grayc-cd)
3 |
4 | #===============================================================================
5 | # 1. LOAD LLVM CONFIGURATION
6 | #===============================================================================
7 | # Set this to a valid LLVM installation dir
8 | set(CT_Clang_INSTALL_DIR "" CACHE PATH "LLVM installation directory")
9 |
10 | # Add the location of ClangConfig.cmake to CMake search paths (so that
11 | # find_package can locate it)
12 | list(APPEND CMAKE_PREFIX_PATH "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/")
13 |
14 | find_package(Clang REQUIRED CONFIG)
15 |
16 | # HelloWorld includes headers from LLVM and Clang - update the include paths
17 | # accordingly
18 | include_directories(SYSTEM "${LLVM_INCLUDE_DIRS};${CLANG_INCLUDE_DIRS}")
19 |
20 | #===============================================================================
21 | # 2. GrayC BUILD CONFIGURATION
22 | #===============================================================================
23 | # Use the same C++ standard as LLVM does
24 | set(CMAKE_CXX_STANDARD 17 CACHE STRING "")
25 |
26 | # LLVM is normally built without RTTI. Be consistent with that.
27 | if(NOT LLVM_ENABLE_RTTI)
28 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
29 | endif()
30 |
31 | add_library(GrayC
32 | GrayC.cpp
33 | GrayCCheck.cpp
34 | GrayCModule.cpp
35 | GrayCDiagnosticConsumer.cpp
36 | GrayCOptions.cpp
37 | GrayCProfiling.cpp
38 | GlobList.cpp
39 | )
40 |
41 | target_link_libraries(GrayC
42 | PRIVATE
43 | clangAnalysis
44 | clangAST
45 | clangASTMatchers
46 | clangBasic
47 | clangFormat
48 | clangFrontend
49 | clangLex
50 | clangRewrite
51 | clangSema
52 | clangSerialization
53 | clangTooling
54 | clangToolingCore
55 | )
56 |
57 | add_subdirectory(tool)
58 | add_subdirectory(utils)
59 | add_subdirectory(cmutation)
60 | add_subdirectory(cxxmutation)
61 |
--------------------------------------------------------------------------------
/grayc/GlobList.cpp:
--------------------------------------------------------------------------------
1 | //===--- grayc/GlobList.cpp ------------------------------===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #include "GlobList.h"
10 | #include "llvm/ADT/SmallString.h"
11 |
12 | using namespace clang;
13 | using namespace grayc;
14 |
15 | // Returns true if GlobList starts with the negative indicator ('-'), removes it
16 | // from the GlobList.
17 | static bool ConsumeNegativeIndicator(StringRef &GlobList) {
18 | GlobList = GlobList.trim(" \r\n");
19 | if (GlobList.startswith("-")) {
20 | GlobList = GlobList.substr(1);
21 | return true;
22 | }
23 | return false;
24 | }
25 |
26 | // Converts first glob from the comma-separated list of globs to Regex and
27 | // removes it and the trailing comma from the GlobList.
28 | static llvm::Regex ConsumeGlob(StringRef &GlobList) {
29 | StringRef UntrimmedGlob = GlobList.substr(0, GlobList.find(','));
30 | StringRef Glob = UntrimmedGlob.trim(' ');
31 | GlobList = GlobList.substr(UntrimmedGlob.size() + 1);
32 | SmallString<128> RegexText("^");
33 | StringRef MetaChars("()^$|*+?.[]\\{}");
34 | for (char C : Glob) {
35 | if (C == '*')
36 | RegexText.push_back('.');
37 | else if (MetaChars.find(C) != StringRef::npos)
38 | RegexText.push_back('\\');
39 | RegexText.push_back(C);
40 | }
41 | RegexText.push_back('$');
42 | return llvm::Regex(RegexText);
43 | }
44 |
45 | GlobList::GlobList(StringRef Globs) {
46 | do {
47 | GlobListItem Item;
48 | Item.IsPositive = !ConsumeNegativeIndicator(Globs);
49 | Item.Regex = ConsumeGlob(Globs);
50 | Items.push_back(std::move(Item));
51 | } while (!Globs.empty());
52 | }
53 |
54 | bool GlobList::contains(StringRef S) {
55 | bool Contains = false;
56 | for (const GlobListItem &Item : Items) {
57 | if (Item.Regex.match(S))
58 | Contains = Item.IsPositive;
59 | }
60 | return Contains;
61 | }
62 |
--------------------------------------------------------------------------------
/grayc/GlobList.h:
--------------------------------------------------------------------------------
1 | //===--- GlobList.h ---------------------------------------------*- C++ -*-===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #ifndef GRAYC_GLOBLIST_H
10 | #define GRAYC_GLOBLIST_H
11 |
12 | #include "clang/Basic/LLVM.h"
13 | #include "llvm/ADT/StringRef.h"
14 | #include "llvm/Support/Regex.h"
15 | #include
16 |
17 | namespace clang {
18 | namespace grayc {
19 |
20 | /// Read-only set of strings represented as a list of positive and negative
21 | /// globs.
22 | ///
23 | /// Positive globs add all matched strings to the set, negative globs remove
24 | /// them in the order of appearance in the list.
25 | class GlobList {
26 | public:
27 | /// \p Globs is a comma-separated list of globs (only the '*' metacharacter is
28 | /// supported) with an optional '-' prefix to denote exclusion.
29 | ///
30 | /// An empty \p Globs string is interpreted as one glob that matches an empty
31 | /// string.
32 | GlobList(StringRef Globs);
33 |
34 | /// Returns \c true if the pattern matches \p S. The result is the last
35 | /// matching glob's Positive flag.
36 | bool contains(StringRef S);
37 |
38 | private:
39 |
40 | struct GlobListItem {
41 | bool IsPositive;
42 | mutable llvm::Regex Regex;
43 | };
44 | std::vector Items;
45 | };
46 |
47 | } // end namespace grayc
48 | } // end namespace clang
49 |
50 | #endif // GRAYC_GLOBLIST_H
51 |
--------------------------------------------------------------------------------
/grayc/GrayC.h:
--------------------------------------------------------------------------------
1 | //===--- GrayC.h - GrayC -------------------------------*- C++ -*-===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #ifndef GRAYC_GRAYC_H
10 | #define GRAYC_GRAYC_H
11 |
12 | #include "GrayCDiagnosticConsumer.h"
13 | #include "GrayCOptions.h"
14 | #include
15 | #include
16 |
17 | namespace llvm {
18 | class raw_ostream;
19 | } // namespace llvm
20 |
21 | namespace clang {
22 |
23 | class ASTConsumer;
24 | class CompilerInstance;
25 | namespace tooling {
26 | class CompilationDatabase;
27 | } // namespace tooling
28 |
29 | namespace grayc {
30 |
31 | class GrayCCheckFactories;
32 |
33 | class GrayCASTConsumerFactory {
34 | public:
35 | GrayCASTConsumerFactory(
36 | GrayCContext &Context,
37 | IntrusiveRefCntPtr OverlayFS = nullptr);
38 |
39 | /// Returns an ASTConsumer that runs the specified GrayC checks.
40 | std::unique_ptr
41 | CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File);
42 |
43 | /// Get the list of enabled checks.
44 | std::vector getCheckNames();
45 |
46 | /// Get the union of options from all checks.
47 | GrayCOptions::OptionMap getCheckOptions();
48 |
49 | private:
50 | GrayCContext &Context;
51 | IntrusiveRefCntPtr OverlayFS;
52 | std::unique_ptr CheckFactories;
53 | };
54 |
55 | /// Fills the list of check names that are enabled when the provided
56 | /// filters are applied.
57 | std::vector getCheckNames(const GrayCOptions &Options,
58 | bool AllowEnablingAnalyzerAlphaCheckers);
59 |
60 | /// Returns the effective check-specific options.
61 | ///
62 | /// The method configures GrayC with the specified \p Options and collects
63 | /// effective options from all created checks. The returned set of options
64 | /// includes default check-specific options for all keys not overridden by \p
65 | /// Options.
66 | GrayCOptions::OptionMap
67 | getCheckOptions(const GrayCOptions &Options,
68 | bool AllowEnablingAnalyzerAlphaCheckers);
69 |
70 | /// Run a set of GrayC checks on a set of files.
71 | ///
72 | /// \param EnableCheckProfile If provided, it enables check profile collection
73 | /// in MatchFinder, and will contain the result of the profile.
74 | /// \param StoreCheckProfile If provided, and EnableCheckProfile is true,
75 | /// the profile will not be output to stderr, but will instead be stored
76 | /// as a JSON file in the specified directory.
77 | std::vector
78 | runGrayC(clang::grayc::GrayCContext &Context,
79 | const tooling::CompilationDatabase &Compilations,
80 | ArrayRef InputFiles,
81 | llvm::IntrusiveRefCntPtr BaseFS,
82 | bool EnableCheckProfile = false,
83 | llvm::StringRef StoreCheckProfile = StringRef());
84 |
85 | // FIXME: This interface will need to be significantly extended to be useful.
86 | // FIXME: Implement confidence levels for displaying/fixing errors.
87 | //
88 | /// Displays the found \p Errors to the users. If \p Fix is true, \p
89 | /// Errors containing fixes are automatically applied and reformatted. If no
90 | /// clang-format configuration file is found, the given \P FormatStyle is used.
91 | void handleErrors(llvm::ArrayRef Errors,
92 | GrayCContext &Context, bool Fix,
93 | unsigned &WarningsAsErrorsCount,
94 | llvm::IntrusiveRefCntPtr BaseFS);
95 |
96 | /// Serializes replacements into YAML and writes them to the specified
97 | /// output stream.
98 | void exportReplacements(StringRef MainFilePath,
99 | const std::vector &Errors,
100 | raw_ostream &OS);
101 |
102 | } // end namespace grayc
103 | } // end namespace clang
104 |
105 | #endif // GRAYC_GRAYC_H
106 |
--------------------------------------------------------------------------------
/grayc/GrayCForceLinker.h:
--------------------------------------------------------------------------------
1 | //===- GrayCForceLinker.h - grayc --------------------------------===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #ifndef GRAYC_GRAYCFORCELINKER_H
10 | #define GRAYC_GRAYCFORCELINKER_H
11 |
12 | #include "clang/Config/config.h"
13 | #include "llvm/Support/Compiler.h"
14 |
15 | namespace clang {
16 | namespace grayc {
17 |
18 | // This anchor is used to force the linker to link the CMutatorModule.
19 | extern volatile int CMutatorModuleAnchorSource;
20 | static int LLVM_ATTRIBUTE_UNUSED CMutatorModuleAnchorDestination =
21 | CMutatorModuleAnchorSource;
22 |
23 | // This anchor is used to force the linker to link the CXXMutatorModule.
24 | extern volatile int CXXMutatorModuleAnchorSource;
25 | static int LLVM_ATTRIBUTE_UNUSED CXXMutatorModuleAnchorDestination =
26 | CXXMutatorModuleAnchorSource;
27 |
28 | } // namespace grayc
29 | } // namespace clang
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/grayc/GrayCModule.cpp:
--------------------------------------------------------------------------------
1 | //===--- graycGrayCModule.cpp - GrayC tool -----===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 | ///
9 | /// \file Implements classes required to build grayc modules.
10 | ///
11 | //===----------------------------------------------------------------------===//
12 |
13 | #include "GrayCModule.h"
14 | #include "GrayCCheck.h"
15 |
16 | namespace clang {
17 | namespace grayc {
18 |
19 | void GrayCCheckFactories::registerCheckFactory(StringRef Name,
20 | CheckFactory Factory) {
21 | Factories[std::string(Name)] = std::move(Factory);
22 | }
23 |
24 | std::vector>
25 | GrayCCheckFactories::createChecks(GrayCContext *Context) {
26 | std::vector> Checks;
27 | for (const auto &Factory : Factories) {
28 | if (Context->isCheckEnabled(Factory.first))
29 | Checks.emplace_back(Factory.second(Factory.first, Context));
30 | }
31 | return Checks;
32 | }
33 |
34 | GrayCOptions GrayCModule::getModuleOptions() {
35 | return GrayCOptions();
36 | }
37 |
38 | } // namespace grayc
39 | } // namespace clang
40 |
--------------------------------------------------------------------------------
/grayc/GrayCModule.h:
--------------------------------------------------------------------------------
1 | //===--- GrayCModule.h - grayc -------------------------*- C++ -*-===//
2 | //
3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 | // See https://llvm.org/LICENSE.txt for license information.
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 | //
7 | //===----------------------------------------------------------------------===//
8 |
9 | #ifndef GRAYC_GrayCModule_H
10 | #define GRAYC_GrayCModule_H
11 |
12 | #include "GrayCOptions.h"
13 | #include "llvm/ADT/StringMap.h"
14 | #include "llvm/ADT/StringRef.h"
15 | #include
16 | #include