├── .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 17 | #include 18 | #include 19 | 20 | namespace clang { 21 | namespace grayc { 22 | 23 | class GrayCCheck; 24 | class GrayCContext; 25 | 26 | /// A collection of \c GrayCCheckFactory instances. 27 | /// 28 | /// All grayc modules register their check factories with an instance of 29 | /// this object. 30 | class GrayCCheckFactories { 31 | public: 32 | using CheckFactory = std::function( 33 | llvm::StringRef Name, GrayCContext *Context)>; 34 | 35 | /// Registers check \p Factory with name \p Name. 36 | /// 37 | /// For all checks that have default constructors, use \c registerCheck. 38 | void registerCheckFactory(llvm::StringRef Name, CheckFactory Factory); 39 | 40 | /// Registers the \c CheckType with the name \p Name. 41 | /// 42 | /// This method should be used for all \c GrayCChecks that don't require 43 | /// constructor parameters. 44 | /// 45 | /// For example, if have a grayc check like: 46 | /// \code 47 | /// class MygraycCheck : public GrayCCheck { 48 | /// void registerMatchers(ast_matchers::MatchFinder *Finder) override { 49 | /// .. 50 | /// } 51 | /// }; 52 | /// \endcode 53 | /// you can register it with: 54 | /// \code 55 | /// class MyModule : public GrayCModule { 56 | /// void addCheckFactories(GrayCCheckFactories &Factories) override { 57 | /// Factories.registerCheck("myproject-my-check"); 58 | /// } 59 | /// }; 60 | /// \endcode 61 | template void registerCheck(llvm::StringRef CheckName) { 62 | registerCheckFactory(CheckName, 63 | [](llvm::StringRef Name, GrayCContext *Context) { 64 | return std::make_unique(Name, Context); 65 | }); 66 | } 67 | 68 | /// Create instances of checks that are enabled. 69 | std::vector> 70 | createChecks(GrayCContext *Context); 71 | 72 | typedef std::map FactoryMap; 73 | FactoryMap::const_iterator begin() const { return Factories.begin(); } 74 | FactoryMap::const_iterator end() const { return Factories.end(); } 75 | bool empty() const { return Factories.empty(); } 76 | 77 | private: 78 | FactoryMap Factories; 79 | }; 80 | 81 | /// A grayc module groups a number of \c GrayCChecks and gives 82 | /// them a prefixed name. 83 | class GrayCModule { 84 | public: 85 | virtual ~GrayCModule() {} 86 | 87 | /// Implement this function in order to register all \c CheckFactories 88 | /// belonging to this module. 89 | virtual void addCheckFactories(GrayCCheckFactories &CheckFactories) = 0; 90 | 91 | /// Gets default options for checks defined in this module. 92 | virtual GrayCOptions getModuleOptions(); 93 | }; 94 | 95 | } // end namespace grayc 96 | } // end namespace clang 97 | 98 | #endif // GRAYC_GrayCModule_H 99 | -------------------------------------------------------------------------------- /grayc/GrayCModuleRegistry.h: -------------------------------------------------------------------------------- 1 | //===--- GrayCModuleRegistry.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_GrayCModuleRegistry_H 10 | #define GRAYC_GrayCModuleRegistry_H 11 | 12 | #include "GrayCModule.h" 13 | #include "llvm/Support/Registry.h" 14 | 15 | namespace clang { 16 | namespace grayc { 17 | 18 | typedef llvm::Registry GrayCModuleRegistry; 19 | 20 | } // end namespace grayc 21 | } // end namespace clang 22 | 23 | #endif // GRAYC_GrayCModuleRegistry_H 24 | -------------------------------------------------------------------------------- /grayc/GrayCProfiling.cpp: -------------------------------------------------------------------------------- 1 | //===--- GrayCProfiling.cpp - 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 | #include "GrayCProfiling.h" 10 | #include "llvm/ADT/STLExtras.h" 11 | #include "llvm/ADT/SmallString.h" 12 | #include "llvm/Support/FileSystem.h" 13 | #include "llvm/Support/Path.h" 14 | #include "llvm/Support/YAMLTraits.h" 15 | #include "llvm/Support/raw_ostream.h" 16 | #include 17 | #include 18 | 19 | #define DEBUG_TYPE "grayc-profiling" 20 | 21 | namespace clang { 22 | namespace grayc { 23 | 24 | GrayCProfiling::StorageParams::StorageParams(llvm::StringRef ProfilePrefix, 25 | llvm::StringRef SourceFile) 26 | : Timestamp(std::chrono::system_clock::now()), SourceFilename(SourceFile) { 27 | llvm::SmallString<32> TimestampStr; 28 | llvm::raw_svector_ostream OS(TimestampStr); 29 | llvm::format_provider::format(Timestamp, OS, 30 | "%Y%m%d%H%M%S%N"); 31 | 32 | llvm::SmallString<256> FinalPrefix(ProfilePrefix); 33 | llvm::sys::path::append(FinalPrefix, TimestampStr); 34 | 35 | // So the full output name is: /ProfilePrefix/timestamp-inputfilename.json 36 | StoreFilename = llvm::Twine(FinalPrefix + "-" + 37 | llvm::sys::path::filename(SourceFile) + ".json") 38 | .str(); 39 | } 40 | 41 | void GrayCProfiling::printUserFriendlyTable(llvm::raw_ostream &OS) { 42 | TG->print(OS); 43 | OS.flush(); 44 | } 45 | 46 | void GrayCProfiling::printAsJSON(llvm::raw_ostream &OS) { 47 | OS << "{\n"; 48 | OS << "\"file\": \"" << Storage->SourceFilename << "\",\n"; 49 | OS << "\"timestamp\": \"" << Storage->Timestamp << "\",\n"; 50 | OS << "\"profile\": {\n"; 51 | TG->printJSONValues(OS, ""); 52 | OS << "\n}\n"; 53 | OS << "}\n"; 54 | OS.flush(); 55 | } 56 | 57 | void GrayCProfiling::storeProfileData() { 58 | assert(Storage.hasValue() && "We should have a filename."); 59 | 60 | llvm::SmallString<256> OutputDirectory(Storage->StoreFilename); 61 | llvm::sys::path::remove_filename(OutputDirectory); 62 | if (std::error_code EC = llvm::sys::fs::create_directories(OutputDirectory)) { 63 | llvm::errs() << "Unable to create output directory '" << OutputDirectory 64 | << "': " << EC.message() << "\n"; 65 | return; 66 | } 67 | 68 | std::error_code EC; 69 | llvm::raw_fd_ostream OS(Storage->StoreFilename, EC, llvm::sys::fs::OF_None); 70 | if (EC) { 71 | llvm::errs() << "Error opening output file '" << Storage->StoreFilename 72 | << "': " << EC.message() << "\n"; 73 | return; 74 | } 75 | 76 | printAsJSON(OS); 77 | } 78 | 79 | GrayCProfiling::GrayCProfiling(llvm::Optional Storage) 80 | : Storage(std::move(Storage)) {} 81 | 82 | GrayCProfiling::~GrayCProfiling() { 83 | TG.emplace("grayc", "GrayC checks profiling", Records); 84 | 85 | if (!Storage.hasValue()) 86 | printUserFriendlyTable(llvm::errs()); 87 | else 88 | storeProfileData(); 89 | } 90 | 91 | } // namespace grayc 92 | } // namespace clang 93 | -------------------------------------------------------------------------------- /grayc/GrayCProfiling.h: -------------------------------------------------------------------------------- 1 | //===--- GrayCProfiling.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_GrayCProfiling_H 10 | #define GRAYC_GrayCProfiling_H 11 | 12 | #include "llvm/ADT/Optional.h" 13 | #include "llvm/ADT/StringMap.h" 14 | #include "llvm/Support/Chrono.h" 15 | #include "llvm/Support/Timer.h" 16 | #include 17 | 18 | namespace llvm { 19 | class raw_ostream; 20 | } // namespace llvm 21 | 22 | namespace clang { 23 | namespace grayc { 24 | 25 | class GrayCProfiling { 26 | public: 27 | struct StorageParams { 28 | llvm::sys::TimePoint<> Timestamp; 29 | std::string SourceFilename; 30 | std::string StoreFilename; 31 | 32 | StorageParams() = default; 33 | 34 | StorageParams(llvm::StringRef ProfilePrefix, llvm::StringRef SourceFile); 35 | }; 36 | 37 | private: 38 | llvm::Optional TG; 39 | 40 | llvm::Optional Storage; 41 | 42 | void printUserFriendlyTable(llvm::raw_ostream &OS); 43 | void printAsJSON(llvm::raw_ostream &OS); 44 | 45 | void storeProfileData(); 46 | 47 | public: 48 | llvm::StringMap Records; 49 | 50 | GrayCProfiling() = default; 51 | 52 | GrayCProfiling(llvm::Optional Storage); 53 | 54 | ~GrayCProfiling(); 55 | }; 56 | 57 | } // end namespace grayc 58 | } // end namespace clang 59 | 60 | #endif // GRAYC_GrayCProfiling_H 61 | -------------------------------------------------------------------------------- /grayc/cmutation/AssignmentExpressionMutator.cpp: -------------------------------------------------------------------------------- 1 | //===--- AssignmentExpressionMutator.cpp - 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 | #include "AssignmentExpressionMutator.h" 10 | #include "../utils/GrayCRandomManager.h" 11 | #include "clang/AST/ASTContext.h" 12 | #include "clang/ASTMatchers/ASTMatchFinder.h" 13 | #include "clang/ASTMatchers/ASTMatchers.h" 14 | #include "clang/Lex/Lexer.h" 15 | 16 | using namespace clang::ast_matchers; 17 | 18 | namespace clang 19 | { 20 | namespace grayc 21 | { 22 | namespace cmutation 23 | { 24 | 25 | void AssignmentExpressionMutator::registerMatchers(MatchFinder *Finder) 26 | { 27 | Finder->addMatcher(binaryOperator(isAssignmentOperator()).bind("assignment"), this); 28 | } 29 | 30 | void AssignmentExpressionMutator::check(const MatchFinder::MatchResult &Result) 31 | { 32 | 33 | const SourceManager &SM = *Result.SourceManager; 34 | const ASTContext *Context = Result.Context; 35 | if (auto B = Result.Nodes.getNodeAs("assignment")) 36 | { 37 | mutateAssignment(Result, B, B->getBeginLoc(), B->getEndLoc()); 38 | } 39 | else 40 | { 41 | llvm_unreachable("Invalid match"); 42 | } 43 | } 44 | 45 | bool AssignmentExpressionMutator::mutateAssignment( 46 | const MatchFinder::MatchResult &Result, const BinaryOperator *B, 47 | SourceLocation InitialLoc, SourceLocation EndLocHint) 48 | { 49 | GrayCRandomManager::CreateInstance(Seed.getValue(), 65000); 50 | if (!InitialLoc.isValid()){ 51 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 52 | return false; 53 | } 54 | const SourceManager &SM = *Result.SourceManager; 55 | const ASTContext *Context = Result.Context; 56 | 57 | // Treat macros. 58 | CharSourceRange FileRange = Lexer::makeFileCharRange( 59 | CharSourceRange::getTokenRange(B->getSourceRange()), SM, 60 | Context->getLangOpts()); 61 | if (FileRange.isInvalid()){ 62 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 63 | return false; 64 | } 65 | InitialLoc = Lexer::makeFileCharRange( 66 | CharSourceRange::getCharRange(InitialLoc, B->getBeginLoc()), 67 | SM, Context->getLangOpts()) 68 | .getBegin(); 69 | 70 | if (InitialLoc.isInvalid()){ 71 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 72 | return false; 73 | } 74 | InitialLoc = B->getRHS()->getBeginLoc(); 75 | assert(InitialLoc.isValid()); 76 | assert(EndLocHint.isValid()); 77 | auto Diag = diag(InitialLoc, "found binary assignment statement to mutate"); 78 | if (isa(B->getRHS())) 79 | { 80 | llvm::WithColor::remark() << "Found RHS expression: " << B->getEndLoc().printToString(SM) << "\n"; 81 | buildExpressionVector(Result, expressions, dyn_cast(B->getRHS())); 82 | } 83 | else 84 | { 85 | auto Diag = diag(InitialLoc, "RHS does not contain subexpressions"); 86 | } 87 | // FIXIT: (Last-11) as, without extra checks, we can't use assignment operators without ensuring that the lvalue is modifiable. 88 | BinaryOperatorKind BK = BinaryOperatorKind(GrayCRandomManager::GetInstance()->rnd_dice(Last - 11)); 89 | // FIXIT: Avoid using pointer-to-member operators 90 | llvm::Twine SelectedBinaryOperator(BinaryOperatorStrings[1 + BK]); 91 | llvm::WithColor::remark() << "Selected binary operator: " << SelectedBinaryOperator.str() << "\n"; 92 | llvm::WithColor::remark() << "Number of subexpressions: " << expressions.size() << "\n"; 93 | 94 | assert(expressions.size() > 0 && "No sub-expressions collected!!"); 95 | llvm::Twine NewRHS(expressions[GrayCRandomManager::GetInstance()->rnd_dice(expressions.size()) % expressions.size()]); 96 | llvm::Twine NewLHS(expressions[(GrayCRandomManager::GetInstance()->rnd_dice(expressions.size())+1) % expressions.size()]); 97 | llvm::Twine MutatedAssignment(NewLHS + SelectedBinaryOperator + NewRHS); 98 | 99 | llvm::WithColor::remark() << "Expression built : " << MutatedAssignment.str() << "\n"; 100 | 101 | Diag << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(InitialLoc, EndLocHint), MutatedAssignment.str()); 102 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 103 | return true; 104 | } 105 | void AssignmentExpressionMutator::buildExpressionVector(const MatchFinder::MatchResult &Result, llvm::SmallVector &expressions, const Expr *E) 106 | { 107 | if (!isa(E)) 108 | { 109 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 110 | return; 111 | } 112 | else 113 | { 114 | const SourceManager &SM = *Result.SourceManager; 115 | const ASTContext *Context = Result.Context; 116 | const BinaryOperator *BO = dyn_cast(E); 117 | Expr *LHS = BO->getLHS()->IgnoreParens()->IgnoreImpCasts(); 118 | Expr *RHS = BO->getRHS()->IgnoreParens()->IgnoreImpCasts(); 119 | SourceRange LHSRange(LHS->getBeginLoc(), LHS->getEndLoc()); 120 | SourceRange RHSRange(RHS->getBeginLoc(), RHS->getEndLoc()); 121 | expressions.push_back(Lexer::getSourceText(CharSourceRange::getTokenRange(LHSRange), SM, Context->getLangOpts())); 122 | expressions.push_back(Lexer::getSourceText(CharSourceRange::getTokenRange(RHSRange), SM, Context->getLangOpts())); 123 | llvm::WithColor::remark() << "Number of expressions collected: " << expressions.size() << "\n"; 124 | llvm::WithColor::remark() << "Collected subexpressions: " << Lexer::getSourceText(CharSourceRange::getTokenRange(LHSRange), SM, Context->getLangOpts()) << "," << Lexer::getSourceText(CharSourceRange::getTokenRange(RHSRange), SM, Context->getLangOpts()) << "\n"; 125 | 126 | if (isa(LHS)) 127 | { 128 | buildExpressionVector(Result, expressions, dyn_cast(LHS)); 129 | } 130 | if (isa(RHS)) 131 | { 132 | buildExpressionVector(Result, expressions, dyn_cast(RHS)); 133 | } 134 | } 135 | } 136 | 137 | } // namespace cmutation 138 | } // namespace grayc 139 | } // namespace clang 140 | -------------------------------------------------------------------------------- /grayc/cmutation/AssignmentExpressionMutator.h: -------------------------------------------------------------------------------- 1 | //===--- AssignmentExpressionMutator.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_ASSIGNMENTEXPRESSIONMUTATOR_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_ASSIGNMENTEXPRESSIONMUTATOR_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang 15 | { 16 | namespace grayc 17 | { 18 | namespace cmutation 19 | { 20 | 21 | /// Expands binary assignments based on their 22 | /// subexpressions. 23 | /// 24 | /// Before: 25 | /// 26 | /// \code 27 | /// a=a+b 28 | /// \endcode 29 | /// 30 | /// After: 31 | /// 32 | /// \code 33 | /// a=a+(a/c) 34 | /// \endcode 35 | /// 36 | class AssignmentExpressionMutator : public GrayCCheck 37 | { 38 | public: 39 | AssignmentExpressionMutator(StringRef Name, GrayCContext *Context) 40 | : GrayCCheck(Name, Context) {Seed = Context->getOptions().Seed;} 41 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 42 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 43 | llvm::Optional Seed; 44 | // Taken from LLVM source repo 45 | // [C++ 5.5] Pointer-to-member operators. 46 | // [C99 6.5.5] Multiplicative operators. 47 | // [C99 6.5.6] Additive operators. 48 | // [C99 6.5.7] Bitwise shift operators. 49 | // C++20 [expr.spaceship] Three-way comparison operator. 50 | // [C99 6.5.8] Relational operators. 51 | // [C99 6.5.9] Equality operators. 52 | // [C99 6.5.10] Bitwise AND operator. 53 | // [C99 6.5.11] Bitwise XOR operator. 54 | // [C99 6.5.12] Bitwise OR operator. 55 | // [C99 6.5.13] Logical AND operator. 56 | // [C99 6.5.14] Logical OR operator. 57 | // [C99 6.5.16] Assignment operators. 58 | // [C99 6.5.17] Comma operator. 59 | 60 | enum BinaryOperatorKind 61 | { 62 | Mul, 63 | Div, 64 | Rem, 65 | Add, 66 | Sub, 67 | Shl, 68 | Shr, 69 | LT, 70 | GT, 71 | LE, 72 | GE, 73 | EQ, 74 | NE, 75 | And, 76 | Xor, 77 | Or, 78 | LAnd, 79 | LOr, 80 | Assign, 81 | MulAssign, 82 | DivAssign, 83 | RemAssign, 84 | AddAssign, 85 | SubAssign, 86 | ShlAssign, 87 | ShrAssign, 88 | XorAssign, 89 | OrAssign, 90 | Comma, 91 | Last 92 | }; 93 | llvm::StringRef BinaryOperatorStrings[32] = {"*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "&", "^", "|", "&&", "||", "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="}; 94 | 95 | private: 96 | bool mutateAssignment(const ast_matchers::MatchFinder::MatchResult &Result, 97 | const BinaryOperator *S, SourceLocation StartLoc, 98 | SourceLocation EndLocHint = SourceLocation()); 99 | void buildExpressionVector(const ast_matchers::MatchFinder::MatchResult &Result, llvm::SmallVector &expressions, const Expr *E); 100 | llvm::SmallVector expressions; 101 | }; 102 | 103 | } // namespace cmutation 104 | } // namespace grayc 105 | } // namespace clang 106 | 107 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_ASSIGNMENTEXPRESSIONMUTATOR_H 108 | -------------------------------------------------------------------------------- /grayc/cmutation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(GrayCCMutator 2 | AssignmentExpressionMutator.cpp 3 | CMutationModule.cpp 4 | ConditionalExpressionMutator.cpp 5 | DuplicateStatementMutator.cpp 6 | JumpMutator.cpp 7 | UnaryOperatorCheck.cpp 8 | ) 9 | 10 | target_link_libraries(GrayCCMutator 11 | PRIVATE 12 | clangAnalysis 13 | clangAST 14 | clangASTMatchers 15 | clangBasic 16 | clangLex 17 | clangTooling 18 | GrayC 19 | GrayCUtils 20 | ) 21 | -------------------------------------------------------------------------------- /grayc/cmutation/CMutationModule.cpp: -------------------------------------------------------------------------------- 1 | //===--- CMutationModule.cpp - 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 | #include "../GrayC.h" 10 | #include "../GrayCModule.h" 11 | #include "../GrayCModuleRegistry.h" 12 | #include "AssignmentExpressionMutator.h" 13 | #include "ConditionalExpressionMutator.h" 14 | #include "DuplicateStatementMutator.h" 15 | #include "JumpMutator.h" 16 | #include "UnaryOperatorCheck.h" 17 | 18 | 19 | namespace clang { 20 | namespace grayc { 21 | namespace cmutation { 22 | 23 | class CMutationModule : public GrayCModule { 24 | public: 25 | void addCheckFactories(GrayCCheckFactories &CheckFactories) override { 26 | CheckFactories.registerCheck( 27 | "cmutation-assignment-expression-mutator"); 28 | CheckFactories.registerCheck( 29 | "cmutation-conditional-expression-mutator"); 30 | CheckFactories.registerCheck( 31 | "cmutation-duplicate-statement-mutator"); 32 | CheckFactories.registerCheck( 33 | "cmutation-jump-mutator"); 34 | CheckFactories.registerCheck( 35 | "cmutation-unary"); 36 | } 37 | }; 38 | 39 | // Register the CMutationModule using this statically initialized variable. 40 | static GrayCModuleRegistry::Add 41 | X("cmutator-module", "C program mutations."); 42 | 43 | } // namespace cmutation 44 | 45 | // This anchor is used to force the linker to link in the generated object file 46 | // and thus register the CMutationModule. 47 | volatile int CMutatorModuleAnchorSource = 0; 48 | 49 | } // namespace grayc 50 | } // namespace clang 51 | -------------------------------------------------------------------------------- /grayc/cmutation/ConditionalExpressionMutator.cpp: -------------------------------------------------------------------------------- 1 | //===--- ConditionalExpressionMutator.cpp - grayc --------------------===// 2 | // 3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM 4 | // Exceptions. See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #include "ConditionalExpressionMutator.h" 10 | #include "../utils/GrayCRandomManager.h" 11 | #include "clang/AST/ASTContext.h" 12 | #include "clang/ASTMatchers/ASTMatchFinder.h" 13 | #include "clang/Lex/Lexer.h" 14 | 15 | using namespace clang::ast_matchers; 16 | 17 | namespace clang { 18 | namespace grayc { 19 | namespace cmutation { 20 | 21 | void ConditionalExpressionMutator::registerMatchers(MatchFinder *Finder) { 22 | Finder->addMatcher( 23 | binaryOperator(unless(isAssignmentOperator())).bind("conditional"), this); 24 | } 25 | 26 | void ConditionalExpressionMutator::check( 27 | const MatchFinder::MatchResult &Result) { 28 | srand(Seed.getValue()); 29 | const SourceManager &SM = *Result.SourceManager; 30 | const ASTContext *Context = Result.Context; 31 | llvm::WithColor::remark() << "Using SEED: " << Seed << "\n"; 32 | if (auto C = Result.Nodes.getNodeAs("conditional")) { 33 | mutateConditional(Result, C, C->getBeginLoc(), C->getEndLoc()); 34 | } else { 35 | llvm_unreachable("Invalid match"); 36 | } 37 | } 38 | bool ConditionalExpressionMutator::mutateConditional( 39 | const MatchFinder::MatchResult &Result, const BinaryOperator *C, 40 | SourceLocation InitialLoc, SourceLocation EndLocHint) { 41 | GrayCRandomManager::CreateInstance(Seed.getValue(), 65000); 42 | if (GrayCRandomManager::GetInstance()->rnd_yes_no(0.6)) { 43 | llvm::WithColor::note() 44 | << "Ignoring potential expression mutation due to the given seed\n"; 45 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 46 | return true; 47 | } 48 | if (!InitialLoc.isValid()){ 49 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 50 | return false; 51 | } 52 | const SourceManager &SM = *Result.SourceManager; 53 | const ASTContext *Context = Result.Context; 54 | 55 | // Treat macros. 56 | CharSourceRange FileRange = Lexer::makeFileCharRange( 57 | CharSourceRange::getTokenRange(C->getSourceRange()), SM, 58 | Context->getLangOpts()); 59 | if (FileRange.isInvalid()){ 60 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 61 | return false; 62 | } 63 | InitialLoc = Lexer::makeFileCharRange( 64 | CharSourceRange::getCharRange(InitialLoc, C->getBeginLoc()), 65 | SM, Context->getLangOpts()) 66 | .getBegin(); 67 | 68 | if (InitialLoc.isInvalid()){ 69 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 70 | return false; 71 | } 72 | assert(EndLocHint.isValid()); 73 | auto Diag = diag(InitialLoc, "found conditional statement to mutate"); 74 | buildExpressionVector(Result, expressions, C); 75 | if (expressions.size() == 0) { 76 | llvm::WithColor::remark() << "No subexpressions collected!!"; 77 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 78 | return false; 79 | } 80 | ConditionOperatorKind CK = ConditionOperatorKind(GrayCRandomManager::GetInstance()->rnd_dice(Last)); 81 | llvm::Twine SelectedConditionOperator(ConditionOperatorStrings[CK]); 82 | llvm::WithColor::remark() 83 | << "Selected operator: " << SelectedConditionOperator.str() << "\n"; 84 | llvm::WithColor::remark() 85 | << "Number of subexpressions: " << expressions.size() << "\n"; 86 | llvm::outs()<rnd_dice(expressions.size())<<"\n"; 87 | llvm::Twine NewRHS(expressions[GrayCRandomManager::GetInstance()->rnd_dice(expressions.size())]); 88 | llvm::Twine NewLHS(expressions[(GrayCRandomManager::GetInstance()->rnd_dice(expressions.size())+1)%expressions.size()]); 89 | llvm::Twine MutatedConditional(NewLHS + SelectedConditionOperator + NewRHS); 90 | 91 | llvm::WithColor::remark() 92 | << "Expression built : " << MutatedConditional.str() << "\n"; 93 | 94 | Diag << FixItHint::CreateReplacement( 95 | CharSourceRange::getTokenRange(InitialLoc, EndLocHint), 96 | MutatedConditional.str()); 97 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 98 | return true; 99 | } 100 | void ConditionalExpressionMutator::buildExpressionVector( 101 | const MatchFinder::MatchResult &Result, 102 | llvm::SmallVector &expressions, const Expr *E) { 103 | if (!isa(E)) { 104 | return; 105 | } else { 106 | const SourceManager &SM = *Result.SourceManager; 107 | const ASTContext *Context = Result.Context; 108 | const BinaryOperator *BO = dyn_cast(E); 109 | Expr *LHS = BO->getLHS()->IgnoreParens()->IgnoreImpCasts(); 110 | Expr *RHS = BO->getRHS()->IgnoreParens()->IgnoreImpCasts(); 111 | SourceRange LHSRange(LHS->getBeginLoc(), LHS->getEndLoc()); 112 | SourceRange RHSRange(RHS->getBeginLoc(), RHS->getEndLoc()); 113 | expressions.push_back(Lexer::getSourceText( 114 | CharSourceRange::getTokenRange(LHSRange), SM, Context->getLangOpts())); 115 | expressions.push_back(Lexer::getSourceText( 116 | CharSourceRange::getTokenRange(RHSRange), SM, Context->getLangOpts())); 117 | llvm::WithColor::remark() 118 | << "Number of expressions collected: " << expressions.size() << "\n"; 119 | llvm::WithColor::remark() 120 | << "Collected subexpressions: " 121 | << Lexer::getSourceText(CharSourceRange::getTokenRange(LHSRange), SM, 122 | Context->getLangOpts()) 123 | << "," 124 | << Lexer::getSourceText(CharSourceRange::getTokenRange(RHSRange), SM, 125 | Context->getLangOpts()) 126 | << "\n"; 127 | 128 | if (isa(LHS)) { 129 | buildExpressionVector(Result, expressions, dyn_cast(LHS)); 130 | } 131 | if (isa(RHS)) { 132 | buildExpressionVector(Result, expressions, dyn_cast(RHS)); 133 | } 134 | } 135 | } 136 | } // namespace cmutation 137 | } // namespace grayc 138 | } // namespace clang 139 | -------------------------------------------------------------------------------- /grayc/cmutation/ConditionalExpressionMutator.h: -------------------------------------------------------------------------------- 1 | //===--- ConditionalExpressionMutator.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_CONDITIONALEXPRESSIONMUTATOR_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_CONDITIONALEXPRESSIONMUTATOR_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang 15 | { 16 | namespace grayc 17 | { 18 | namespace cmutation 19 | { 20 | 21 | /// FIXME: Write a short description. 22 | /// 23 | class ConditionalExpressionMutator : public GrayCCheck 24 | { 25 | public: 26 | ConditionalExpressionMutator(StringRef Name, GrayCContext *Context) 27 | : GrayCCheck(Name, Context) { Seed = Context->getOptions().Seed;} 28 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 29 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 30 | llvm::Optional Seed; 31 | // Taken from LLVM source repo 32 | // [C++ 5.5] Pointer-to-member operators. 33 | // [C99 6.5.5] Multiplicative operators. 34 | // [C99 6.5.6] Additive operators. 35 | // [C99 6.5.7] Bitwise shift operators. 36 | // C++20 [expr.spaceship] Three-way comparison operator. 37 | // [C99 6.5.8] Relational operators. 38 | // [C99 6.5.9] Equality operators. 39 | // [C99 6.5.10] Bitwise AND operator. 40 | // [C99 6.5.11] Bitwise XOR operator. 41 | // [C99 6.5.12] Bitwise OR operator. 42 | // [C99 6.5.13] Logical AND operator. 43 | // [C99 6.5.14] Logical OR operator. 44 | // [C99 6.5.17] Comma operator. 45 | 46 | enum ConditionOperatorKind 47 | { 48 | Mul, 49 | Div, 50 | Rem, 51 | Add, 52 | Sub, 53 | Shl, 54 | Shr, 55 | Cmp, 56 | LT, 57 | GT, 58 | LE, 59 | GE, 60 | EQ, 61 | NE, 62 | And, 63 | Xor, 64 | Or, 65 | LAnd, 66 | LOr, 67 | Last 68 | }; 69 | llvm::StringRef ConditionOperatorStrings[19] = {"*", "/", "%", "+", "-", "<<", ">>", "<", ">", "<=", ">=", "&", "^", "|", "&&", "||"}; 70 | 71 | private: 72 | bool mutateConditional(const ast_matchers::MatchFinder::MatchResult &Result, 73 | const BinaryOperator *S, SourceLocation StartLoc, 74 | SourceLocation EndLocHint = SourceLocation()); 75 | void buildExpressionVector(const ast_matchers::MatchFinder::MatchResult &Result, llvm::SmallVector &expressions, const Expr *E); 76 | llvm::SmallVector expressions; 77 | }; 78 | 79 | } // namespace cmutation 80 | } // namespace grayc 81 | } // namespace clang 82 | 83 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_CONDITIONALEXPRESSIONMUTATOR_H 84 | -------------------------------------------------------------------------------- /grayc/cmutation/DuplicateStatementMutator.cpp: -------------------------------------------------------------------------------- 1 | //===--- DuplicateStatementMutator.cpp - grayc -----------------------===// 2 | // 3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM 4 | // Exceptions. See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #include "DuplicateStatementMutator.h" 10 | #include "../utils/GrayCRandomManager.h" 11 | #include "clang/AST/ASTContext.h" 12 | #include "clang/ASTMatchers/ASTMatchFinder.h" 13 | #include "clang/Lex/Lexer.h" 14 | 15 | using namespace clang::ast_matchers; 16 | 17 | namespace clang { 18 | namespace grayc { 19 | namespace cmutation { 20 | 21 | void DuplicateStatementMutator::registerMatchers(MatchFinder *Finder) { 22 | Finder->addMatcher(binaryOperator(hasOperatorName("="), 23 | hasLHS(declRefExpr().bind("lhs")), 24 | hasRHS(expr().bind("rhs"))) 25 | .bind("binaryOp"), 26 | this); 27 | } 28 | 29 | void DuplicateStatementMutator::check(const MatchFinder::MatchResult &Result) { 30 | 31 | const SourceManager &SM = *Result.SourceManager; 32 | const ASTContext *Context = Result.Context; 33 | GrayCRandomManager::CreateInstance(Seed.getValue(), 65000); 34 | llvm::WithColor::remark() << "Using SEED: " << Seed << "\n"; 35 | if (GrayCRandomManager::GetInstance()->rnd_yes_no(0.7)) { 36 | llvm::WithColor::note() 37 | << "Ignoring potential duplicate statement mutation due to the given seed\n"; 38 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 39 | return; 40 | } 41 | const auto *BinaryOp = Result.Nodes.getNodeAs("binaryOp"); 42 | // Treat macros. 43 | CharSourceRange FileRange = Lexer::makeFileCharRange( 44 | CharSourceRange::getTokenRange(BinaryOp->getSourceRange()), SM, 45 | Context->getLangOpts()); 46 | if (FileRange.isInvalid()) { 47 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 48 | return; 49 | } 50 | if (BinaryOp) { 51 | const auto *LHS = Result.Nodes.getNodeAs("lhs"); 52 | const auto *RHS = Result.Nodes.getNodeAs("rhs"); 53 | 54 | if (LHS && RHS) { 55 | // Duplicate the binary assignment statement. 56 | SourceLocation StartLoc = BinaryOp->getBeginLoc(); 57 | SourceLocation EndLoc = BinaryOp->getEndLoc(); 58 | SourceRange AssignmentOperatorRange(StartLoc, EndLoc); 59 | std::string ExtractedString = std::string(Lexer::getSourceText( 60 | CharSourceRange::getTokenRange(AssignmentOperatorRange), SM, 61 | Context->getLangOpts())); 62 | std::string DuplicatedStringToInsert = ExtractedString + ";"; 63 | auto Diag = diag(StartLoc, "found statement to duplicate"); 64 | llvm::WithColor::remark() 65 | << "Adding duplicated statement after " 66 | << RHS->getEndLoc().getLocWithOffset(2).printToString(SM) << "\n"; 67 | Diag << FixItHint::CreateInsertion(RHS->getEndLoc().getLocWithOffset(2), 68 | DuplicatedStringToInsert); 69 | 70 | } 71 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 72 | } 73 | } 74 | } // namespace cmutation 75 | } // namespace grayc 76 | } // namespace clang 77 | -------------------------------------------------------------------------------- /grayc/cmutation/DuplicateStatementMutator.h: -------------------------------------------------------------------------------- 1 | //===--- DuplicateStatementMutator.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_DUPLICATESTATEMENTMUTATOR_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_DUPLICATESTATEMENTMUTATOR_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang { 15 | namespace grayc { 16 | namespace cmutation { 17 | 18 | /// FIXME: Write a short description. 19 | /// 20 | class DuplicateStatementMutator : public GrayCCheck { 21 | public: 22 | DuplicateStatementMutator(StringRef Name, GrayCContext *Context) 23 | : GrayCCheck(Name, Context) {Seed = Context->getOptions().Seed;} 24 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 25 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 26 | llvm::Optional Seed; 27 | }; 28 | 29 | } // namespace cmutation 30 | } // namespace grayc 31 | } // namespace clang 32 | 33 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_DUPLICATESTATEMENTMUTATOR_H 34 | -------------------------------------------------------------------------------- /grayc/cmutation/JumpMutator.cpp: -------------------------------------------------------------------------------- 1 | //===--- JumpMutator.cpp - 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 | #include "JumpMutator.h" 10 | #include "clang/AST/ASTContext.h" 11 | #include "clang/ASTMatchers/ASTMatchFinder.h" 12 | #include "clang/Lex/Lexer.h" 13 | #include "../utils/GrayCRandomManager.h" 14 | 15 | 16 | using namespace clang::ast_matchers; 17 | 18 | namespace clang 19 | { 20 | namespace grayc 21 | { 22 | namespace cmutation 23 | { 24 | 25 | void JumpMutator::registerMatchers(MatchFinder *Finder) 26 | { 27 | // FIXIT: Extend to nested loops, for now only match non-nested loops. 28 | Finder->addMatcher(forStmt(unless(hasDescendant(forStmt()))).bind("no-nest-for"), this); 29 | Finder->addMatcher(whileStmt(unless(hasDescendant(whileStmt()))).bind("no-nest-while"), this); 30 | Finder->addMatcher(doStmt(unless(hasDescendant(doStmt()))).bind("no-nest-do"), this); 31 | } 32 | 33 | void JumpMutator::check(const MatchFinder::MatchResult &Result) 34 | { 35 | 36 | if (auto F = Result.Nodes.getNodeAs("no-nest-for")) 37 | { 38 | mutateLoop(Result, For, F, F->getBeginLoc(), F->getEndLoc()); 39 | } 40 | else if (auto W = Result.Nodes.getNodeAs("no-nest-while")) 41 | { 42 | mutateLoop(Result, While, W, W->getBeginLoc(), W->getEndLoc()); 43 | } 44 | else if (auto D = Result.Nodes.getNodeAs("no-nest-while")) 45 | { 46 | mutateLoop(Result, DoWhile, D, D->getBeginLoc(), D->getEndLoc()); 47 | } 48 | else 49 | { 50 | llvm_unreachable("Invalid match"); 51 | } 52 | } 53 | bool JumpMutator::mutateLoop( 54 | const MatchFinder::MatchResult &Result, LoopKind L, const Stmt *S, 55 | SourceLocation InitialLoc, SourceLocation EndLocHint) 56 | { 57 | GrayCRandomManager::CreateInstance(Seed.getValue(), 65000); 58 | if (GrayCRandomManager::GetInstance()->rnd_yes_no(0.4)){ 59 | llvm::WithColor::note() 60 | << "Ignoring potential jump statement mutation due to the given seed\n"; 61 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 62 | return true; 63 | } 64 | if (!InitialLoc.isValid()) 65 | return false; 66 | const SourceManager &SM = *Result.SourceManager; 67 | const ASTContext *Context = Result.Context; 68 | 69 | // Treat macros. 70 | CharSourceRange FileRange = Lexer::makeFileCharRange( 71 | CharSourceRange::getTokenRange(S->getSourceRange()), SM, 72 | Context->getLangOpts()); 73 | if (FileRange.isInvalid()) 74 | return false; 75 | InitialLoc = Lexer::makeFileCharRange( 76 | CharSourceRange::getCharRange(InitialLoc, S->getBeginLoc()), 77 | SM, Context->getLangOpts()) 78 | .getBegin(); 79 | 80 | if (InitialLoc.isInvalid()) 81 | return false; 82 | assert(EndLocHint.isValid()); 83 | const Stmt *Body; 84 | std::string JumpConstruct((GrayCRandomManager::GetInstance()->rnd_yes_no(0.5)) == 1 ? "{break;}" : "{continue;}"); 85 | 86 | switch (L) 87 | { 88 | case For: 89 | assert(isa(S) && "Error matching nodes!!"); 90 | if (dyn_cast(S)->getBody()) 91 | { 92 | Body = dyn_cast(S)->getBody(); 93 | auto Diag = diag(Body->getEndLoc(), "found for loop to mutate"); 94 | llvm::WithColor::remark() << "Adding jump statement (`break` or `continue`) at " << Body->getEndLoc().printToString(SM) << "\n"; 95 | Diag << FixItHint::CreateInsertion(Body->getEndLoc(), JumpConstruct); 96 | } 97 | else 98 | { 99 | return false; 100 | } 101 | break; 102 | case While: 103 | assert(isa(S) && "Error matching nodes!!"); 104 | if (dyn_cast(S)->getBody()) 105 | { 106 | Body = dyn_cast(S)->getBody(); 107 | auto Diag = diag(InitialLoc, "found while loop to mutate"); 108 | llvm::WithColor::remark() << "Adding jump statement (`break` or `continue`) at " << Body->getEndLoc().printToString(SM) << "\n"; 109 | Diag << FixItHint::CreateInsertion(Body->getBeginLoc(), JumpConstruct); 110 | } 111 | else 112 | { 113 | return false; 114 | } 115 | break; 116 | case DoWhile: 117 | assert(isa(S) && "Error matching nodes!!"); 118 | if (dyn_cast(S)->getBody()) 119 | { 120 | Body = dyn_cast(S)->getBody(); 121 | auto Diag = diag(InitialLoc, "found do while loop to mutate"); 122 | llvm::WithColor::remark() << "Adding jump statement (`break` or `continue`) at " << Body->getEndLoc().printToString(SM) << "\n"; 123 | Diag << FixItHint::CreateInsertion(Body->getBeginLoc(), JumpConstruct); 124 | } 125 | else 126 | { 127 | return false; 128 | } 129 | break; 130 | default: 131 | return false; 132 | } 133 | 134 | return true; 135 | } 136 | } // namespace cmutation 137 | } // namespace grayc 138 | } // namespace clang 139 | -------------------------------------------------------------------------------- /grayc/cmutation/JumpMutator.h: -------------------------------------------------------------------------------- 1 | //===--- JumpMutator.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_JUMPMUTATOR_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_JUMPMUTATOR_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang 15 | { 16 | namespace grayc 17 | { 18 | namespace cmutation 19 | { 20 | 21 | /// FIXME: Write a short description. 22 | /// 23 | class JumpMutator : public GrayCCheck 24 | { 25 | public: 26 | JumpMutator(StringRef Name, GrayCContext *Context) 27 | : GrayCCheck(Name, Context) {Seed = Context->getOptions().Seed;} 28 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 29 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 30 | llvm::Optional Seed; 31 | private: 32 | enum LoopKind {For,While,DoWhile}; 33 | bool mutateLoop(const ast_matchers::MatchFinder::MatchResult &Result,LoopKind L, 34 | const Stmt *S, SourceLocation StartLoc, 35 | SourceLocation EndLocHint = SourceLocation()); 36 | }; 37 | } // namespace cmutation 38 | } // namespace grayc 39 | } // namespace clang 40 | 41 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_CMUTATION_JUMPMUTATOR_H 42 | -------------------------------------------------------------------------------- /grayc/cmutation/UnaryOperatorCheck.cpp: -------------------------------------------------------------------------------- 1 | //===--- UnaryOperatorCheck.cpp - GrayC ---------------------===// 2 | // 3 | // Taken from the LLVM Project, under the Apache License v2.0 with LLVM 4 | // Exceptions. See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #include "UnaryOperatorCheck.h" 10 | #include "../utils/GrayCRandomManager.h" 11 | #include "clang/AST/ASTContext.h" 12 | #include "clang/ASTMatchers/ASTMatchers.h" 13 | #include "clang/Lex/Lexer.h" 14 | 15 | using namespace clang::ast_matchers; 16 | 17 | namespace clang { 18 | namespace grayc { 19 | namespace cmutation { 20 | namespace { 21 | 22 | tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, 23 | const ASTContext *Context) { 24 | Token Tok; 25 | SourceLocation Beginning = 26 | Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts()); 27 | const bool Invalid = 28 | Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts()); 29 | assert(!Invalid && "Expected a valid token."); 30 | 31 | if (Invalid) 32 | return tok::NUM_TOKENS; 33 | 34 | return Tok.getKind(); 35 | } 36 | 37 | SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc, 38 | const SourceManager &SM, 39 | const ASTContext *Context) { 40 | assert(Loc.isValid()); 41 | for (;;) { 42 | while (isWhitespace(*SM.getCharacterData(Loc))) 43 | Loc = Loc.getLocWithOffset(1); 44 | 45 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 46 | if (TokKind != tok::comment) 47 | return Loc; 48 | 49 | // Fast-forward current token. 50 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 51 | } 52 | } 53 | 54 | SourceLocation findEndLocation(SourceLocation LastTokenLoc, 55 | const SourceManager &SM, 56 | const ASTContext *Context) { 57 | SourceLocation Loc = 58 | Lexer::GetBeginningOfToken(LastTokenLoc, SM, Context->getLangOpts()); 59 | // Loc points to the beginning of the last (non-comment non-ws) token 60 | // before end or ';'. 61 | assert(Loc.isValid()); 62 | bool SkipEndWhitespaceAndComments = true; 63 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 64 | if (TokKind == tok::NUM_TOKENS || TokKind == tok::semi || 65 | TokKind == tok::r_brace) { 66 | // If we are at ";" or "}", we found the last token. We could use as well 67 | // `if (isa(S))`, but it wouldn't work for nested statements. 68 | SkipEndWhitespaceAndComments = false; 69 | } 70 | 71 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 72 | // Loc points past the last token before end or after ';'. 73 | if (SkipEndWhitespaceAndComments) { 74 | Loc = forwardSkipWhitespaceAndComments(Loc, SM, Context); 75 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 76 | if (TokKind == tok::semi) 77 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 78 | } 79 | 80 | for (;;) { 81 | assert(Loc.isValid()); 82 | while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { 83 | Loc = Loc.getLocWithOffset(1); 84 | } 85 | 86 | if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { 87 | // EOL, insert brace before. 88 | break; 89 | } 90 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 91 | if (TokKind != tok::comment) { 92 | // Non-comment token, insert brace before. 93 | break; 94 | } 95 | 96 | SourceLocation TokEndLoc = 97 | Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 98 | SourceRange TokRange(Loc, TokEndLoc); 99 | StringRef Comment = Lexer::getSourceText( 100 | CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts()); 101 | if (Comment.startswith("/*") && Comment.find('\n') != StringRef::npos) { 102 | // Multi-line block comment, insert brace before. 103 | break; 104 | } 105 | // else: Trailing comment, insert brace after the newline. 106 | 107 | // Fast-forward current token. 108 | Loc = TokEndLoc; 109 | } 110 | return Loc; 111 | } 112 | 113 | } // namespace 114 | 115 | void UnaryOperatorCheck::registerMatchers(MatchFinder *Finder) { 116 | Finder->addMatcher(unaryOperator().bind("unary-operator"), this); 117 | } 118 | 119 | void UnaryOperatorCheck::check(const MatchFinder::MatchResult &Result) { 120 | const SourceManager &SM = *Result.SourceManager; 121 | const ASTContext *Context = Result.Context; 122 | llvm::WithColor::remark() << "Using SEED: " << Seed << "\n"; 123 | if (auto S = Result.Nodes.getNodeAs("unary-operator")) { 124 | mutateUnaryOperator(Result, S, S->getOperatorLoc(), S->getExprLoc()); 125 | } else { 126 | llvm_unreachable("Invalid match"); 127 | } 128 | } 129 | 130 | bool UnaryOperatorCheck::mutateUnaryOperator( 131 | const MatchFinder::MatchResult &Result, const UnaryOperator *S, 132 | SourceLocation InitialLoc, SourceLocation EndLocHint) { 133 | GrayCRandomManager::CreateInstance(Seed.getValue(), 65000); 134 | if (GrayCRandomManager::GetInstance()->rnd_yes_no(0.6)) { 135 | llvm::WithColor::note() 136 | << "Ignoring potential unary operator mutation due to the given seed\n"; 137 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 138 | return true; 139 | } 140 | if (!S->isIncrementOp() && !S->isDecrementOp()) { 141 | return false; 142 | } 143 | if (!InitialLoc.isValid()) 144 | return false; 145 | const SourceManager &SM = *Result.SourceManager; 146 | const ASTContext *Context = Result.Context; 147 | 148 | // Treat macros. 149 | CharSourceRange FileRange = Lexer::makeFileCharRange( 150 | CharSourceRange::getTokenRange(S->getSourceRange()), SM, 151 | Context->getLangOpts()); 152 | if (FileRange.isInvalid()) 153 | return false; 154 | InitialLoc = Lexer::makeFileCharRange( 155 | CharSourceRange::getCharRange(InitialLoc, S->getBeginLoc()), 156 | SM, Context->getLangOpts()) 157 | .getBegin(); 158 | if (InitialLoc.isInvalid()) 159 | return false; 160 | assert(EndLocHint.isValid()); 161 | auto Diag = diag(InitialLoc, "found candidate unary operator to mutate"); 162 | 163 | // Decide opcode and hence the mutated opcode 164 | std::string MutatedOperator; 165 | MutatedOperator = S->getOpcode() == UO_PreInc ? "--" : "++"; 166 | 167 | Diag << FixItHint::CreateReplacement( 168 | CharSourceRange::getTokenRange(InitialLoc, EndLocHint), MutatedOperator); 169 | 170 | GrayCRandomManager::DeleteInstance(Seed.getValue()); 171 | return true; 172 | } 173 | 174 | } // namespace cmutation 175 | } // namespace grayc 176 | } // namespace clang 177 | -------------------------------------------------------------------------------- /grayc/cmutation/UnaryOperatorCheck.h: -------------------------------------------------------------------------------- 1 | //===--- UnaryOperatorCheck.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_READABILITY_UnaryOperatorCheck_H 10 | #define GRAYC_READABILITY_UnaryOperatorCheck_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang { 15 | namespace grayc { 16 | namespace cmutation { 17 | 18 | /// Transforms increment and decrement unary operators 19 | /// into their opposite types 20 | /// 21 | /// Before: 22 | /// 23 | /// \code 24 | /// ++a; 25 | /// \endcode 26 | /// 27 | /// After: 28 | /// 29 | /// \code 30 | /// --a; 31 | /// \endcode 32 | /// 33 | class UnaryOperatorCheck : public GrayCCheck { 34 | public: 35 | UnaryOperatorCheck(StringRef Name, GrayCContext *Context) : GrayCCheck(Name, Context) {Seed = Context->getOptions().Seed;} 36 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 37 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 38 | llvm::Optional Seed; 39 | private: 40 | bool mutateUnaryOperator(const ast_matchers::MatchFinder::MatchResult &Result, 41 | const UnaryOperator *S, SourceLocation StartLoc, 42 | SourceLocation EndLocHint = SourceLocation()); 43 | }; 44 | 45 | } // namespace readability 46 | } // namespace grayc 47 | } // namespace clang 48 | 49 | #endif // GRAYC_READABILITY_UnaryOperatorCheck_H 50 | -------------------------------------------------------------------------------- /grayc/cxxmutation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(GrayCCXXMutator 2 | CXXMutationModule.cpp 3 | CXXUnaryOperatorCheck.cpp 4 | ) 5 | 6 | target_link_libraries(GrayCCXXMutator 7 | PRIVATE 8 | clangAnalysis 9 | clangAST 10 | clangASTMatchers 11 | clangBasic 12 | clangLex 13 | clangTooling 14 | GrayC 15 | ) 16 | -------------------------------------------------------------------------------- /grayc/cxxmutation/CXXMutationModule.cpp: -------------------------------------------------------------------------------- 1 | //===--- CXXMutationModule.cpp - 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 | #include "../GrayC.h" 10 | #include "../GrayCModule.h" 11 | #include "../GrayCModuleRegistry.h" 12 | #include "CXXUnaryOperatorCheck.h" 13 | 14 | 15 | namespace clang { 16 | namespace grayc { 17 | namespace cxxmutation { 18 | 19 | class CXXMutationModule : public GrayCModule { 20 | public: 21 | void addCheckFactories(GrayCCheckFactories &CheckFactories) override { 22 | CheckFactories.registerCheck( 23 | "cxxmutaion-unary"); 24 | } 25 | }; 26 | 27 | // Register the CXXMutationModule using this statically initialized variable. 28 | static GrayCModuleRegistry::Add 29 | X("cxxmutator-module", "CXX program mutations."); 30 | 31 | } // namespace readability 32 | 33 | // This anchor is used to force the linker to link in the generated object file 34 | // and thus register the CXXMutationModule. 35 | volatile int CXXMutatorModuleAnchorSource = 0; 36 | 37 | } // namespace grayc 38 | } // namespace clang 39 | -------------------------------------------------------------------------------- /grayc/cxxmutation/CXXUnaryOperatorCheck.cpp: -------------------------------------------------------------------------------- 1 | //===--- UnaryOperatorCheck.cpp - 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 | #include "CXXUnaryOperatorCheck.h" 10 | #include "clang/AST/ASTContext.h" 11 | #include "clang/ASTMatchers/ASTMatchers.h" 12 | #include "clang/Lex/Lexer.h" 13 | 14 | using namespace clang::ast_matchers; 15 | 16 | namespace clang { 17 | namespace grayc { 18 | namespace cxxmutation { 19 | namespace { 20 | 21 | tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, 22 | const ASTContext *Context) { 23 | Token Tok; 24 | SourceLocation Beginning = 25 | Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts()); 26 | const bool Invalid = 27 | Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts()); 28 | assert(!Invalid && "Expected a valid token."); 29 | 30 | if (Invalid) 31 | return tok::NUM_TOKENS; 32 | 33 | return Tok.getKind(); 34 | } 35 | 36 | SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc, 37 | const SourceManager &SM, 38 | const ASTContext *Context) { 39 | assert(Loc.isValid()); 40 | for (;;) { 41 | while (isWhitespace(*SM.getCharacterData(Loc))) 42 | Loc = Loc.getLocWithOffset(1); 43 | 44 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 45 | if (TokKind != tok::comment) 46 | return Loc; 47 | 48 | // Fast-forward current token. 49 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 50 | } 51 | } 52 | 53 | SourceLocation findEndLocation(SourceLocation LastTokenLoc, 54 | const SourceManager &SM, 55 | const ASTContext *Context) { 56 | SourceLocation Loc = 57 | Lexer::GetBeginningOfToken(LastTokenLoc, SM, Context->getLangOpts()); 58 | // Loc points to the beginning of the last (non-comment non-ws) token 59 | // before end or ';'. 60 | assert(Loc.isValid()); 61 | bool SkipEndWhitespaceAndComments = true; 62 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 63 | if (TokKind == tok::NUM_TOKENS || TokKind == tok::semi || 64 | TokKind == tok::r_brace) { 65 | // If we are at ";" or "}", we found the last token. We could use as well 66 | // `if (isa(S))`, but it wouldn't work for nested statements. 67 | SkipEndWhitespaceAndComments = false; 68 | } 69 | 70 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 71 | // Loc points past the last token before end or after ';'. 72 | if (SkipEndWhitespaceAndComments) { 73 | Loc = forwardSkipWhitespaceAndComments(Loc, SM, Context); 74 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 75 | if (TokKind == tok::semi) 76 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 77 | } 78 | 79 | for (;;) { 80 | assert(Loc.isValid()); 81 | while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { 82 | Loc = Loc.getLocWithOffset(1); 83 | } 84 | 85 | if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { 86 | // EOL, insert brace before. 87 | break; 88 | } 89 | tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); 90 | if (TokKind != tok::comment) { 91 | // Non-comment token, insert brace before. 92 | break; 93 | } 94 | 95 | SourceLocation TokEndLoc = 96 | Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); 97 | SourceRange TokRange(Loc, TokEndLoc); 98 | StringRef Comment = Lexer::getSourceText( 99 | CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts()); 100 | if (Comment.startswith("/*") && Comment.find('\n') != StringRef::npos) { 101 | // Multi-line block comment, insert brace before. 102 | break; 103 | } 104 | // else: Trailing comment, insert brace after the newline. 105 | 106 | // Fast-forward current token. 107 | Loc = TokEndLoc; 108 | } 109 | return Loc; 110 | } 111 | 112 | } // namespace 113 | 114 | CXXUnaryOperatorCheck::CXXUnaryOperatorCheck( 115 | StringRef Name, GrayCContext *Context) 116 | : GrayCCheck(Name, Context) {} 117 | 118 | 119 | void CXXUnaryOperatorCheck::registerMatchers(MatchFinder *Finder) { 120 | Finder->addMatcher(unaryOperator().bind("unary-operator"), this); 121 | } 122 | 123 | void CXXUnaryOperatorCheck::check( 124 | const MatchFinder::MatchResult &Result) { 125 | const SourceManager &SM = *Result.SourceManager; 126 | const ASTContext *Context = Result.Context; 127 | if (auto S = Result.Nodes.getNodeAs("unary-operator")) { 128 | mutateUnaryOperator(Result,S, S->getOperatorLoc(),S->getExprLoc()); 129 | } 130 | else { 131 | llvm_unreachable("Invalid match"); 132 | } 133 | } 134 | 135 | 136 | bool CXXUnaryOperatorCheck::mutateUnaryOperator( 137 | const MatchFinder::MatchResult &Result, const UnaryOperator *S, 138 | SourceLocation InitialLoc, SourceLocation EndLocHint) { 139 | if (!S->isIncrementOp() && !S->isDecrementOp()){ 140 | return false; 141 | } 142 | if (!InitialLoc.isValid()) 143 | return false; 144 | const SourceManager &SM = *Result.SourceManager; 145 | const ASTContext *Context = Result.Context; 146 | 147 | // Treat macros. 148 | CharSourceRange FileRange = Lexer::makeFileCharRange( 149 | CharSourceRange::getTokenRange(S->getSourceRange()), SM, 150 | Context->getLangOpts()); 151 | if (FileRange.isInvalid()) 152 | return false; 153 | InitialLoc = Lexer::makeFileCharRange( 154 | CharSourceRange::getCharRange(InitialLoc, S->getBeginLoc()), 155 | SM, Context->getLangOpts()) 156 | .getBegin(); 157 | if (InitialLoc.isInvalid()) 158 | return false; 159 | assert(EndLocHint.isValid()); 160 | auto Diag = diag(InitialLoc, "found candidate unary operator to mutate"); 161 | 162 | // Decide opcode and hence the mutated opcode 163 | std::string MutatedOperator; 164 | MutatedOperator = S->getOpcode() == UO_PreInc ? "--" : "++"; 165 | 166 | Diag << FixItHint::CreateReplacement(CharSourceRange::getTokenRange(InitialLoc, EndLocHint), MutatedOperator); 167 | return true; 168 | } 169 | 170 | 171 | } // namespace readability 172 | } // namespace grayc 173 | } // namespace clang 174 | -------------------------------------------------------------------------------- /grayc/cxxmutation/CXXUnaryOperatorCheck.h: -------------------------------------------------------------------------------- 1 | //===--- CXXUnaryOperatorCheck.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_READABILITY_CXXUnaryOperatorCheck_H 10 | #define GRAYC_READABILITY_CXXUnaryOperatorCheck_H 11 | 12 | #include "../GrayCCheck.h" 13 | 14 | namespace clang { 15 | namespace grayc { 16 | namespace cxxmutation { 17 | 18 | /// Checks that bodies of `if` statements and loops (`for`, `range-for`, 19 | /// `do-while`, and `while`) are inside braces 20 | /// 21 | /// Before: 22 | /// 23 | /// \code 24 | /// if (condition) 25 | /// statement; 26 | /// \endcode 27 | /// 28 | /// After: 29 | /// 30 | /// \code 31 | /// if (condition) { 32 | /// statement; 33 | /// } 34 | /// \endcode 35 | /// 36 | class CXXUnaryOperatorCheck : public GrayCCheck { 37 | public: 38 | CXXUnaryOperatorCheck(StringRef Name, GrayCContext *Context); 39 | void registerMatchers(ast_matchers::MatchFinder *Finder) override; 40 | void check(const ast_matchers::MatchFinder::MatchResult &Result) override; 41 | 42 | private: 43 | bool mutateUnaryOperator(const ast_matchers::MatchFinder::MatchResult &Result, 44 | const UnaryOperator *S, SourceLocation StartLoc, 45 | SourceLocation EndLocHint = SourceLocation()); 46 | }; 47 | 48 | } // namespace readability 49 | } // namespace grayc 50 | } // namespace clang 51 | 52 | #endif // GRAYC_READABILITY_CXXUnaryOperatorCheck_H 53 | -------------------------------------------------------------------------------- /grayc/run_clang_diff.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srg-imperial/GrayC/cbe5f4860283bfb44012881eae4a40e387164ca1/grayc/run_clang_diff.py -------------------------------------------------------------------------------- /grayc/tool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.3) 2 | project(grayc-st) 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 | #=============================================================================== 32 | # 3. ADD THE TARGET 33 | #=============================================================================== 34 | 35 | add_library(GrayCMain 36 | GrayCMain.cpp 37 | ) 38 | 39 | target_link_libraries(GrayCMain 40 | PRIVATE 41 | clangAST 42 | clangASTMatchers 43 | clangBasic 44 | clangTooling 45 | clangToolingCore 46 | GrayC 47 | GrayCCMutator 48 | GrayCCXXMutator 49 | ) 50 | 51 | add_executable(grayc GrayCToolMain.cpp) 52 | 53 | target_link_libraries(grayc 54 | PRIVATE 55 | GrayC 56 | GrayCMain 57 | GrayCCMutator 58 | GrayCCXXMutator 59 | ) 60 | target_link_libraries(grayc 61 | PRIVATE 62 | clangTooling 63 | clangBasic 64 | clangASTMatchers 65 | clangAST 66 | clangBasic 67 | clangToolingCore 68 | ) 69 | 70 | 71 | -------------------------------------------------------------------------------- /grayc/tool/GrayCMain.h: -------------------------------------------------------------------------------- 1 | //===--- GrayCMain.h - GrayC tool -------===// 2 | // 3 | //===----------------------------------------------------------------------===// 4 | /// 5 | /// \file This file declares the main function for the GrayC tool. 6 | /// 7 | //===----------------------------------------------------------------------===// 8 | namespace clang { 9 | namespace grayc { 10 | 11 | int GrayCMain(int argc, const char **argv); 12 | 13 | } // namespace grayc 14 | } 15 | -------------------------------------------------------------------------------- /grayc/tool/GrayCToolMain.cpp: -------------------------------------------------------------------------------- 1 | //===--- graycGrayCToolMain.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 This file contains grayc tool entry point main function. 10 | /// 11 | /// This tool uses the Clang Tooling infrastructure, see 12 | /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html 13 | /// for details on setting it up with LLVM source tree. 14 | /// 15 | //===----------------------------------------------------------------------===// 16 | 17 | #include "GrayCMain.h" 18 | 19 | int main(int argc, const char **argv) { 20 | return clang::grayc::GrayCMain(argc, argv); 21 | } 22 | -------------------------------------------------------------------------------- /grayc/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | add_library(GrayCUtils 4 | FixItHintUtils.cpp 5 | LexerUtils.cpp 6 | GrayCRandomManager.cpp 7 | ) 8 | 9 | target_link_libraries(GrayCUtils 10 | PRIVATE 11 | clangAST 12 | clangASTMatchers 13 | clangBasic 14 | clangLex 15 | clangSema 16 | clangTransformer 17 | GrayC 18 | ) 19 | -------------------------------------------------------------------------------- /grayc/utils/FixItHintUtils.h: -------------------------------------------------------------------------------- 1 | //===--- FixItHintUtils.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_FIXITHINTUTILS_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_FIXITHINTUTILS_H 11 | 12 | #include "clang/AST/ASTContext.h" 13 | #include "clang/AST/Decl.h" 14 | #include "clang/Sema/DeclSpec.h" 15 | 16 | namespace clang { 17 | namespace grayc { 18 | namespace utils { 19 | namespace fixit { 20 | 21 | /// Creates fix to make ``VarDecl`` a reference by adding ``&``. 22 | FixItHint changeVarDeclToReference(const VarDecl &Var, ASTContext &Context); 23 | 24 | /// This enum defines where the qualifier shall be preferably added. 25 | enum class QualifierPolicy { 26 | Left, // Add the qualifier always to the left side, if that is possible. 27 | Right, // Add the qualifier always to the right side. 28 | }; 29 | 30 | /// This enum defines which entity is the target for adding the qualifier. This 31 | /// makes only a difference for pointer-types. Other types behave identical 32 | /// for either value of \c ConstTarget. 33 | enum class QualifierTarget { 34 | Pointee, /// Transforming a pointer attaches to the pointee and not the 35 | /// pointer itself. For references and normal values this option has 36 | /// no effect. `int * p = &i;` -> `const int * p = &i` or `int const 37 | /// * p = &i`. 38 | Value, /// Transforming pointers will consider the pointer itself. 39 | /// `int * p = &i;` -> `int * const = &i` 40 | }; 41 | 42 | /// \brief Creates fix to qualify ``VarDecl`` with the specified \c Qualifier. 43 | /// Requires that `Var` is isolated in written code like in `int foo = 42;`. 44 | Optional 45 | addQualifierToVarDecl(const VarDecl &Var, const ASTContext &Context, 46 | DeclSpec::TQ Qualifier, 47 | QualifierTarget CT = QualifierTarget::Pointee, 48 | QualifierPolicy CP = QualifierPolicy::Left); 49 | } // namespace fixit 50 | } // namespace utils 51 | } // namespace grayc 52 | } // namespace clang 53 | 54 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_FIXITHINTUTILS_H 55 | -------------------------------------------------------------------------------- /grayc/utils/GrayCRandomManager.cpp: -------------------------------------------------------------------------------- 1 | #include "GrayCRandomManager.h" 2 | 3 | GrayCRandomManager *GrayCRandomManager::m_instance = NULL; 4 | 5 | void GrayCRandomManager::DeleteInstance(const unsigned long _seed) { 6 | assert(m_instance); 7 | delete m_instance; 8 | m_instance = NULL; 9 | } 10 | -------------------------------------------------------------------------------- /grayc/utils/GrayCRandomManager.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAYC_CUSTOM_RANDOM_H 2 | #define GRAYC_CUSTOM_RANDOM_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class GrayCRandomManager { 10 | public: 11 | static GrayCRandomManager *GetInstance(void) { 12 | assert(m_instance); 13 | return m_instance; 14 | } 15 | static void CreateInstance(const unsigned long _seed, 16 | const unsigned int _DICE_SIZE) { 17 | assert(!m_instance); 18 | m_instance = new GrayCRandomManager(_seed, _DICE_SIZE); 19 | } 20 | 21 | static void DeleteInstance(const unsigned long _seed); 22 | virtual ~GrayCRandomManager(void) {} 23 | 24 | virtual double rnd_probability() { 25 | double val = m_dist(m_rng); 26 | assert(val >= 0.0 && val <= 1.0); 27 | return val; 28 | } 29 | virtual bool rnd_yes_no(const double cut_prob) { 30 | return (m_dist(m_rng) < cut_prob); 31 | } 32 | virtual unsigned rnd_dice() { 33 | return (m_dice_generator(m_rng) % m_DICE_SIZE); 34 | } 35 | virtual unsigned rnd_dice(unsigned dice_size) { 36 | return (m_dice_generator(m_rng) % dice_size); 37 | } 38 | 39 | private: 40 | static GrayCRandomManager *m_instance; 41 | const unsigned long m_seed; 42 | const unsigned m_DICE_SIZE; 43 | 44 | std::mt19937 m_rng; // mersenne twister 45 | std::uniform_real_distribution<> m_dist; 46 | std::uniform_int_distribution<> m_dice_generator; 47 | 48 | explicit GrayCRandomManager(const unsigned long _seed, 49 | const unsigned int _DICE_SIZE) 50 | : m_seed(_seed), m_DICE_SIZE(_DICE_SIZE), m_rng(m_seed), m_dist(0.0, 1.0), 51 | m_dice_generator(0, _DICE_SIZE - 1) {} 52 | 53 | // Don't implement them 54 | GrayCRandomManager(GrayCRandomManager const &) = delete; 55 | void operator=(GrayCRandomManager const &) = delete; 56 | }; 57 | #endif // End of GRAYC_CUSTOM_RANDOM_H 58 | -------------------------------------------------------------------------------- /grayc/utils/LexerUtils.cpp: -------------------------------------------------------------------------------- 1 | //===--- LexerUtils.cpp - 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 | #include "LexerUtils.h" 10 | #include "clang/Basic/SourceManager.h" 11 | 12 | namespace clang { 13 | namespace grayc { 14 | namespace utils { 15 | namespace lexer { 16 | 17 | Token getPreviousToken(SourceLocation Location, const SourceManager &SM, 18 | const LangOptions &LangOpts, bool SkipComments) { 19 | Token Token; 20 | Token.setKind(tok::unknown); 21 | 22 | Location = Location.getLocWithOffset(-1); 23 | if (Location.isInvalid()) 24 | return Token; 25 | 26 | auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location)); 27 | while (Location != StartOfFile) { 28 | Location = Lexer::GetBeginningOfToken(Location, SM, LangOpts); 29 | if (!Lexer::getRawToken(Location, Token, SM, LangOpts) && 30 | (!SkipComments || !Token.is(tok::comment))) { 31 | break; 32 | } 33 | Location = Location.getLocWithOffset(-1); 34 | } 35 | return Token; 36 | } 37 | 38 | SourceLocation findPreviousTokenStart(SourceLocation Start, 39 | const SourceManager &SM, 40 | const LangOptions &LangOpts) { 41 | if (Start.isInvalid() || Start.isMacroID()) 42 | return SourceLocation(); 43 | 44 | SourceLocation BeforeStart = Start.getLocWithOffset(-1); 45 | if (BeforeStart.isInvalid() || BeforeStart.isMacroID()) 46 | return SourceLocation(); 47 | 48 | return Lexer::GetBeginningOfToken(BeforeStart, SM, LangOpts); 49 | } 50 | 51 | SourceLocation findPreviousTokenKind(SourceLocation Start, 52 | const SourceManager &SM, 53 | const LangOptions &LangOpts, 54 | tok::TokenKind TK) { 55 | if (Start.isInvalid() || Start.isMacroID()) 56 | return SourceLocation(); 57 | 58 | while (true) { 59 | SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); 60 | if (L.isInvalid() || L.isMacroID()) 61 | return SourceLocation(); 62 | 63 | Token T; 64 | if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true)) 65 | return SourceLocation(); 66 | 67 | if (T.is(TK)) 68 | return T.getLocation(); 69 | 70 | Start = L; 71 | } 72 | } 73 | 74 | SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, 75 | const LangOptions &LangOpts) { 76 | return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi); 77 | } 78 | 79 | Optional findNextTokenSkippingComments(SourceLocation Start, 80 | const SourceManager &SM, 81 | const LangOptions &LangOpts) { 82 | Optional CurrentToken; 83 | do { 84 | CurrentToken = Lexer::findNextToken(Start, SM, LangOpts); 85 | } while (CurrentToken && CurrentToken->is(tok::comment)); 86 | return CurrentToken; 87 | } 88 | 89 | bool rangeContainsExpansionsOrDirectives(SourceRange Range, 90 | const SourceManager &SM, 91 | const LangOptions &LangOpts) { 92 | assert(Range.isValid() && "Invalid Range for relexing provided"); 93 | SourceLocation Loc = Range.getBegin(); 94 | 95 | while (Loc < Range.getEnd()) { 96 | if (Loc.isMacroID()) 97 | return true; 98 | 99 | llvm::Optional Tok = Lexer::findNextToken(Loc, SM, LangOpts); 100 | 101 | if (!Tok) 102 | return true; 103 | 104 | if (Tok->is(tok::hash)) 105 | return true; 106 | 107 | Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts).getLocWithOffset(1); 108 | } 109 | 110 | return false; 111 | } 112 | 113 | llvm::Optional getQualifyingToken(tok::TokenKind TK, 114 | CharSourceRange Range, 115 | const ASTContext &Context, 116 | const SourceManager &SM) { 117 | assert((TK == tok::kw_const || TK == tok::kw_volatile || 118 | TK == tok::kw_restrict) && 119 | "TK is not a qualifier keyword"); 120 | std::pair LocInfo = SM.getDecomposedLoc(Range.getBegin()); 121 | StringRef File = SM.getBufferData(LocInfo.first); 122 | Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(), 123 | File.begin(), File.data() + LocInfo.second, File.end()); 124 | llvm::Optional LastMatchBeforeTemplate; 125 | llvm::Optional LastMatchAfterTemplate; 126 | bool SawTemplate = false; 127 | Token Tok; 128 | while (!RawLexer.LexFromRawLexer(Tok) && 129 | Range.getEnd() != Tok.getLocation() && 130 | !SM.isBeforeInTranslationUnit(Range.getEnd(), Tok.getLocation())) { 131 | if (Tok.is(tok::raw_identifier)) { 132 | IdentifierInfo &Info = Context.Idents.get( 133 | StringRef(SM.getCharacterData(Tok.getLocation()), Tok.getLength())); 134 | Tok.setIdentifierInfo(&Info); 135 | Tok.setKind(Info.getTokenID()); 136 | } 137 | if (Tok.is(tok::less)) 138 | SawTemplate = true; 139 | else if (Tok.isOneOf(tok::greater, tok::greatergreater)) 140 | LastMatchAfterTemplate = None; 141 | else if (Tok.is(TK)) { 142 | if (SawTemplate) 143 | LastMatchAfterTemplate = Tok; 144 | else 145 | LastMatchBeforeTemplate = Tok; 146 | } 147 | } 148 | return LastMatchAfterTemplate != None ? LastMatchAfterTemplate 149 | : LastMatchBeforeTemplate; 150 | } 151 | } // namespace lexer 152 | } // namespace utils 153 | } // namespace grayc 154 | } // namespace clang 155 | -------------------------------------------------------------------------------- /grayc/utils/LexerUtils.h: -------------------------------------------------------------------------------- 1 | //===--- LexerUtils.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 LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_LEXER_UTILS_H 10 | #define LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_LEXER_UTILS_H 11 | 12 | #include "clang/AST/ASTContext.h" 13 | #include "clang/Basic/TokenKinds.h" 14 | #include "clang/Lex/Lexer.h" 15 | 16 | namespace clang { 17 | namespace grayc { 18 | namespace utils { 19 | namespace lexer { 20 | 21 | /// Returns previous token or ``tok::unknown`` if not found. 22 | Token getPreviousToken(SourceLocation Location, const SourceManager &SM, 23 | const LangOptions &LangOpts, bool SkipComments = true); 24 | 25 | SourceLocation findPreviousTokenStart(SourceLocation Start, 26 | const SourceManager &SM, 27 | const LangOptions &LangOpts); 28 | 29 | SourceLocation findPreviousTokenKind(SourceLocation Start, 30 | const SourceManager &SM, 31 | const LangOptions &LangOpts, 32 | tok::TokenKind TK); 33 | 34 | SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM, 35 | const LangOptions &LangOpts); 36 | 37 | template 38 | SourceLocation findPreviousAnyTokenKind(SourceLocation Start, 39 | const SourceManager &SM, 40 | const LangOptions &LangOpts, 41 | TokenKind TK, TokenKinds... TKs) { 42 | if (Start.isInvalid() || Start.isMacroID()) 43 | return SourceLocation(); 44 | while (true) { 45 | SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); 46 | if (L.isInvalid() || L.isMacroID()) 47 | return SourceLocation(); 48 | 49 | Token T; 50 | // Returning 'true' is used to signal failure to retrieve the token. 51 | if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true)) 52 | return SourceLocation(); 53 | 54 | if (T.isOneOf(TK, TKs...)) 55 | return T.getLocation(); 56 | 57 | Start = L; 58 | } 59 | } 60 | 61 | template 62 | SourceLocation findNextAnyTokenKind(SourceLocation Start, 63 | const SourceManager &SM, 64 | const LangOptions &LangOpts, TokenKind TK, 65 | TokenKinds... TKs) { 66 | while (true) { 67 | Optional CurrentToken = Lexer::findNextToken(Start, SM, LangOpts); 68 | 69 | if (!CurrentToken) 70 | return SourceLocation(); 71 | 72 | Token PotentialMatch = *CurrentToken; 73 | if (PotentialMatch.isOneOf(TK, TKs...)) 74 | return PotentialMatch.getLocation(); 75 | 76 | // If we reach the end of the file, and eof is not the target token, we stop 77 | // the loop, otherwise we will get infinite loop (findNextToken will return 78 | // eof on eof). 79 | if (PotentialMatch.is(tok::eof)) 80 | return SourceLocation(); 81 | Start = PotentialMatch.getLastLoc(); 82 | } 83 | } 84 | 85 | // Finds next token that's not a comment. 86 | Optional findNextTokenSkippingComments(SourceLocation Start, 87 | const SourceManager &SM, 88 | const LangOptions &LangOpts); 89 | 90 | /// Re-lex the provide \p Range and return \c false if either a macro spans 91 | /// multiple tokens, a pre-processor directive or failure to retrieve the 92 | /// next token is found, otherwise \c true. 93 | bool rangeContainsExpansionsOrDirectives(SourceRange Range, 94 | const SourceManager &SM, 95 | const LangOptions &LangOpts); 96 | 97 | /// Assuming that ``Range`` spans a CVR-qualified type, returns the 98 | /// token in ``Range`` that is responsible for the qualification. ``Range`` 99 | /// must be valid with respect to ``SM``. Returns ``None`` if no qualifying 100 | /// tokens are found. 101 | /// \note: doesn't support member function qualifiers. 102 | llvm::Optional getQualifyingToken(tok::TokenKind TK, 103 | CharSourceRange Range, 104 | const ASTContext &Context, 105 | const SourceManager &SM); 106 | 107 | } // namespace lexer 108 | } // namespace utils 109 | } // namespace grayc 110 | } // namespace clang 111 | 112 | #endif // LLVM_CLANG_TOOLS_EXTRA_GRAYC_UTILS_LEXER_UTILS_H 113 | -------------------------------------------------------------------------------- /img/grayc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srg-imperial/GrayC/cbe5f4860283bfb44012881eae4a40e387164ca1/img/grayc-logo.png -------------------------------------------------------------------------------- /img/grayc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srg-imperial/GrayC/cbe5f4860283bfb44012881eae4a40e387164ca1/img/grayc.png -------------------------------------------------------------------------------- /scripts/LLVM-Test-suite-coverage/1-get-llvm-testsuite-single-source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | location=$1 # Where to add the tests 3 | 4 | # Create the output directory 5 | rm -rf $location 6 | mkdir $location 7 | 8 | rm -rf $location/corpus 9 | mkdir $location/corpus 10 | 11 | ## Copy from LLVM test-suite. 12 | mkdir $location/llvm-tests 13 | cd $location/llvm-tests 14 | git clone https://github.com/llvm/llvm-test-suite.git 15 | cd .. 16 | cp $location/llvm-tests/llvm-test-suite/SingleSource/Regression/C/*.c $location/corpus/ 17 | cp $location/llvm-tests/llvm-test-suite/SingleSource/Regression/C/gcc-c-torture/execute/*.c $location/corpus/ 18 | cp $location/llvm-tests/llvm-test-suite/SingleSource/Regression/C/gcc-c-torture/execute/builtins/*.c $location/corpus/ 19 | cp $location/llvm-tests/llvm-test-suite/SingleSource/Regression/C/gcc-c-torture/execute/builtins/lib/*.c $location/corpus/ 20 | rm -rf $location/llvm-tests 21 | 22 | ## Remove duplicates 23 | fdupes -dN corpus/ 24 | 25 | echo "==> Done. SingleSource files are in $location." 26 | -------------------------------------------------------------------------------- /scripts/LLVM-Test-suite-coverage/2-llvm-testsuite-reg-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shopt -s extglob # Activate extended pattern matching in bash 3 | working_folder=$1 ## base folder 4 | gfauto=$2 ## gfauto path 5 | testsuite=$3 ## Path to LLVM test suite folder 6 | i=$4 ## which copy 7 | 8 | ## Before running it, run: (1) ./0-download-git-llvm-wt-rt.sh /home/user42 11 and (2) ./1-install-csmith-llvm-ninja-cov.sh /home/user42 /home/user42/.sources.mhAmsGY.tmp 11 9 | ## put in comment: add_subdirectory(sqlite3) and add_subdirectory(XRay) 10 | ## test-suite/MultiSource/Applications/CMakeLists.txt 11 | ## test-suite/CTMark/CMakeLists.txt 12 | ## test-suite/MicroBenchmarks/CMakeLists.txt 13 | 14 | ######## 15 | llvm_folder=$working_folder/llvm-csmith-$i 16 | gcda=$llvm_folder/coverage_gcda_files 17 | cov_processed=$llvm_folder/coverage_processed 18 | tests_build=$llvm_folder/test-suite-build 19 | comp_info=$llvm_folder/compilation_info 20 | ######## 21 | rm -rf $gcda/ 22 | rm -rf $cov_processed/ 23 | 24 | ## Save information regarding the version and how we compile it 25 | cd $comp_info 26 | echo " - date: $(date '+%Y-%m-%d at %H:%M.%S')" > $comp_info/llvm-test-suite-version.txt 27 | echo " - host name $(hostname -f)" >> $comp_info/llvm-test-suite-version.txt 28 | echo " - current path: $(pwd)" >> $comp_info/llvm-test-suite-version.txt 29 | gcc-11 --version >> $comp_info/llvm-test-suite-version.txt; g++-11 --version >> $comp_info/llvm-test-suite-version.txt; gcov-11 --version >> $comp_info/llvm-test-suite-version.txt; cpp-11 --version >> $comp_info/llvm-test-suite-version.txt; /usr/bin/cc --version >> $comp_info/llvm-test-suite-version.txt; /usr/bin/c++ --version >> $comp_info/llvm-test-suite-version.txt 30 | 31 | Ccompiler="$llvm_folder/llvm-install/usr/local/bin/clang" 32 | CXXcompiler="$llvm_folder/llvm-install/usr/local/bin/clang++" 33 | 34 | ## Set env. and compile to get coverage 35 | ( 36 | mkdir -p $gcda/application_run # Created once, to aggregate coverage from all configurations 37 | echo " - Creating temp output folder: <$gcda/application_run>" 38 | 39 | # LOOP over all configurations and collect coverage 40 | declare -a arr=("O3.cmake" "O0.cmake" "Os.cmake" "Oz.cmake" "ReleaseNoLTO.cmake" "Debug.cmake" ) 41 | 42 | k=0 43 | for j in "${arr[@]}" ; do 44 | k=$((k+1)) 45 | # Cmake and build of the LLVM Test-suite 46 | cd $llvm_folder 47 | rm -rf $tests_build/ 48 | mkdir $tests_build 49 | cd $tests_build 50 | 51 | set CXX=$CXXcompiler 52 | set CC=$Ccompiler 53 | time1=$(date +"%T") 54 | echo " --> Configure LLVM test-suite with cmake to $tests_build... ("$time1")" 55 | echo "Configuration: cmake -DCMAKE_C_COMPILER=$llvm_folder/llvm-build/bin/clang -C $testsuite/cmake/caches/$j $testsuite" > $comp_info/llvm-test-suite-version-$i-$k.txt 56 | cmake -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_C_COMPILER="$Ccompiler" -DCMAKE_CXX_COMPILER="$CXXcompiler" -C "$testsuite/cmake/caches/$j" $testsuite > $comp_info/config_test-suite_output-$i-$k.txt 2>&1 57 | 58 | # Run compiler and save coverage data 59 | time2=$(date +"%T") 60 | echo " --> Build LLVM test-suite with cmake to $tests_build... ("$time2")" 61 | 62 | export GCOV_PREFIX=$gcda/application_run 63 | make > $comp_info/build_test-suite_output-$i-$k.txt 2>&1 64 | 65 | # Cleaning after build 66 | unset GCOV_PREFIX 67 | unset CC 68 | unset CXX 69 | 70 | 71 | ## Measure Coverage 72 | time3=$(date +"%T") 73 | echo " --> MEASURING COVERAGE... ("$time3")" 74 | cd $llvm_folder 75 | mkdir -p $cov_processed/x-line-$i-$k 76 | mkdir -p $cov_processed/x-func-$i-$k 77 | 78 | # Venv. start 79 | ( 80 | source $gfauto/.venv/bin/activate 81 | 82 | ## FUNCTION COVERAGE ## 83 | cd $cov_processed/x-func-$i-$k 84 | #gfauto_cov_from_gcov --out run_gcov2cov.cov $llvm_folder/llvm-build/ $gcda/application_run/ --num_threads 32 --gcov_uses_json --gcov_functions >> gfauto.log 2>&1 85 | gfauto_cov_from_gcov --out run_gcov2cov.cov $llvm_folder/llvm-build/ --gcov_prefix_dir $gcda/application_run/ --num_threads 32 --gcov_uses_json --gcov_functions >> gfauto.log 2>&1 86 | gfauto_cov_to_source --coverage_out cov.out --cov run_gcov2cov.cov $llvm_folder/llvm-build/ >> gfauto.log 2>&1 87 | 88 | ## LINE COVERAGE ## 89 | cd $cov_processed/x-line-$i-$k 90 | #gfauto_cov_from_gcov --out run_gcov2cov.cov $llvm_folder/llvm-build/ $gcda/application_run/ --num_threads 32 --gcov_uses_json >> gfauto.log 2>&1 91 | gfauto_cov_from_gcov --out run_gcov2cov.cov $llvm_folder/llvm-build/ --gcov_prefix_dir $gcda/application_run/ --num_threads 32 --gcov_uses_json >> gfauto.log 2>&1 92 | gfauto_cov_to_source --coverage_out cov.out --cov run_gcov2cov.cov $llvm_folder/llvm-build/ >> gfauto.log 2>&1 93 | ) 94 | cd $current_folder 95 | done 96 | ) 97 | # End of Loop 98 | ls -l $cov_processed/x-line-$i-* 99 | ls -l $cov_processed/x-func-$i-* 100 | echo " ## DONE. ##" 101 | -------------------------------------------------------------------------------- /scripts/LLVM-Test-suite-coverage/README.md: -------------------------------------------------------------------------------- 1 | # The LLVM test suite 2 | 3 | There are two parts relevant to GrayC in the LLVM test suite. 4 | 5 | - Single source folders: we use these as part of GrayC initial corpus. 6 | - The whole LLVM test suite: we use this to compare GrayC performance and to locate under tested part of the compiler. 7 | 8 | Requirement: download and build from source LLVM 15 with compiler-rt and clang parts. You can find how to do so [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/coverage). 9 | 10 | ## Single tests of the LLVM test suite 11 | To download LLVM's single source tests, use this script: 12 | ``` 13 | sudo apt install fdupes ## if not yet installed 14 | ./1-get-llvm-testsuite-single-source.sh 15 | ``` 16 | You can then measure coverage for this folder as with any other folder of tests as explained [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/coverage). 17 | 18 | ## The Whole LLVM Test suite 19 | 20 | First, download the LLVM test suite: 21 | ``` 22 | git clone https://github.com/llvm/llvm-test-suite.git 23 | ``` 24 | into your base-folder. 25 | 26 | For the LLVM test suite: use this script to measure coverage for the whole llvm test suite: 27 | ``` 28 | ./2-llvm-testsuite-reg-cov.sh 15 29 | ``` 30 | with LLVM 15. If you wish to use it with a different version, then replace the 15 with it. 31 | 32 | Before using these scripts you will need to build LLVM with rt. You can find instructions [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/coverage). 33 | 34 | ## Coverage statistics of the Back-, Middle- and Front-end of the LLVM code base 35 | 36 | These scripts are pretty ad-hoc for LLVM 13. You can find these [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/LLVM-Test-suite-coverage/llvm-cov-sub-folders). 37 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts of GrayC 2 | 3 | We are preparing a set of README files for the scripts that are part of GrayC. We update below which folders are ready to use. 4 | 5 | - general: contains scripts to get LLVM and GCC source code. 6 | - LLVM-Test-suite-coverage: scripts were specifically written to the LLVM code base for downloading the LLVM test suites or parts of it and to measure coverage. 7 | 8 | -------------------------------------------------------------------------------- /scripts/coverage/0-install-gcc-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shopt -s extglob # Activate extended pattern matching in bash 3 | 4 | working_folder=$1 # e.g. /home/user42/coverage 5 | TMP_SOURCE_FOLDER=$2 # Input from 0- script 6 | nb_processes=1 # Cannot really be controlled because of how we build gcc 7 | current_folder=`pwd` # current folder 8 | 9 | cd $current_folder 10 | # Copying GCC source and Csmith exe to parallel execution folders, then install GCC with coverage data in each folder 11 | i=0 # compile a basic one - never to use. 12 | while (( $i <= $nb_processes )); 13 | do 14 | ## Start loop i 15 | echo ">> Copy gcc folder-$i of gcc" 16 | 17 | ### Create a working folder with GCC source 18 | rm -rf $working_folder/gcc-csmith-$i ## Remove the old version 19 | mkdir $working_folder/gcc-csmith-$i ## Create a new version 20 | cp -r $TMP_SOURCE_FOLDER/* $working_folder/gcc-csmith-$i ## Copy the data from the temp download folder 21 | 22 | ### Update Csmith settings 23 | cd $working_folder/gcc-csmith-$i 24 | mkdir -p ./csmith/scripts/ 25 | echo $working_folder/gcc-csmith-$i"/gcc-build/gcc/xgcc -B"$working_folder/gcc-csmith-$i"/gcc-build/gcc/. -O3" > ./csmith/scripts/compiler_test.in 26 | 27 | ### GCC PART: with instrumentation 28 | # Setting the env. + cov. and keeping information of the versions 29 | cd $working_folder/gcc-csmith-$i; mkdir compilation_info; mv $working_folder/gcc-csmith-$i/gcc $working_folder/gcc-csmith-$i/gcc-source 30 | cd gcc-source; git status > $working_folder/gcc-csmith-$i/compilation_info/git_info.txt; git log | head -10 >> $working_folder/gcc-csmith-$i/compilation_info/git_info.txt 31 | gcc --version > $working_folder/gcc-csmith-$i/compilation_info/gcc-version.txt; g++ --version >> $working_folder/gcc-csmith-$i/compilation_info/gcc-version.txt; gcov --version >> $working_folder/gcc-csmith-$i/compilation_info/gcc-version.txt; cpp --version >> $working_folder/gcc-csmith-$i/compilation_info/gcc-version.txt 32 | cd $working_folder/gcc-csmith-$i ## Assure we are now here. 33 | 34 | ## Finish settings and moving files 35 | echo ">> gcc folder-$i is set" 36 | 37 | if (( 0 < $i )); then 38 | ## Compile with coverage 39 | ( 40 | ## Set output folders 41 | TMP_GCOV_FOLDER=$(mktemp -d .sources_gcc.XXXXXXX.tmp) 42 | mkdir -p $TMP_GCOV_FOLDER/coverage_gcda_files/application_run-init 43 | mkdir gcc-build gcc-install 44 | cd ./gcc-build 45 | 46 | ## Assure we are using the built gcc: 47 | ( 48 | usrLib=$working_folder/gcc-csmith-0/gcc-install 49 | sudo rm -f /usr/bin/cpp /usr/bin/gcc /usr/bin/g++ /usr/bin/gcov 50 | sudo rm -f /usr/local/bin/cpp /usr/local/bin/gcc /usr/local/bin/g++ /usr/local/bin/gcov 51 | sudo ln -s $usrLib/bin/cpp /usr/bin/cpp 52 | sudo ln -s $usrLib/bin/gcc /usr/bin/gcc 53 | sudo ln -s $usrLib/bin/g++ /usr/bin/g++ 54 | sudo ln -s $usrLib/bin/gcov /usr/bin/gcov 55 | ) 56 | 57 | # Covarage flags: 58 | export GCOV_PREFIX=$TMP_GCOV_FOLDER/coverage_gcda_files/application_run-init ## Send gcda of build to temp. 59 | export GCOV_PREFIX_STRIP=0 60 | export CFLAGS='-g -O0 --coverage -ftest-coverage -fprofile-arcs' 61 | export CXXFLAGS='-g -O0 --coverage -ftest-coverage -fprofile-arcs' 62 | export LDFLAGS='-lgcov --coverage -ftest-coverage -fprofile-arcs' 63 | 64 | ./../gcc-source/configure --disable-multilib --disable-bootstrap --disable-install-libiberty --enable-coverage=noopt --enable-targets='X86' --enable-languages='c,c++,lto,objc,obj-c++' --with-gmp=/tmp/gcc/ --with-mpfr=/tmp/gcc/ --with-mpc=/tmp/gcc/ --with-isl=/tmp/isl --prefix=$working_folder/gcc-csmith-$i/gcc-install/ CFLAGS_FOR_TARGET='-g -O0 --coverage -ftest-coverage -fprofile-arcs' CXXFLAGS_FOR_TARGET='-g -O0 --coverage -ftest-coverage -fprofile-arcs' > $working_folder/gcc-csmith-$i/compilation_info/config_output.txt 2>&1 65 | 66 | make -j$(nproc) > $working_folder/gcc-csmith-$i/compilation_info/build_output.txt 2>&1 67 | make -j$(nproc) install > $working_folder/gcc-csmith-$i/compilation_info/install_output.txt 2>&1 68 | #### WE KEEP build, install and source folders sperated. #### 69 | 70 | # Cleaning after build 71 | rm -rf $TMP_GCOV_FOLDER 72 | unset CFLAGS 73 | unset CXXFLAGS 74 | unset LDFLAGS 75 | unset GCOV_PREFIX 76 | unset GCOV_PREFIX_STRIP 77 | ) 78 | ## Shall be here: cd $working_folder/gcc-csmith-$i/gcc 79 | cd $working_folder/gcc-csmith-$i/gcc-source 80 | 81 | ## Remove other languages: brig, fortran, go, d 82 | rm -rf libgfortran # FORTRAN 83 | rm -rf libgo gotools # GO 84 | rm -rf libphobos # D (also GDC is D) 85 | rm -rf libada # ADA 86 | ## Remove testsuite folders (gcc does not include these into coverage) 87 | rm -rf gcc/testsuite libatomic/testsuite libffi/testsuite libgomp/testsuite libiberty/testsuite libitm/testsuite 88 | rm -rf libstdc++-v3/testsuite libvtv/testsuite 89 | 90 | # stat for core: 91 | c1=`find $working_folder/gcc-csmith-$i/gcc-source/ -name *.c | wc -l` 92 | c2=`find $working_folder/gcc-csmith-$i/gcc-source/ -name *.h | wc -l` 93 | c3=`find $working_folder/gcc-csmith-$i/gcc-build/ -name *.gcno | wc -l` 94 | c4=`find $working_folder/gcc-csmith-$i/gcc-build/ -name *.gcda | wc -l` 95 | echo ">> Built GCC in $working_folder/gcc-csmith-$i/gcc-build/, installed in $working_folder/gcc-csmith-$i/gcc-install/." 96 | echo ">> Compilation info. in $working_folder/gcc-csmith-$i/compilation_info/." 97 | echo ">> Total ($c1) C-files, ($c2) header files, ($c3) gcno files, ($c4) gcda files." 98 | find $working_folder/gcc-csmith-$i/gcc-source/ -name *.c > $working_folder/gcc-csmith-$i/compilation_info/gcc_c_files.txt 99 | find $working_folder/gcc-csmith-$i/gcc-source/ -name *.h > $working_folder/gcc-csmith-$i/compilation_info/gcc_h_files.txt 100 | find $working_folder/gcc-csmith-$i/gcc-build/ -name *.gcno > $working_folder/gcc-csmith-$i/compilation_info/gcc_gcno_files.txt 101 | find . -name *.gcda -exec rm -rf {} \; 102 | echo " --> Removed $c4 gcda files." 103 | #### TESTS #### 104 | else 105 | ## Compile without coverage 106 | ( 107 | ## Set output folders 108 | mkdir gcc-build ; mkdir gcc-install 109 | cd ./gcc-build 110 | 111 | ## Config, compile and install: 112 | ./../gcc-source/configure --disable-multilib --disable-bootstrap --disable-install-libiberty --enable-targets='X86' --enable-languages='c,c++,lto,objc,obj-c++' --with-gmp=/tmp/gcc --with-mpfr=/tmp/gcc --with-mpc=/tmp/gcc --with-isl=/tmp/isl --prefix=$working_folder/gcc-csmith-$i/gcc-install/ > $working_folder/gcc-csmith-$i/compilation_info/config_output.txt 2>&1 113 | 114 | make -j$(nproc) > $working_folder/gcc-csmith-$i/compilation_info/build_output.txt 2>&1 115 | make -j$(nproc) install > $working_folder/gcc-csmith-$i/compilation_info/install_output.txt 2>&1 116 | #### WE KEEP build, install and source folders sperated. #### 117 | ) 118 | fi 119 | 120 | ## Zip it with soft links - unzip with h option: tar -xhzvf gcc-csmith-0.tar.gz 121 | cd $working_folder 122 | tar -czvf gcc-csmith-$i.tar.gz gcc-csmith-$i/ > $working_folder/tar_me-$i.txt 2>&1 123 | # Next core 124 | i=$(($i+1)) 125 | done 126 | 127 | ## Revert back all gcc changes: 128 | sudo rm -f /usr/bin/cpp /usr/bin/gcc /usr/bin/g++ /usr/bin/gcov 129 | sudo rm -f /usr/local/bin/cpp /usr/local/bin/gcc /usr/local/bin/g++ /usr/local/bin/gcov 130 | sudo ln -s /usr/bin/cpp-10 /usr/bin/cpp 131 | sudo ln -s /usr/bin/gcc-10 /usr/bin/gcc 132 | sudo ln -s /usr/bin/g++-10 /usr/bin/g++ 133 | sudo ln -s /usr/bin/gcov-10 /usr/bin/gcov 134 | 135 | #rm -rf $TMP_SOURCE_FOLDER 136 | -------------------------------------------------------------------------------- /scripts/coverage/0-install-llvm-cov-rt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shopt -s extglob # Activate extended pattern matching in bash 3 | 4 | #### This is a version for using LLVM with re-compilation of code with asserts(0) #### 5 | #### First time will take longer, but re-build is quick. No coverage. #### 6 | 7 | working_folder=$1 ## base folder 8 | TMP_SOURCE_FOLDER=$2 ## Where is your llvm source code? 9 | nb_processes=$3 ## which copy? 10 | 11 | ## Assure we are in gcc-11! 12 | sudo apt install gcc-11 g++-11 13 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 1100 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 14 | sudo rm -f /usr/bin/c++ /usr/bin/cpp /usr/bin/gcc /usr/bin/g++ /usr/bin/gcov 15 | sudo rm -f /usr/local/bin/c++ /usr/local/bin/cpp /usr/local/bin/gcc /usr/local/bin/g++ /usr/local/bin/gcov 16 | sudo ln -s /usr/bin/cpp-11 /usr/bin/cpp 17 | sudo ln -s /usr/bin/gcc-11 /usr/bin/gcc 18 | sudo ln -s /usr/bin/g++-11 /usr/bin/g++ 19 | sudo ln -s /usr/bin/g++-11 /usr/bin/c++ 20 | sudo ln -s /usr/bin/gcov-11 /usr/bin/gcov 21 | echo ">> End Settings" 22 | 23 | timeB=$(date +"%T") 24 | echo ">> Start Script <$timeB>" 25 | 26 | # Copying LLVM source and Csmith exe to parallel execution folders, then install LLVM with coverage data in each folder 27 | i=$nb_processes 28 | 29 | ### Create a working folder with LLVM source 30 | rm -rf $working_folder/llvm-csmith-$i ## Remove the old version 31 | mkdir $working_folder/llvm-csmith-$i ## Create a new version 32 | cp -rf $TMP_SOURCE_FOLDER/* $working_folder/llvm-csmith-$i ## Copy the data from the temp download folder 33 | 34 | ### Update Csmith settings 35 | mkdir -p $working_folder/llvm-csmith-$i/csmith/scripts/ ## Just incase it isn't there 36 | cd $working_folder/llvm-csmith-$i 37 | mkdir -p ./csmith/scripts/ 38 | echo $working_folder/llvm-csmith-$i"/llvm-install/usr/local/bin/clang -O3" > $working_folder/llvm-csmith-$i/csmith/scripts/compiler_test.in 39 | 40 | ## Save information regarding the version and how we compile it 41 | mkdir compilation_info 42 | echo " - date: $(date '+%Y-%m-%d at %H:%M.%S')" > $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 43 | echo " - host name $(hostname -f)" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 44 | echo " - current path: $(pwd)" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 45 | gcc-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 46 | g++-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 47 | gcov-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 48 | cpp-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 49 | /usr/bin/cc --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 50 | /usr/bin/c++ --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 51 | 52 | mv llvm-project llvm-source 53 | ### LLVM PART: with instrumentation 54 | # Setting the env. + cov. 55 | { 56 | mkdir llvm-build llvm-install 57 | cd ./llvm-build 58 | 59 | set CFLAGS='--coverage -ftest-coverage -fprofile-arcs -fno-inline' 60 | set CXXFLAGS='--coverage -ftest-coverage -fprofile-arcs -fno-inline' 61 | set LDFLAGS='-lgcov --coverage -ftest-coverage -fprofile-arcs' 62 | set CXX=g++-11 63 | set CC=gcc-11 64 | 65 | # Cmake and build of LLVM 66 | timeS=$(date +"%T") 67 | echo "Configuration: cmake -G Ninja -Wall ../llvm-source/llvm/ -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_BUILD_DOCS=OFF -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_EXE_LINKER_FLAGS=--coverage -Wno-dev <$timeS>" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 68 | cmake -G Ninja -Wall ../llvm-source/llvm/ -DLLVM_ENABLE_PROJECTS='clang;compiler-rt' -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_INCLUDE_TESTS="OFF" -DLLVM_INCLUDE_DOCS="OFF" -DLLVM_INCLUDE_BENCHMARKS="OFF" -DLLVM_BUILD_EXAMPLES="OFF" -DLLVM_BUILD_TESTS="OFF" -DLLVM_BUILD_DOCS="OFF" -DCMAKE_C_FLAGS="--coverage" -DCMAKE_CXX_FLAGS="--coverage" -DCMAKE_EXE_LINKER_FLAGS="--coverage" -Wno-dev > $working_folder/llvm-csmith-$i/compilation_info/config_output.txt 2>&1 69 | 70 | timeB=$(date +"%T") 71 | echo ">> Build LLVM with ninja to ./llvm-build <$timeB>" 72 | 73 | ninja > $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 2>&1 74 | ninja check-clang >> $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 2>&1 75 | grep "FAILED:" $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 76 | timeI=$(date +"%T") 77 | echo ">> Install LLVM locallly with ninja to ./llvm-install <$timeI>" 78 | DESTDIR=../llvm-install ninja install -k 10 > $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 2>&1 79 | grep "FAILED:" $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 80 | 81 | # Cleaning after build 82 | unset CFLAGS 83 | unset CXXFLAGS 84 | unset LDFLAGS 85 | unset CXX 86 | unset CC 87 | } 88 | cd .. ; cd .. 89 | timeT=$(date +"%T") 90 | echo ">> Create .tar of LLVM local installation <$timeT>" 91 | tar -czvf llvm-csmith-$i.tar.gz llvm-csmith-$i/ >> $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 2>&1 92 | timeE=$(date +"%T") 93 | echo "Done. <$timeE>" 94 | -------------------------------------------------------------------------------- /scripts/coverage/0-install-llvm-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shopt -s extglob # Activate extended pattern matching in bash 3 | 4 | #### This is a version for using LLVM with re-compilation of code with asserts(0) #### 5 | #### First time will take longer, but re-build is quick. No coverage. #### 6 | 7 | working_folder=$1 ## base folder 8 | TMP_SOURCE_FOLDER=$2 ## Where is your llvm source code? 9 | nb_processes=$3 ## which copy? 10 | 11 | ## Assure we are in gcc-11! 12 | sudo apt install gcc-11 g++-11 13 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 1100 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 14 | sudo rm -f /usr/bin/c++ /usr/bin/cpp /usr/bin/gcc /usr/bin/g++ /usr/bin/gcov 15 | sudo rm -f /usr/local/bin/c++ /usr/local/bin/cpp /usr/local/bin/gcc /usr/local/bin/g++ /usr/local/bin/gcov 16 | sudo ln -s /usr/bin/cpp-11 /usr/bin/cpp 17 | sudo ln -s /usr/bin/gcc-11 /usr/bin/gcc 18 | sudo ln -s /usr/bin/g++-11 /usr/bin/g++ 19 | sudo ln -s /usr/bin/g++-11 /usr/bin/c++ 20 | sudo ln -s /usr/bin/gcov-11 /usr/bin/gcov 21 | echo ">> End Settings" 22 | 23 | timeB=$(date +"%T") 24 | echo ">> Start Script <$timeB>" 25 | 26 | # Copying LLVM source and Csmith exe to parallel execution folders, then install LLVM with coverage data in each folder 27 | i=$nb_processes 28 | 29 | ### Create a working folder with LLVM source 30 | rm -rf $working_folder/llvm-csmith-$i ## Remove the old version 31 | mkdir $working_folder/llvm-csmith-$i ## Create a new version 32 | cp -rf $TMP_SOURCE_FOLDER/* $working_folder/llvm-csmith-$i ## Copy the data from the temp download folder 33 | 34 | ### Update Csmith settings 35 | mkdir -p $working_folder/llvm-csmith-$i/csmith/scripts/ ## Just incase it isn't there 36 | cd $working_folder/llvm-csmith-$i 37 | mkdir -p ./csmith/scripts/ 38 | echo $working_folder/llvm-csmith-$i"/llvm-install/usr/local/bin/clang -O3" > $working_folder/llvm-csmith-$i/csmith/scripts/compiler_test.in 39 | 40 | ## Save information regarding the version and how we compile it 41 | mkdir compilation_info 42 | echo " - date: $(date '+%Y-%m-%d at %H:%M.%S')" > $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 43 | echo " - host name $(hostname -f)" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 44 | echo " - current path: $(pwd)" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 45 | gcc-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 46 | g++-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 47 | gcov-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 48 | cpp-11 --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 49 | /usr/bin/cc --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 50 | /usr/bin/c++ --version >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 51 | 52 | mv llvm-project llvm-source 53 | ### LLVM PART: with instrumentation 54 | # Setting the env. + cov. 55 | { 56 | mkdir llvm-build llvm-install 57 | cd ./llvm-build 58 | 59 | set CFLAGS='--coverage -ftest-coverage -fprofile-arcs -fno-inline' 60 | set CXXFLAGS='--coverage -ftest-coverage -fprofile-arcs -fno-inline' 61 | set LDFLAGS='-lgcov --coverage -ftest-coverage -fprofile-arcs' 62 | set CXX=g++-11 63 | set CC=gcc-11 64 | 65 | # Cmake and build of LLVM 66 | timeS=$(date +"%T") 67 | echo "Configuration: cmake -G Ninja -Wall ../llvm-source/llvm/ -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_EXAMPLES=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_BUILD_DOCS=OFF -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_EXE_LINKER_FLAGS=--coverage -Wno-dev <$timeS>" >> $working_folder/llvm-csmith-$i/compilation_info/llvm-version.txt 68 | cmake -G Ninja -Wall ../llvm-source/llvm/ -DLLVM_ENABLE_PROJECTS='clang' -DCMAKE_C_COMPILER=gcc-11 -DCMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_INCLUDE_TESTS="OFF" -DLLVM_INCLUDE_DOCS="OFF" -DLLVM_INCLUDE_BENCHMARKS="OFF" -DLLVM_BUILD_EXAMPLES="OFF" -DLLVM_BUILD_TESTS="OFF" -DLLVM_BUILD_DOCS="OFF" -DCMAKE_C_FLAGS="--coverage" -DCMAKE_CXX_FLAGS="--coverage" -DCMAKE_EXE_LINKER_FLAGS="--coverage" -Wno-dev > $working_folder/llvm-csmith-$i/compilation_info/config_output.txt 2>&1 69 | 70 | timeB=$(date +"%T") 71 | echo ">> Build LLVM with ninja to ./llvm-build <$timeB>" 72 | 73 | ninja > $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 2>&1 74 | ninja check-clang >> $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 2>&1 75 | grep "FAILED:" $working_folder/llvm-csmith-$i/compilation_info/build_output.txt 76 | timeI=$(date +"%T") 77 | echo ">> Install LLVM locallly with ninja to ./llvm-install <$timeI>" 78 | DESTDIR=../llvm-install ninja install -k 10 > $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 2>&1 79 | grep "FAILED:" $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 80 | 81 | # Cleaning after build 82 | unset CFLAGS 83 | unset CXXFLAGS 84 | unset LDFLAGS 85 | unset CXX 86 | unset CC 87 | } 88 | cd .. ; cd .. 89 | timeT=$(date +"%T") 90 | echo ">> Create .tar of LLVM local installation <$timeT>" 91 | tar -czvf llvm-csmith-$i.tar.gz llvm-csmith-$i/ >> $working_folder/llvm-csmith-$i/compilation_info/install_output.txt 2>&1 92 | timeE=$(date +"%T") 93 | echo "Done. <$timeE>" 94 | -------------------------------------------------------------------------------- /scripts/coverage/0-set-gcov-version.sh: -------------------------------------------------------------------------------- 1 | ## Assure we are in gcc-11! 2 | sudo apt install gcc-11 g++-11 3 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 1100 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 4 | sudo rm -f /usr/bin/c++ /usr/bin/cpp /usr/bin/gcc /usr/bin/g++ /usr/bin/gcov 5 | sudo rm -f /usr/local/bin/c++ /usr/local/bin/cpp /usr/local/bin/gcc /usr/local/bin/g++ /usr/local/bin/gcov 6 | sudo ln -s /usr/bin/cpp-11 /usr/bin/cpp 7 | sudo ln -s /usr/bin/gcc-11 /usr/bin/gcc 8 | sudo ln -s /usr/bin/g++-11 /usr/bin/g++ 9 | sudo ln -s /usr/bin/g++-11 /usr/bin/c++ 10 | sudo ln -s /usr/bin/gcov-11 /usr/bin/gcov 11 | echo ">> End Settings" 12 | -------------------------------------------------------------------------------- /scripts/coverage/1-wrapper-get-coverage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | base=$1 # /home/user42 3 | testcaseDir=$2 # where is basic.c 4 | process_number=$3 # 5 5 | itr=$4 # 0 6 | csmith_location=$5 # Where are the runtime folder of csmith 7 | gfauto=$6 # gfauto location, e.g., /home/user42/git/graphicsfuzz/gfauto 8 | output_table_file_func=$7 # Where to dump the results (table of the results per file int the working_folder 9 | output_table_file_line=$8 # Where to dump the results (table of the results per file int the working_folder 10 | output_report=$9 # Where to print the summary report to 11 | compiler=${10} # llvm or gcc? 12 | gfauto_old_version=${11} # Is old or new version of gfauto 13 | working_folder=$base/$compiler-csmith-$process_number # the llvm or gcc installation we will measure coverage for 14 | ## E.g., ./1-wrapper-get-coverage.sh /home/user42 /home/user42/git/data/reduced/corpus_all_v1_2021-02-15 5 0 /home/user42/git/csmith /home/user42/git/graphicsfuzz/gfauto func_cov_v1.csv line_cov_v1.csv coverage_summary_v1.log gcc 0 15 | ## ./1-wrapper-get-coverage.sh /home/user42 /home/user42/Documents/cov_float 5 0 /home/user42/git/csmith /home/user42/git/graphicsfuzz/gfauto func_cov_v1.csv line_cov_v1.csv coverage_summary_v1.log llvm 0 16 | 17 | ## Print inputs: 18 | echo "base:=$base" 19 | echo "testcaseDir:=$testcaseDir" 20 | echo "process_number:=$process_number" 21 | echo "itr:=$itr" 22 | echo "csmith_location:=$csmith_location" 23 | echo "gfauto:=$gfauto" 24 | echo "output_table_file_func:=$output_table_file_func" 25 | echo "output_table_file_line:=$output_table_file_line" 26 | echo "output_report:=$output_report" 27 | echo "compiler:=$compiler" 28 | echo "gfauto_old_version:=$gfauto_old_version" 29 | echo "working_folder:=$working_folder" 30 | 31 | ## Cleaning: 32 | rm -f $output_table_file_func $output_table_file_line $output_report 33 | 34 | ## Add .c to all files 35 | echo "Prepare folder" 36 | (./coverage-sub-scripts/0-prepare-folder.sh $testcaseDir) 37 | 38 | ## if gcc set the env. 39 | if [[ "$compiler" == "gcc" ]]; then 40 | (./coverage-sub-scripts/2-pre-gcc-cov-run.sh $base $compiler $process_number) 41 | fi 42 | 43 | ## Compute the coverage from gcov files 44 | echo "Compute coverage" 45 | (./coverage-sub-scripts/2-compute-coverage_DIR_gfauto.sh $base $testcaseDir $process_number $itr $csmith_location $gfauto $compiler $gfauto_old_version) 46 | 47 | ## if gcc set the env. 48 | if [[ "$compiler" == "gcc" ]]; then 49 | (./coverage-sub-scripts/2-post-gcc-cov-run.sh) 50 | fi 51 | 52 | ## Add the total of files in COV reports 53 | files_no=`ls -l $testcaseDir | wc -l` 54 | echo ">> Total of files in coverage report: $files_no" >> $output_report 55 | 56 | ## Report for function coverage 57 | echo "Get statistics for functions" 58 | cov_func=$working_folder/coverage_processed/x-func-$process_number-$itr/cov.out/ 59 | (./coverage-sub-scripts/3-gen-statistic-gcov-diff-tab_gfauto.sh "$cov_func" $output_table_file_func >> $output_report) 60 | 61 | ## Report for line coverage 62 | echo "Get statistics for lines" 63 | cov_line=$working_folder/coverage_processed/x-line-$process_number-$itr/cov.out/ 64 | (./coverage-sub-scripts/3-gen-statistic-gcov-diff-tab_gfauto.sh "$cov_line" $output_table_file_line >> $output_report) 65 | -------------------------------------------------------------------------------- /scripts/coverage/4-cov-stat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | base=$1 # /home/user42 3 | process_number=$2 # 5 4 | itr=$3 # 0 5 | output_table_file_func=$4 # Where to dump the results (table of the results per file int the working_folder 6 | output_table_file_line=$5 # Where to dump the results (table of the results per file int the working_folder 7 | output_report=$6 # Where to print the summary report to 8 | 9 | working_folder=$base/$compiler-csmith-$process_number # the llvm or gcc installation we will measure coverage for 10 | ## ./4-cov-stat.sh /home/user42 15x 6 func_cov_v1.csv line_cov_v1.csv coverage_summary_v1.log 11 | 12 | ## Print inputs: 13 | echo "base:=$base" 14 | echo "process_number:=$process_number" 15 | echo "itr:=$itr" 16 | echo "output_table_file_func:=$output_table_file_func" 17 | echo "output_table_file_line:=$output_table_file_line" 18 | echo "output_report:=$output_report" 19 | echo "working_folder:=$working_folder" 20 | 21 | ## Report for function coverage 22 | echo "Get statistics for functions" 23 | cov_func=$working_folder/coverage_processed/x-func-$process_number-$itr/cov.out/ 24 | (./coverage-sub-scripts/3-gen-statistic-gcov-diff-tab_gfauto.sh "$cov_func" $output_table_file_func >> $output_report) 25 | 26 | ## Report for line coverage 27 | echo "Get statistics for lines" 28 | cov_line=$working_folder/coverage_processed/x-line-$process_number-$itr/cov.out/ 29 | (./coverage-sub-scripts/3-gen-statistic-gcov-diff-tab_gfauto.sh "$cov_line" $output_table_file_line >> $output_report) 30 | -------------------------------------------------------------------------------- /scripts/coverage/README.md: -------------------------------------------------------------------------------- 1 | # Coverage Scripts 2 | 3 | To use these scripts to measure coverage for GrayC follow the steps below. 4 | 5 | ## Software Requirements 6 | 7 | *For installing from source,* you will need to install the following: gcc, gcov, g++, flex, bison, binutils, git, python3, python3-pip, gfauto (under Google's graphicsfuzz), cmake, m4, ninja-build, curl, wget, zip, unzip, frama-c, creduce, openSSL (libcurl4-openssl-dev, libssl-dev). Commonly these packages are installed if you work with compilers' source code. 8 | 9 | Note 1: CMake 3.13.4 or higher is required. 10 | 11 | Note 2: GCC-11 is required. 12 | 13 | Note 3: gfauto: https://github.com/google/graphicsfuzz.git 14 | 15 | ### gfauto tool 16 | If you don't have gfauto installed, please follow the instructions here: https://github.com/google/graphicsfuzz. 17 | You can try the following instructions we used to set up the tool: 18 | ``` 19 | git clone https://github.com/google/graphicsfuzz.git 20 | cd graphicsfuzz/gfauto/ 21 | vi dev_shell.sh.template 22 | EDIT TO YOUR LOCAL VERSION of Python3: PYTHON=${PYTHON-python3.6} 23 | rm Pipfile.lock (if Python3.8 or above) 24 | ./dev_shell.sh.template 25 | ``` 26 | 27 | ## Download GCC and LLVM source code 28 | 29 | Follow the instructions [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/general). 30 | 31 | ## LLVM Code Coverage 32 | 33 | To build a copy of LLVM with coverage use this script: 34 | ``` 35 | ./0-install-llvm-cov.sh 36 | ``` 37 | We recommend setting a large swap file (between 4 - 12 GB) for standard laptop configuration (servers do not have to follow this). 38 | 39 | ``` 40 | cd ~ 41 | sudo fallocate -l 8G swapfile 42 | sudo chmod 600 swapfile 43 | sudo mkswap swapfile 44 | sudo swapon swapfile 45 | sudo swapon --show 46 | ``` 47 | 48 | After building LLVM with coverage successfully, run this script per set to measure its coverage; no need to rebuild LLVM between runs of this script. 49 | ``` 50 | ./1-wrapper-get-coverage.sh 15 0 llvm 0 51 | ``` 52 | Base-folder=where the installation of LLVM 15 with coverage is, that is, \/llvm-csmith-15/ 53 | 54 | ## LLVM Code Coverage with Compiler-rt parts 55 | 56 | To compare the addition of a set of files to the coverage of LLVM on top of the LLVM test suite, you will need to do the following. 57 | 58 | First, get the source code of LLVM; see [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/general) how. 59 | 60 | Second, build with compiler-rt and coverage: 61 | ``` 62 | ./0-install-llvm-cov-rt.sh 63 | ``` 64 | Third, see [here](https://github.com/srg-imperial/GrayC/blob/main/scripts/LLVM-Test-suite-coverage#the-whole-llvm-test-suite) how to measure coverage for the whole LLVM test suite. 65 | 66 | Last, you will need to create a folder with all the files you have fuzzed, and run this script: 67 | ``` 68 | ./1-wrapper-get-coverage.sh 15 7 llvm 0 69 | ``` 70 | For example: 71 | ``` 72 | nohup ./1-wrapper-get-coverage.sh /home/ubuntu/grayc/ /home/ubuntu/grayc/test-single/corpus/ 15x 7 /home/ubuntu/grayc/llvm-csmith-15x/csmith/ /home/ubuntu/graphicsfuzz/gfauto/ func_cov_v1.csv line_cov_v1.csv coverage_summary_v1.log llvm 0 > cov_delta.log 2>&1 & 73 | ``` 74 | **NOTE**: you cannot change versions of LLVM builds in between the scripts, it must always be the same build. 75 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/0-prepare-folder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Parameters: 3 | sourceFolder=$1 ## /home/user42/dailydump/*.c 4 | 5 | ## Check we have process number 6 | if [ -z "$1" ] 7 | then 8 | echo "No source folder supplied." 9 | exit 1 10 | fi 11 | 12 | ## Run for all programs in folder: 13 | # rm -f $sourceFolder/*.c ## Only for opimization 14 | for p in $sourceFolder/* 15 | do 16 | if [[ ! $p == *.c ]]; then 17 | mv $p $p.c 18 | echo " >> rename $p to $p.c" 19 | fi 20 | done 21 | echo "## DONE. ##" 22 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/2-compute-coverage_DIR_gfauto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################ 3 | ## This scripts get a folder of test-cases and 4 | ## compute their coverage using GCOV and GFAUTO 5 | ## How to call? 6 | ## ./1-compute-coverage_basic_case_gfauto.sh /home/user42 /home/user42/allTestCases 5 0 /home/user42/csmith /home/user42/gfauto 7 | ################################################ 8 | base=$1 # /home/user42 9 | testcaseDir=$2 # where is basic.c 10 | process_number=$3 # 5 11 | itr=$4 # 0 12 | csmith_location=$5 # Where are the runtime folder of csmith 13 | gfauto=$6 # gfauto location, e.g., /home/user42/git/graphicsfuzz/gfauto 14 | compiler=$7 # gcc or llvm? 15 | old_version=$8 # 1 - yes, 0 - no 16 | # $base $testcaseDir $process_number $itr $csmith_location $gfauto $compiler $gfauto_old_version 17 | 18 | ## Required parameters 19 | working_folder=$base/$compiler-csmith-$process_number 20 | configuration_location=$working_folder/csmith/scripts/compiler_test.in # config file location 21 | compile_line_lib_default="-I$csmith_location/runtime -I$csmith_location/build/runtime -lgcov -w" 22 | 23 | ## Init 24 | if [[ $itr -eq 0 ]]; then 25 | if [[ "$compiler" == "llvm" ]]; then 26 | rm -rf $working_folder/llvm-source/tools/clang/test 27 | rm -rf $working_folder/llvm-source/tools/clang/unittests 28 | rm -rf $working_folder/llvm-source/tools/clang/docs 29 | rm -rf $working_folder/llvm-source/tools/clang/www 30 | fi 31 | 32 | rm -rf $working_folder/coverage_processed 33 | rm -rf $working_folder/coverage_gcda_files/application_run 34 | fi 35 | 36 | ## Start evaluation 37 | time1=$(date +"%T") 38 | echo "EVOLUTION OF LLVM COVERAGE WHEN COMPILING PROGRAM in folder: "$testcaseDir" ("$time1")" 39 | 40 | # Loop over compilation and coverage measurement 41 | current_folder=`pwd` 42 | 43 | ## Read which compiler to test: 44 | compilerInfo=`head -1 $configuration_location` 45 | if [[ "$compilerInfo" == "" ]] || [[ "$compilerInfo" == " " ]] ; then 46 | echo "no compiler info in file $configuration_location <$compilerInfo>" 47 | exit 48 | fi 49 | 50 | # Set location to record the data 51 | mkdir -p $working_folder/coverage_gcda_files/application_run 52 | 53 | time2=$(date +"%T") 54 | echo "--> COMPILING "$testcaseDir" ITERATION "$itr" with compiler info. "$compilerInfo" ("$time2")" 55 | 56 | # Run compiler and save coverage data 57 | export GCOV_PREFIX=$working_folder/coverage_gcda_files/application_run 58 | 59 | echo "Folder: $testcaseDir" 60 | for testcaseFile in $testcaseDir/* ; do 61 | compiler_flag="-w" 62 | is_math=`grep "math.h" $testcaseFile | wc -l` 63 | if [[ $is_math -gt 0 ]]; then 64 | compiler_flag="-w -lm" 65 | fi 66 | 67 | ## Compile the test-case 68 | if [[ "$testcaseFile" == *".c" ]] ; then 69 | echo "--> PERFORMING (*.c) <(ulimit -St 50; ${compilerInfo} $testcaseFile $compiler_flag) > basic_output.txt 2>&1>" 70 | (ulimit -St 50; ${compilerInfo} ${compile_line_lib_default} $testcaseFile $compiler_flag) > "basic_output.txt" 2>&1 71 | else 72 | echo "--> PERFORMING (missing *.c) <(ulimit -St 50; ${compilerInfo} $testcaseFile $compiler_flag) > basic_output.txt 2>&1>" 73 | mv "$testcaseFile" "$testcaseFile".c 74 | (ulimit -St 50; ${compilerInfo} ${compile_line_lib_default} $testcaseFile.c $compiler_flag) > "basic_output.txt" 2>&1 75 | fi 76 | grep "fatal error: csmith.h: No such file or directory" basic_output.txt 77 | 78 | # i=$((i+1)) 79 | # if [[ $i -eq 1 ]]; then 80 | # break 81 | # fi 82 | done 83 | unset GCOV_PREFIX 84 | 85 | ## Measure Coverage 86 | time3=$(date +"%T") 87 | echo "--> MEASURING COVERAGE... ("$time3")" 88 | mkdir -p $working_folder/coverage_processed/x-func-$process_number-$itr 89 | mkdir -p $working_folder/coverage_processed/x-line-$process_number-$itr 90 | ( 91 | source $gfauto/.venv/bin/activate 92 | 93 | ## Function coverage 94 | cd $working_folder/coverage_processed/x-func-$process_number-$itr 95 | if [ "$old_version" == "1" ]; then 96 | gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json --gcov_functions >> gfauto.log 2>&1 97 | else 98 | echo "gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ --gcov_prefix_dir $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json --gcov_functions >> gfauto.log 2>&1" 99 | gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ --gcov_prefix_dir $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json --gcov_functions >> gfauto.log 2>&1 100 | fi 101 | gfauto_cov_to_source --coverage_out cov.out --cov run_gcov2cov.cov $working_folder/$compiler-build/ >> gfauto.log 2>&1 102 | 103 | ## Line coverage 104 | cd $working_folder/coverage_processed/x-line-$process_number-$itr 105 | if [ "$old_version" == "1" ]; then 106 | gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json >> gfauto.log 2>&1 107 | else 108 | echo "gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ --gcov_prefix_dir $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json >> gfauto.log 2>&1" 109 | gfauto_cov_from_gcov --out run_gcov2cov.cov $working_folder/$compiler-build/ --gcov_prefix_dir $working_folder/coverage_gcda_files/application_run/ --num_threads 32 --gcov_uses_json >> gfauto.log 2>&1 110 | fi 111 | gfauto_cov_to_source --coverage_out cov.out --cov run_gcov2cov.cov $working_folder/$compiler-build/ >> gfauto.log 2>&1 112 | ls -l 113 | ) 114 | cd $current_folder 115 | 116 | time2=$(date +"%T") 117 | echo "DONE. RESULTS (FUNCTION) AVAILABLE IN $working_folder/coverage_processed/x-func-$process_number-$itr for test case folder <$testcaseFile> ($time2)" 118 | echo "DONE. RESULTS (LINE) AVAILABLE IN $working_folder/coverage_processed/x-line-$process_number-$itr for test case folder <$testcaseFile> ($time2)" 119 | rm a.out "basic_output.txt" ## clean at the end 120 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/2-post-gcc-cov-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Revert back all gcc changes: restore gcov 3 | sudo rm -f /usr/local/bin/gcov /usr/bin/gcov 4 | sudo ln -s /usr/bin/gcov-10 /usr/bin/gcov 5 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/2-pre-gcc-cov-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | base=$1 ## e.g., /home/user42 3 | compiler=$2 ## llvm or gcc 4 | process_number=$3 ## e.g., 5 5 | working_folder=$base/$compiler-csmith-$process_number 6 | 7 | ######################################## Prepare the env. for using GCC compiler ######################################## 8 | # Restore softlink linker lto 9 | cd $working_folder/gcc-build/gcc/ 10 | ln -sf liblto_plugin.so.0.0.0 liblto_plugin.so 11 | ln -sf liblto_plugin.so.0.0.0 liblto_plugin.so.0 12 | 13 | ## Assure we are using the gcov in the gcc built: 14 | usrLib=$working_folder/gcc-install 15 | sudo rm -f /usr/local/bin/gcov /usr/bin/gcov 16 | sudo ln -s $usrLib/bin/gcov /usr/bin/gcov 17 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/3-gen-statistic-gcov-diff-tab_gfauto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | working_folder=$1 # Add where gcov files are for compiler/test 1 3 | output_table_file=$2 # Where to put the table 4 | unitest_skip=utils/unittest # unittest folder should not be part of cov measurements 5 | ## E.g., ./3-gen-statistic-gcov-diff-tab_gfauto.sh /home/user42/llvm-csmith-1/coverage_processed-1/x-10/cov.out/ table__all_1_0.csv 6 | 7 | ## INIT: 8 | rm $output_table_file 9 | rm list_gcov.txt 10 | 11 | wf1_size=${#working_folder} 12 | 13 | ## START ## 14 | 15 | ## Constract the lines on the table 16 | find $working_folder -type f | sort >> list_gcov.txt 17 | linecount=`cat list_gcov.txt | wc -l` 18 | if [ "$linecount" == "0" ]; then 19 | echo ">> ERROR: no file found in $working_folder" 20 | rm list_gcov.txt 21 | exit 1 22 | fi 23 | 24 | ## If same population, continue: 25 | echo "Total files in $working_folder: <$linecount>" 26 | 27 | ## file name: the name of the file we comapare 28 | ## #line 1: number of lines in file 1 29 | ## #line 1 hit: number of lines hit in file 1 30 | echo ">> file name,#line 1,#line 1 hit" >> $output_table_file 31 | while IFS= read -r -u 4 file_name ; do 32 | fn=${file_name:$wf_size} 33 | if [[ ! "$fn" == *"$unitest_skip"* ]]; then 34 | ## Add a row to the csv file 35 | tmp=__tmp_x.txt 36 | test=__test_x.txt 37 | cat $file_name | sed 's:^ : 0 :1' | sed -n 's/\(^......[0-9]*[0-9] \).*$/\1/p' | cat -n > $tmp 38 | cat -n $file_name > $test 39 | ./coverage-sub-scripts/CF3-1_LH_file.sh $fn $tmp $output_func_hit >> $output_table_file 40 | rm -f $tmp $test 41 | fi 42 | done 4> End extracting data for $linecount files." 44 | 45 | resT=`sed '1d' $output_table_file | cut -d',' -f2 | awk '{ sum += $1 } END { print sum }'` 46 | echo "#line 1 ................. ==> "$resT 47 | 48 | resT=`sed '1d' $output_table_file | cut -d',' -f3 | awk '{ sum += $1 } END { print sum }'` 49 | echo "#line 1 HIT ............. ==> "$resT 50 | 51 | # cleaning 52 | rm list_gcov.txt 53 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/CF3-1_LH_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################ 3 | ## MAIN: 4 | ############################ 5 | 6 | fileO=$1 # file name originally 7 | file1=$2 # file 1 8 | 9 | file1_ln=`cat $file1 | wc -l` # size file 1 10 | file1_cov_any=`cat $file1 | awk '{if ($2 >0) print($2)}' | wc -l` 11 | echo ">> $fileO,$file1_ln,$file1_cov_any" 12 | -------------------------------------------------------------------------------- /scripts/coverage/coverage-sub-scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts sub-folder 2 | 3 | These scripts are not stand-alone and hence we added no instructions regarding these. 4 | -------------------------------------------------------------------------------- /scripts/crash-testing/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srg-imperial/GrayC/cbe5f4860283bfb44012881eae4a40e387164ca1/scripts/crash-testing/.DS_Store -------------------------------------------------------------------------------- /scripts/crash-testing/0-prepare-folder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Parameters: 3 | sourceFolder=$1 ## /home/user42/dailydump/*.c 4 | skip=$2 ## to skip original test-cases? 1-yes 5 | skipFiles=$3 ## skip_me.log 6 | 7 | ## Check we have process number 8 | if [ -z "$1" ] 9 | then 10 | echo "No source folder supplied." 11 | exit 1 12 | fi 13 | 14 | ## Run for all programs in folder: 15 | # rm -f $sourceFolder/*.c ## Only for opimization 16 | rm -f $sourceFolder/*.zip 17 | 18 | ## Shall we skip it? (original code) 19 | if [[ "$skip" -eq "1" ]] ; then 20 | for p in $sourceFolder/* 21 | do 22 | prog=${p%.*} 23 | program_file_name=${prog##*/} 24 | exists=`grep -x "$program_file_name" $skipFiles | wc -l` 25 | if [[ "$exists" -eq "1" ]] ; then 26 | rm $p 27 | echo "Remove file in original set $p" 28 | fi 29 | exists=`grep -x "$program_file_name.c" $skipFiles | wc -l` 30 | if [[ "$exists" -eq "1" ]] ; then 31 | rm $p 32 | echo "Remove file in original set $p" 33 | fi 34 | done 35 | fi 36 | 37 | ## Check if need rename of remove of empty 38 | for p in $sourceFolder/* 39 | do 40 | ## Check if need to rename or remove if size 0 41 | sizeF=`cat $p | wc -l` 42 | if [[ "$sizeF" -eq "0" ]] ; then 43 | rm $p 44 | echo "remove zero size file $p" 45 | elif [[ ! $p == *.c ]]; then 46 | mv $p $p.c 47 | echo " >> rename $p to $p.c" 48 | elif [[ $p == *.c.c ]]; then 49 | prog=${p%.*} 50 | mv $p $prog 51 | echo " >> rename $p to $prog" 52 | fi 53 | done 54 | echo "## DONE. ##" 55 | -------------------------------------------------------------------------------- /scripts/crash-testing/10-get-res.sh: -------------------------------------------------------------------------------- 1 | outputfolder=$1 2 | grep -e"../gcc-source/gcc/" -e"assert" -e" diagnostic msg" -e"error: unable to execute command: Aborted" -e"Assertion" -e"LLVM ERROR" -e"Error: " -e"ERROR:" -e"BUG" -e"bug" -e"Bug" -e"Please" -e"please" -e"PLEASE" -e"Please" -e"internal compiler error:" -e" ============ test " -e"CPU time limit" -e"clang: error:" -e"unable to execute command: File size limit exceeded" -e"generic_simplify_BIT_NOT_EXPR" -e"diagnostic msg" -e"error: clang frontend command failed with exit code" -e"failed." -e": Assertion" $outputfolder/output.log | grep -ve"bugger(" -ve"copysign_bug" -ve"==ERROR: MemorySanitizer: " -ve"==ERROR: AddressSanitizer: " -ve"5-testing_all.sh" -ve"clang: error: linker command failed with exit code 1" -ve "debug" -ve "u32 bug " -ve "In function ‘bug’:" -ve"Please use" -ve"bug when they were" -ve"This tests for a bug in regstack" -ve"int showbug" -ve"unsigned bug " -ve"Bug in reorg.c" -ve"This bug exists in " -ve"had a bug that causes the final" -ve"If some target has a Max alignment less than 32" | grep -B1 -e"diagnostic msg" -e"generic_simplify_BIT_NOT_EXPR" -e"error: unable to execute command: Aborted" -e"Assertion" -e"LLVM ERROR" -e"Error: " -e"ERROR:" -e"BUG" -e"bug" -e"Bug" -e"Please" -e"please" -e"PLEASE" -e"Please" -e"internal compiler error:" -e"CPU time limit" -e"unable to execute command: File size limit exceeded" 3 | echo " === END COMP === " 4 | echo "." 5 | echo "." 6 | echo "==============> frama-c errors:" 7 | ## Run for all programs in folder: 8 | ( 9 | for p in Frama-C-zone/*.log 10 | do 11 | res=`grep -e"Unexpected error" -e"BUG" -e"bug" -e"Bug" -e"Please" -e"please" -e"PLEASE" -e"Please" $p | grep -ve"copysign_bug" -ve"debug" -ve "u32 bug " -ve "In function ‘bug’:" -ve"Please use" -ve"bug when they were" -ve"This tests for a bug in regstack" -ve"int showbug" -ve"unsigned bug " -ve"Bug in reorg.c" -ve"This bug exists in " -ve"had a bug that causes the final" -ve"If some target has a Max alignment less than 32" -ve"information to understand the bug" -ve"https://git.frama-c.com/pub/frama-c/-/wikis/Guidelines-for-reporting-bugs" -ve"eva:final-states" -ve"The following decl of" -ve"4294966804 (auto)"` 12 | if [[ ${#res} -gt 0 ]] ; then 13 | echo "============ $p > $res" 14 | else 15 | echo ""rm $p"" 16 | fi 17 | done 18 | ) | grep -B1 "Please report as " 19 | -------------------------------------------------------------------------------- /scripts/crash-testing/11-run-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | input=$1 3 | 4 | count1=1 5 | 6 | echo "Start Script with folder $input" 7 | 8 | ## Remove name extension to get the right input folder 9 | for filegz in $input/* ; do 10 | count1=$(($count1+1)) 11 | 12 | if [[ $count1 -gt 403 ]] ; then 13 | echo ">> Testing folder: $filegz" 14 | 15 | # Run wrapper for crash testing 16 | (./9-run-all-wrapper.sh /home/user42/directed-compiler-fuzzing-code/scripts/8-crash-testing/input /home/user42/directed-compiler-fuzzing-code/scripts/8-crash-testing/output "$filegz" 1) > crash_testing_current_log.log 2>&1 17 | 18 | # Collect results 19 | ./10-get-res.sh /home/user42/directed-compiler-fuzzing-code/scripts/8-crash-testing/output/ 20 | rm -rf Frama-C-zone/ ; cp -r ../7-diff-testing/Frama-C-zone/ . 21 | fi 22 | done 23 | 24 | -------------------------------------------------------------------------------- /scripts/crash-testing/12-filter-errors.sh: -------------------------------------------------------------------------------- 1 | echo "CLANG Errors: --->" 2 | grep -e": Assertion" -e"failed." -e"error: clang frontend command failed with exit code" -e"Testing folder:" -e"assert" -e"Assert" -e"======" -e"LLVM ERROR: out of memory" -e"clang: error: unable to execute command: Aborted" $1 | grep -B1 -e"LLVM ERROR: out of memory" -e"clang: error: unable to execute command: Aborted" | grep -A1 " ============" | grep -ve"LLVM ERROR: out of memory" -ve"--" -ve"====" 3 | 4 | echo "GCC Errors: --->" 5 | grep -e"Testing folder:" -e"assert" -e"Assert" -e"internal compiler error:" $1 | grep -e"internal compiler error:" | grep -ve"internal compiler error: in expand_call, at calls.cc:3643" -ve"CPU time limit" -ve"File size limit exceeded signal terminated program as" -ve"internal compiler error: in expand_call, at calls.cc:3601" -ve"in expand_call, at calls.cc:3905" -ve"internal compiler error: verify_gimple failed" -ve "internal compiler error: in decompose, at wide-int.h:984" -ve"in tree_to_poly_int64, at tree.cc:3188" -ve"internal compiler error: in as_a, at value-range.h:381" 6 | 7 | echo "Frama-c Errors: --->" 8 | grep -e"Testing folder:" -e"============ Frama-C-zone/f" $1 | grep -e"============ Frama-C-zone/f" | grep -ve'Unexpected error (File "src/plugins/value/engine/evaluation.ml", line 1176, characters 14-20: Assertion failed).' -ve"Unexpected error (Stack overflow)." -ve"Unexpected error (Out of memory)." -ve'Unexpected error (Invalid_argument("Z.shift_left: count argument must be positive")).' -ve'Unexpected error (Invalid_argument("Array.make")).' -ve"Unexpected error (Cil.Not_representable)." -ve'Unexpected error (File "src/kernel_services/abstract_interp/ival.ml", line 444, characters 31-37: Assertion failed).' -ve"Unexpected error (Z.Overflow)." 9 | 10 | files=`grep "Testing folder:" $1 | wc -l` 11 | echo "Total tar files $files" 12 | -------------------------------------------------------------------------------- /scripts/crash-testing/8-testing_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## Checks modified code for seg-fault (DEBUG) 4 | function check_configuration { 5 | program_test=$1 6 | compiler_test=$2 7 | compile_line_test=$3 8 | compileoutput_test=$4 9 | test_san=$5 10 | 11 | # Skip if already got errors 12 | if [[ $time_out_flag -eq 0 ]]; then 13 | # echo "<$program_test> <$compiler_test> <$compile_line_test> <$compileoutput_test>" 14 | # PLAIN 15 | { 16 | rm -f a.out 17 | (ulimit -St 45 -Sf 90000; $compiler_test -pedantic -Wall -Wextra $compile_line_test $program_test) >> $compileoutput_test 2>&1 18 | if [[ ! -f "a.out" ]]; then ## check if the file exists 19 | isSimpleError=`tail -1 $compileoutput_test | grep -e'errors generated' -e'error generated' | wc -l` 20 | if [[ $isSimpleError -gt 0 ]] ; then 21 | time_out_flag=1 22 | fi 23 | echo ">> ERROR: " 24 | echo "($program_test) Recognized error in generating this test-case during plain compilation. Please check for any report of BUGS in the logs. (time_out_flag=$time_out_flag)" 25 | fi 26 | } 27 | else 28 | echo "Skip crashed before program $program (1)" >> $loggerCurr 29 | fi 30 | 31 | # Can skip testing sanitizers 32 | if [[ $test_san -eq 0 ]]; then 33 | return 1 34 | fi 35 | 36 | 37 | # Skip if already got errors 38 | if [[ $time_out_flag -eq 0 ]]; then 39 | # ASAN 40 | { 41 | rm -f a.out 42 | (ulimit -St 180 -Sf 90000; $compiler_test -fsanitize=address -g -w -fno-omit-frame-pointer $compile_line_test $program_test) >> $compileoutput_test 2>&1 43 | if [[ ! -f "a.out" ]]; then ## check if the file exists 44 | time_out_flag=1 45 | echo ">> ERROR: " 46 | echo "($program_test) Recognized error in generating this test-case during compilation with ASAN. Please check for any report of BUGS in the logs. (time_out_flag=$time_out_flag)" 47 | fi 48 | } 49 | else 50 | echo "Skip crashed before program $program (2)" >> $loggerCurr 51 | fi 52 | 53 | # Skip if already got errors 54 | if [[ $time_out_flag -eq 0 ]]; then 55 | # UBSAN 56 | { 57 | rm -f a.out 58 | if [[ $compiler_test == *"clang"* ]]; then 59 | (ulimit -St 180 -Sf 90000; $compiler_test -fsanitize=undefined -g -w -lgcc_s --rtlib=compiler-rt $compile_line_test $program_test) >> $compileoutput_test 2>&1 60 | else 61 | (ulimit -St 180 -Sf 90000; $compiler_test -fsanitize=undefined -g -w -lgcc_s $compile_line_test $program_test) >> $compileoutput_test 2>&1 62 | fi 63 | 64 | if [[ ! -f "a.out" ]]; then ## check if the file exists 65 | time_out_flag=1 66 | echo ">> ERROR: $compile_line_test $program_test>" 67 | echo "($program_test) Recognized error in generating this test-case during compilation with UBSAN. Please check for any report of BUGS in the logs. (time_out_flag=$time_out_flag)" 68 | fi 69 | } 70 | else 71 | echo "Skip crashed before program $program (3)" >> $loggerCurr 72 | fi 73 | } 74 | 75 | ## Checks modified code with Frama-C for seg-fault (DEBUG) 76 | function check_wt_FramaC { 77 | progOrig=$1 78 | progName=$2 79 | output=$3 80 | progRMv=$framac_run_folder/_rmv_"$progName" 81 | 82 | # FRAMA-C 83 | cd $framac_run_folder 84 | sed 's/volatile/ /g' $progOrig > $progRMv 85 | (ulimit -St 300; frama-c -eva -eva-slevel 100 -eva-plevel 256 -eva-precision 5 -eva-warn-undefined-pointer-comparison pointer -eva-no-alloc-returns-null -warn-signed-overflow -eva-no-show-progress -machdep x86_64 $progRMv) > $output 2>&1 86 | rm -f $progRMv 87 | 88 | ## Frama-C installation can easiliy be broken, test it: 89 | countError=`cat $output | grep "cannot load module" | wc -l` 90 | if [[ $countError -gt 0 ]]; then 91 | echo ">>>>>> PLEASE re-insall frama-C!" 92 | cat $output | grep "cannot load module" 93 | exit 94 | fi 95 | cd $curr_folder 96 | } 97 | 98 | ################### TEST PROGRAM ########### 99 | function test_program { 100 | program=$1 101 | program_file_name=${program##*/} 102 | 103 | ## If program has too long expressions : skip it, anyhow we cannot reduce it. 104 | maxLine=`awk 'length > max_length { max_length = length; longest_line = $0 } END { print max_length }' $program` 105 | maxMem=`grep -P '\[.*\d{4}.*\]' $program | grep -ve"if" -ve"|" -ve">" -ve"builtin" -ve"return" -ve"(" | cut -d'=' -f1 | grep -P -o '\[.*\d{4}.*\]' | grep '.\{16\}' | grep -ve'[A-Za-z]'` 106 | if [[ "$maxLine" -lt "22000" ]] && [[ "$maxMem" -lt "1" ]] ; then 107 | ## Check compilers 108 | for (( i=0; i<${#compilers[@]}; i++ )) 109 | do 110 | time_out_flag=0 # Reset the timeout flag! 111 | for (( j=0; j<${#compilerFlags[@]}; j++ )) 112 | do 113 | output="__temp_$program_file_name_$i_$j.log" 114 | check_configuration "$program" "${compilers[$i]}" "${compilerFlags[$j]} $compile_line" "$loggerCurr" "${compilers_san_flags[$i]}" 115 | done 116 | done 117 | 118 | ## Test Frama-c crashes 119 | output=$program_file_name.framac.log 120 | touch $output 121 | check_wt_FramaC "$program" "$program_file_name" "$output" 122 | cat $output >> $loggerCurr 123 | rm -rf $output 124 | else 125 | echo "Skip bad program $program" >> $loggerCurr 126 | fi 127 | } 128 | ################### MAIN ################### 129 | 130 | ## Parameters: 131 | sourceFolder=$1 ## /home/user42/dailydump/*.c 132 | outputFolder=$2 ## /home/user42/dailydump/output 133 | loggerCurr=$3 ## /home/user42/diff-test.log 134 | compile_line=$4 ## -w 135 | curr_folder=`pwd` ## current folder 136 | framac_run_folder=$curr_folder/Frama-C-zone ## frama-c folder 137 | time_out_flag=0 ## timeout flag to avoid running other test after program timed-out 138 | 139 | ## Check we have process number 140 | if [ -z "$1" ] 141 | then 142 | echo "No source folder supplied." 143 | exit 1 144 | fi 145 | if [ -z "$2" ] 146 | then 147 | echo "No output folder supplied." 148 | exit 1 149 | fi 150 | if [ -z "$3" ] 151 | then 152 | echo "No logger file supplied." 153 | exit 1 154 | fi 155 | if [ -z "$4" ] 156 | then 157 | echo "No compile line parameters supplied." 158 | exit 1 159 | fi 160 | 161 | #### Test we have Frama-c, and not the system default #### 162 | eval $(opam config env) ## Just to assure it gets it from the right place 163 | frama-c --version 164 | echo " ==> Frama-C version" 165 | testIT=`frama-c --version` 166 | if [ "$testIT" == "Phosphorus-20170501" ]; then 167 | echo ">> Frama-C version is too old. Please install version 20.0.0 or up." 168 | exit 169 | fi 170 | if [[ "$testIT" == "" ]]; then 171 | echo ">> Please install Frama-C version 20.0.0 or up." 172 | exit 173 | fi 174 | if [ ! -d "$framac_run_folder" ]; then 175 | echo ">> Please create a folder for Frama-C testing with all required headers for your testing." 176 | exit 177 | fi 178 | if [ ! -d "$sourceFolder" ]; then 179 | echo ">> Missing source folder: <$sourceFolder>. Exit." 180 | exit 181 | fi 182 | 183 | ## clean prev. run 184 | rm -rf $outputFolder 185 | mkdir $outputFolder 186 | 187 | ## Testing inputs 188 | compilerFlags=("-O0" "-O1" "-O2" "-O3" "-Os") 189 | 190 | ## Quick test 191 | compilers=("/home/user42/data/gcc-csmith-1201/gcc-install/bin/gcc" "clang-15") 192 | 193 | compilers_names=("gcc-13" "clang-15") 194 | 195 | compilers_san_flags=("0" "0" "1" "1") 196 | ## 197 | 198 | ## dump script information 199 | touch $loggerCurr 200 | for (( i=0; i<${#compilers[@]}; i++ )) 201 | do 202 | echo "## - Compiler version:" `${compilers[$i]} --version | head -1` >> $loggerCurr 203 | done 204 | echo "## - Applying testing for compiler optimizations ${compilerFlags[0]} ${compilerFlags[1]} ${compilerFlags[2]} ${compilerFlags[3]} ${compilerFlags[4]}" >> $loggerCurr 205 | echo "## - CSMITH_HOME: $csmith_location" >> $loggerCurr 206 | echo "## - Compilation of testcase: $compile_line" >> $loggerCurr 207 | echo "## - Source folder: $sourceFolder for process $process_number" >> $loggerCurr 208 | echo "## - Date: $(date '+%Y-%m-%d at %H:%M.%S')" >> $loggerCurr 209 | echo "## - Host name $(hostname -f)" >> $loggerCurr 210 | 211 | ## Run for all programs in folder: 212 | for p in $sourceFolder/*.c 213 | do 214 | test -f "$p" || continue 215 | echo " >> test $p" 216 | echo " ============ test $p ============ " >> $loggerCurr 217 | (test_program "$p") 218 | done 219 | 220 | ## Diff again: 221 | ## Generating logger per test: 222 | logger_checksum_0=$outputFolder/checksum_logger_"${compilers[0]}"_"${compilerFlags[0]}".log 223 | echo "## DONE. ##" >> $loggerCurr 224 | echo " >> Errors if exists logged into <$loggerCurr>" 225 | -------------------------------------------------------------------------------- /scripts/crash-testing/9-run-all-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | input=$1 3 | output=$2 4 | zipf=$3 5 | zip_or_folder=$4 # zip 1, folder 2 6 | 7 | current=`pwd` 8 | 9 | lib1=/home/user42/data/csmith/runtime/ 10 | lib2=/home/user42/data/csmith/build/runtime/ 11 | 12 | ## Prepare an input folder with all the files 13 | rm -rf $output $input 14 | mkdir $output $input 15 | 16 | ## Open files and change to csmith style prints 17 | cd $input 18 | if [[ $zip_or_folder -eq 1 ]] ; then 19 | tar -xf $zipf 20 | cp -r fuzzer-output-directory/ . 21 | rm -rf fuzzer-output-directory/ 22 | elif [[ $zip_or_folder -eq 2 ]] ; then 23 | cp -r $zipf/* . 24 | else 25 | echo "Is $zipf a tar (1) or a folder (2) ?. Exit." 26 | exit 27 | fi 28 | cd $current 29 | 30 | ## Remove name extension to get the right input folder 31 | for input_d in $input/* ; do 32 | echo ">> Testing folder: $input_d" 33 | 34 | ## Remove init corpus data 35 | rm $input_d/A_*.c 36 | rm $input_d/B_*.c 37 | 38 | fdupes -dN $input_d/. 39 | 40 | ## Rename all to be .c in the end 41 | echo ">> $input_d" 42 | (./0-prepare-folder.sh $input_d 1 skip_me.log) 43 | 44 | ## run script 8 now 45 | touch $output/output.log 46 | compile_line="-I$lib1 -I$lib2" 47 | (./8-testing_all.sh "$input_d" "$output" "$output/output.log" "$compile_line") 48 | ## End 49 | wc -l $output/output.log 50 | ./10-get-res.sh $output >> get_all_results.log 51 | done 52 | echo "## DONE. " 53 | ## ./9-run-all-wrapper.sh /home/user42/directed-compiler-fuzzing-code/scripts/8-crash-testing/input /home/user42/directed-compiler-fuzzing-code/scripts/8-crash-testing/output /home/user42/corpus-zips-for-fuzzing/corpus-v0-compiled.tar.xz 54 | -------------------------------------------------------------------------------- /scripts/crash-testing/Frama-C-zone/config.h: -------------------------------------------------------------------------------- 1 | /* Define to 1 if you have the `arc4random_buf' function. */ 2 | /* #undef HAVE_ARC4RANDOM_BUF */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | /* #undef HAVE_BSD_STDLIB_H */ 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #define HAVE_DLFCN_H 1 9 | 10 | /* Define to 1 if you have the header file. */ 11 | #define HAVE_INTTYPES_H 1 12 | 13 | /* Define to 1 if you have the `lrand48' function. */ 14 | #define HAVE_LRAND48 1 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #define HAVE_MEMORY_H 1 18 | 19 | /* Define to 1 if you have the `srand48_deterministic' function. */ 20 | /* #undef HAVE_SRAND48_DETERMINISTIC */ 21 | 22 | /* Define to 1 if you have the header file. */ 23 | #define HAVE_STDINT_H 1 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #define HAVE_STDLIB_H 1 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_STRINGS_H 1 30 | 31 | /* Define to 1 if you have the header file. */ 32 | #define HAVE_STRING_H 1 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #define HAVE_SYS_STAT_H 1 36 | 37 | /* Define to 1 if you have the header file. */ 38 | #define HAVE_SYS_TYPES_H 1 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #define HAVE_UNISTD_H 1 42 | 43 | /* Name of package */ 44 | #define PACKAGE "csmith" 45 | 46 | /* Define to the address where bug reports for this package should be sent. */ 47 | #define PACKAGE_BUGREPORT "csmith-bugs@flux.utah.edu" 48 | 49 | /* Define to the full name of this package. */ 50 | #define PACKAGE_NAME "csmith" 51 | 52 | /* Define to the full name and version of this package. */ 53 | #define PACKAGE_STRING "csmith 2.4.0" 54 | 55 | /* Define to the one symbol short name of this package. */ 56 | #define PACKAGE_TARNAME "csmith" 57 | 58 | /* Define to the home page for this package. */ 59 | #define PACKAGE_URL "http://embed.cs.utah.edu/csmith/" 60 | 61 | /* Define to the version of this package. */ 62 | #define PACKAGE_VERSION "2.4.0" 63 | 64 | /* Version number of package */ 65 | #define VERSION "2.4.0" 66 | -------------------------------------------------------------------------------- /scripts/crash-testing/Frama-C-zone/csmith.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C -*- 2 | * 3 | * Copyright (c) 2007-2011, 2013, 2014 The University of Utah 4 | * All rights reserved. 5 | * 6 | * This file is part of `csmith', a random generator of C programs. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef RANDOM_RUNTIME_H 32 | #define RANDOM_RUNTIME_H 33 | 34 | #ifdef CSMITH_MINIMAL 35 | #include "csmith_minimal.h" 36 | #else 37 | 38 | /*****************************************************************************/ 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #define __STDC_LIMIT_MACROS 45 | #include "random_inc.h" 46 | 47 | static uint32_t crc32_tab[256]; 48 | static uint32_t crc32_context = 0xFFFFFFFFUL; 49 | 50 | static void 51 | crc32_gentab (void) 52 | { 53 | uint32_t crc; 54 | const uint32_t poly = 0xEDB88320UL; 55 | int i, j; 56 | 57 | for (i = 0; i < 256; i++) { 58 | crc = i; 59 | for (j = 8; j > 0; j--) { 60 | if (crc & 1) { 61 | crc = (crc >> 1) ^ poly; 62 | } else { 63 | crc >>= 1; 64 | } 65 | } 66 | crc32_tab[i] = crc; 67 | } 68 | } 69 | 70 | static void 71 | crc32_byte (uint8_t b) { 72 | crc32_context = 73 | ((crc32_context >> 8) & 0x00FFFFFF) ^ 74 | crc32_tab[(crc32_context ^ b) & 0xFF]; 75 | } 76 | 77 | #if defined(__SPLAT__) || defined(NO_LONGLONG) 78 | static void 79 | crc32_8bytes (uint32_t val) 80 | { 81 | crc32_byte ((val>>0) & 0xff); 82 | crc32_byte ((val>>8) & 0xff); 83 | crc32_byte ((val>>16) & 0xff); 84 | crc32_byte ((val>>24) & 0xff); 85 | } 86 | 87 | static void 88 | transparent_crc (uint32_t val, char* vname, int flag) 89 | { 90 | crc32_8bytes(val); 91 | if (flag) { 92 | printf("...checksum after hashing %s : %X\n", vname, crc32_context ^ 0xFFFFFFFFU); 93 | } 94 | } 95 | #else 96 | static void 97 | crc32_8bytes (uint64_t val) 98 | { 99 | crc32_byte ((val>>0) & 0xff); 100 | crc32_byte ((val>>8) & 0xff); 101 | crc32_byte ((val>>16) & 0xff); 102 | crc32_byte ((val>>24) & 0xff); 103 | crc32_byte ((val>>32) & 0xff); 104 | crc32_byte ((val>>40) & 0xff); 105 | crc32_byte ((val>>48) & 0xff); 106 | crc32_byte ((val>>56) & 0xff); 107 | } 108 | 109 | static void 110 | transparent_crc (uint64_t val, char* vname, int flag) 111 | { 112 | crc32_8bytes(val); 113 | if (flag) { 114 | printf("...checksum after hashing %s : %lX\n", vname, crc32_context ^ 0xFFFFFFFFUL); 115 | } 116 | } 117 | 118 | #endif 119 | 120 | static void 121 | transparent_crc_bytes (char *ptr, int nbytes, char* vname, int flag) 122 | { 123 | int i; 124 | for (i=0; i32)?(x%32):x) 74 | 75 | uint64_t crc32_context; 76 | 77 | #ifdef TCC 78 | int strcmp (const char *s1, const char *s2) 79 | { 80 | for(; *s1 == *s2; ++s1, ++s2) 81 | if(*s1 == 0) 82 | return 0; 83 | return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1; 84 | } 85 | #else 86 | extern int strcmp (const char *, const char *); 87 | #endif 88 | 89 | static inline void 90 | transparent_crc (uint64_t val, char* vname, int flag) 91 | { 92 | #ifndef NO_PRINTF 93 | if (flag) printf ("%s %d\n", vname, val); 94 | #endif 95 | crc32_context += val; 96 | } 97 | 98 | static void 99 | transparent_crc_bytes (char *ptr, int nbytes, char* vname, int flag) 100 | { 101 | int i; 102 | for (i=0; i 40 | #endif 41 | 42 | static void 43 | platform_main_begin(void) 44 | { 45 | /* Nothing to do. */ 46 | } 47 | 48 | static void 49 | platform_main_end(uint32_t crc, int flag) 50 | { 51 | #if defined (__FRAMAC) 52 | Frama_C_dump_assert_each(); 53 | #endif 54 | 55 | #ifndef NOT_PRINT_CHECKSUM 56 | printf ("checksum = %X\n", crc); 57 | #endif 58 | 59 | #if defined (LOG_WRAPPERS) 60 | { 61 | int i, first; 62 | 63 | printf ("executed wrappers: "); 64 | first = 1; 65 | for (i=1; i 38 | #include "windows/stdint.h" 39 | #elif defined (IA32_ARCH) 40 | #include "stdint_ia32.h" 41 | #elif defined (IA64_ARCH) 42 | #include "stdint_ia64.h" 43 | #elif defined (MSP430) 44 | #include "stdint_msp430.h" 45 | #elif defined (AVR_ARCH) 46 | #include "stdint_avr.h" 47 | #else 48 | #include "stdint_ia32.h" 49 | #endif 50 | #else 51 | #include 52 | #if defined(_MSC_VER) 53 | #include "windows/stdint.h" 54 | #else 55 | #include 56 | #endif 57 | #endif 58 | 59 | #include 60 | 61 | /*****************************************************************************/ 62 | 63 | #ifndef DEPUTY 64 | #define COUNT(n) 65 | #define TC 66 | #define SAFE 67 | #endif 68 | 69 | /*****************************************************************************/ 70 | 71 | #ifdef LOG_WRAPPERS 72 | #include "wrapper.h" 73 | char __failed_checks[N_WRAP+1]; 74 | char __executed_checks[N_WRAP+1]; 75 | #define UNDEFINED(__val) (__failed_checks[index]=1,(__val)) 76 | #define LOG_INDEX , int index 77 | #define LOG_EXEC __executed_checks[index]=1; 78 | #else 79 | #define UNDEFINED(__val) (__val) 80 | #define LOG_INDEX 81 | #define LOG_EXEC 82 | #endif 83 | 84 | #if defined(AVR_ARCH) 85 | #include "platform_avr.h" 86 | #elif defined (MSP430) 87 | #include "platform_msp430.h" 88 | #else 89 | #include "platform_generic.h" 90 | #endif 91 | 92 | #define STATIC static 93 | 94 | #if defined (USE_MATH_MACROS_NOTMP) 95 | #include "safe_math_macros_notmp.h" 96 | #elif defined (USE_MATH_MACROS) 97 | #include "safe_math_macros.h" 98 | #else 99 | #define FUNC_NAME(x) (safe_##x) 100 | #include "safe_math.h" 101 | #undef FUNC_NAME 102 | #endif 103 | 104 | #define INT_BIT (sizeof(int)*CHAR_BIT) 105 | #define _CSMITH_BITFIELD(x) (((x)>INT_BIT)?((x)%INT_BIT):(x)) 106 | 107 | #ifdef TCC 108 | 109 | void* memcpy(void* dest, const void* src, size_t count) { 110 | char* dst8 = (char*)dest; 111 | char* src8 = (char*)src; 112 | 113 | while (count--) { 114 | *dst8++ = *src8++; 115 | } 116 | return dest; 117 | } 118 | 119 | void *memset(void *s, int c, size_t n) 120 | { 121 | unsigned char* p=s; 122 | while(n--) 123 | *p++ = (unsigned char)c; 124 | return s; 125 | } 126 | 127 | #endif 128 | 129 | #endif // RANDOM_INC_H 130 | -------------------------------------------------------------------------------- /scripts/enhanCer/1-1-prepare-folder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## Parameters: 3 | sourceFolder=$1 ## /home/user42/dailydump/*.c 4 | skip=$2 ## to skip original test-cases? 1-yes 5 | skipFiles=$3 ## skip_me.log 6 | 7 | ## Check we have process number 8 | if [ -z "$1" ] 9 | then 10 | echo "No source folder supplied." 11 | exit 1 12 | fi 13 | 14 | ## Run for all programs in folder: 15 | # rm -f $sourceFolder/*.c ## Only for opimization 16 | rm -f $sourceFolder/*.zip 17 | 18 | ## Shall we skip it? (original code) 19 | if [[ "$skip" -eq "1" ]] ; then 20 | for p in $sourceFolder/* 21 | do 22 | prog=${p%.*} 23 | program_file_name=${prog##*/} 24 | exists=`grep -x "$program_file_name" $skipFiles | wc -l` 25 | if [[ "$exists" -eq "1" ]] ; then 26 | rm $p 27 | echo "Remove file in original set $p" 28 | fi 29 | exists=`grep -x "$program_file_name.c" $skipFiles | wc -l` 30 | if [[ "$exists" -eq "1" ]] ; then 31 | rm $p 32 | echo "Remove file in original set $p" 33 | fi 34 | exists=`grep "q = p + 1 + 42" $p | wc -l` 35 | if [[ "$exists" -eq "1" ]] ; then 36 | rm $p 37 | echo "Remove file in original set $p" 38 | fi 39 | done 40 | fi 41 | 42 | ## Check if need rename of remove of empty 43 | for p in $sourceFolder/* 44 | do 45 | ## Check if need to rename or remove if size 0 46 | sizeF=`cat $p | wc -l` 47 | if [[ "$sizeF" -eq "0" ]] ; then 48 | rm $p 49 | echo "remove zero size file $p" 50 | elif [[ ! $p == *.c ]]; then 51 | mv $p $p.c 52 | echo " >> rename $p to $p.c" 53 | elif [[ $p == *.c.c ]]; then 54 | prog=${p%.*} 55 | mv $p $prog 56 | echo " >> rename $p to $prog" 57 | fi 58 | done 59 | 60 | # Fix Main names - transformation before script 3 61 | for p in $sourceFolder/* 62 | do 63 | sed -i 's:enum fred frod;:enum fred frod=1;:g' $p 64 | sed -i 's:int a;:int a=0;:g' $p 65 | sed -i 's:int b;:int d=0;:g' $p 66 | sed -i 's:int c;:int c=0;:g' $p 67 | sed -i 's:int d;:int d=0;:g' $p 68 | sed -i 's:extern int memcmp (:extern int memcmp_inner-def (:g' $p 69 | sed -i 's:typedef __uint64_t uint64_t;:/* Remove typedef */:g' $p 70 | sed -i 's:typedef int ssize_t;:/* Remove typedef */:g' $p 71 | sed -i 's:typedef unsigned long long uint64_t;:/* Remove typedef */:g' $p 72 | sed -i 's:main ():main():g' $p 73 | sed -i 's:main (:main(:g' $p 74 | sed -i 's:( void ):(void):g' $p 75 | sed -i 's:(void ):(void):g' $p 76 | sed -i 's:( void):(void):g' $p 77 | sed -i 's:( int:(int:g' $p 78 | sed -i 's: ):):g' $p 79 | sed -i 's: (:(:g' $p 80 | sed -i 's:main(void):main():g' $p 81 | sed -i 's:main (void):main():g' $p 82 | sed -i 's:main(int argc):main(int argc, char \*argv[]):g' $p 83 | sed -i 's:main(int argc, char \*\*argv):main(int argc, char \*argv[]):g' $p 84 | sed -i 's:main(int argc, char\*\* argv):main(int argc, char \*argv[]):g' $p 85 | sed -i 's:main(int argc, char\* argv\[\]):main(int argc, char \*argv\[\]):g' $p 86 | sed -i 's:main(int argc,char \*\*argv):main(int argc, char \*argv[]):g' $p 87 | sed -i 's:main(int argc,char\*\* argv):main(int argc, char \*argv[]):g' $p 88 | sed -i 's:main(int argc,char \*argv\[\]):main(int argc, char \*argv\[\]):g' $p 89 | sed -i 's:main(int argc,char\* argv\[\]):main(int argc, char \*argv\[\]):g' $p 90 | sed -i ':a;N;$!ba;s:int\nmain():int main():g' $p 91 | sed -i ':a;N;$!ba;s:int\nmain(:int main(:g' $p 92 | sed -i ':a;N;$!ba;s:\nmain(: main(:g' $p 93 | sed -i ':a;N;$!ba;s:int main\(argc, argv\)\n int argc;\n char \*\*argv;:int main(int argc, char \*argv[]):g' $p 94 | sed -i ':a;N;$!ba;s:int main\(int argc __attribute__\(\(unused\)\), char \*\*argv __attribute__\(\(unused\)\)\):int main\(int argc, char \*argv\[\]\):g' $p 95 | sed -i ':a;N;$!ba;s:int main(argc, argv)\n int argc;\n char \*\*argv;:int main(int argc, char \*argv[]):g' $p 96 | sed -i ':a;N;$!ba;s:int main(int argc __attribute__((unused)), char \*\*argv __attribute__((unused))):int main(int argc, char \*argv[]):g' $p 97 | sed -i ':a;N;$!ba;s:typedef __attribute__((aligned(16))):typedef:g' $p 98 | sed -i ':a;N;$!ba;s:typedef __attribute__\(\(aligned\(16\)\)\):typedef:g' $p 99 | 100 | # Mark signature we can recognize 101 | sed -i 's:main():main() /* OK */:g' $p 102 | sed -i 's:main(int argc, char \*argv\[\]):main(int argc, char \*argv\[\]) /* OK */:g' $p 103 | done 104 | 105 | echo "## DONE. ##" 106 | -------------------------------------------------------------------------------- /scripts/enhanCer/1-2-filter-compiled.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################## 3 | ## This script check which of the single file programs we can 4 | ## compile given a folder. 5 | ################# 6 | testcaseDir=$1 #"/home/user42/git/directed-compiler-fuzzing-code/scripts/3-reduce-general-spots-reaching-files/corpus_weak+gen_feb/orig_1" 7 | testcaseDir_output=$2 # Where to copy those that compiles 8 | includes=$3 # Add -I line: e.g., -I/home/user42/git/csmith/build/runtime/ -I/home/user42/git/csmith/runtime/ 9 | 10 | rm -rf $testcaseDir_output 11 | mkdir $testcaseDir_output 12 | 13 | for testcaseFile in $testcaseDir/* ; do 14 | (ulimit -St 50 -Sf 90000; clang -w -O0 $includes $testcaseFile) > basic_output.txt 2>&1 15 | warnings=`cat basic_output.txt | wc -l` 16 | errors=`grep "error:" basic_output.txt | wc -l` 17 | linker=`grep "error: linker command failed" basic_output.txt | wc -l` 18 | echo "--> Compile $testcaseFile $warnings $errors $linker" 19 | rm basic_output.txt 20 | 21 | if [ $errors -eq 0 ] && [ $linker -eq 0 ]; then 22 | cp $testcaseFile $testcaseDir_output 23 | fi 24 | done 25 | 26 | x=`ls -l $testcaseDir | wc -l` 27 | y=`ls -l $testcaseDir_output | wc -l` 28 | echo ">> Out of $x programs $y pass compilations <$testcaseDir_output>" 29 | -------------------------------------------------------------------------------- /scripts/enhanCer/1-main-enhanCer-option-1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | current=`pwd` 3 | 4 | input=$1"_input" # Where are all the original tests 5 | output=$1"_output" # Where to put transformed tests - ready for diff-testing 6 | error=$1"_error-programs-fuzzed" # where to put programs that failed the transformation: e.g. /home/user42/directed-compiler-fuzzing-code/scripts/7-diff-testing/error-programs-fuzzed 7 | zipf=$2 # The tests can be in a single zip file or as a folder: 1 for zip, 2 for a folder. 8 | zip_or_folder=$3 # zip 1, folder 2 9 | csmith=$4 # Add location of csmith installation if corpus tests contain csmith's generated tests fed to GrayC. 10 | 11 | lib1=$csmith/runtime 12 | lib2=$csmith/build/runtime 13 | lib3=/usr/include/x86_64-linux-gnu/ 14 | 15 | ## Prepare an input folder with all the files 16 | rm -rf "$output/" "$input/" "$error/" 17 | mkdir $output $input $error $output/compiled $output/include $output/transform 18 | 19 | ## Open files and change to csmith style prints 20 | cd $input 21 | if [[ $zip_or_folder -eq 1 ]] ; then 22 | tar -xf $zipf 23 | elif [[ $zip_or_folder -eq 2 ]] ; then 24 | cp -r $zipf . 25 | else 26 | echo "Is $zipf a tar (1) or a folder (2) ?. Exit." 27 | exit 28 | fi 29 | 30 | cd $current 31 | anythingCompiled=0 32 | 33 | ## Remove name extension to get the right input folder 34 | for input_d in $input/* ; do 35 | echo "$input_d" 36 | 37 | ## Remove init corpus data 38 | rm $input_d/A_*.c 39 | rm $input_d/B_*.c 40 | 41 | fdupes -dN $input_d/. 42 | 43 | ## Rename all to be .c in the end 44 | (./1-1-prepare-folder.sh $input_d 1 skip_me.data) 45 | 46 | ## Remove all files we cannot compile 47 | (./1-2-filter-compiled.sh $input_d $output/compiled "-I$lib1 -I$lib2 -I$input_d -Werror=shift-count-negative -Werror=unsequenced") 48 | 49 | ## Run script to add csmith's prints 50 | echo ">> Adding checksum to all files in $input_d, output to $output" 51 | for program in $output/compiled/*.c ; do 52 | filename=${program##*/} 53 | prog_to_path_name=${filename%.*} 54 | 55 | working_dir=$output/transform/$prog_to_path_name 56 | mkdir $working_dir 57 | cp $program $working_dir 58 | echo "(python3 1-3-transform.py $working_dir $working_dir $lib1 $lib2 $lib3 $input_d 2>&1 errors_transform_py.log)" 59 | (python3 1- 3-transform.py $working_dir $working_dir $lib1 $lib2 $lib3 $input_d 2>&1 errors_transform_py.log) 60 | cp $working_dir/*_copy.c $output 2>/dev/null 61 | cp errors_transform_py.log $working_dir 2>/dev/null 62 | cp Record-Info.txt $working_dir 2>/dev/null 63 | cp Main-Sign.txt $working_dir 2>/dev/null 64 | cp Global-Info.txt $working_dir 2>/dev/null 65 | rm Main-Sign.txt Global-Info.txt Record-Info.txt errors_transform_py.log 2>/dev/null # remove temp files from the python script 66 | 67 | ## Prepare for later 68 | anythingCompiled=$((anythingCompiled+1)) 69 | 70 | ## Copying if missing (so we can compile later) 71 | cp -f $program $output/include/ 72 | 73 | ## If the original file does not contain exit or abort, can copy it 74 | exitORabort=`grep -e"exit()" -e"abort()" -e"fred.txt" $program | wc -l` 75 | if [[ "$exitORabort" -eq "0" ]] ; then 76 | cp -f $program $output/ 77 | fi 78 | done 79 | echo ">> Done with script 3-transform.py" 80 | done 81 | 82 | ## Check if we managed to compile anything! 83 | if [[ $anythingCompiled -le 1 ]] ; then 84 | echo ">> Cannot compile programs. Exit. ($sizeComp)" 85 | exit 86 | fi 87 | 88 | ## Remove duplicates 89 | fdupes -dN $output/. 90 | 91 | ## run script 5 now 92 | mkdir $output/logger 93 | touch $output/logger/output.log 94 | compile_line="-I$lib1 -I$lib2 -I$output -I$output/include" 95 | 96 | trans=`grep "Original main of the program " $output/*.c | wc -l` 97 | gErrMain=`grep "Global but no valid main" $output/*.c | wc -l` 98 | noGOKMain=`grep "No Global Variable but valid main" $output/*.c | wc -l` 99 | noGErrMain=`grep "No Global Variable and no valid main" $output/*.c | wc -l` 100 | echo "Compiled (initially): $anythingCompiled" 101 | echo "Results - translated = $trans, valid without translating = $noGOKMain, error with main = $gErrMain and $noGErrMain" 102 | echo "## DONE. Check Results in: <$output/logger/output.log>" 103 | ## ./1-main-enhanCer-option-1.sh /home/user42/directed-compiler-fuzzing-code/scripts/7-diff-testing/results /home/user42/corpus-zips-for-fuzzing/corpus-v0-compiled.tar.xz /home/user42/directed-compiler-fuzzing-code/scripts/7-diff-testing/corrected 104 | -------------------------------------------------------------------------------- /scripts/enhanCer/2-main-coverage-diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TODO 3 | -------------------------------------------------------------------------------- /scripts/enhanCer/2-reduce2func-instCombine.sh: -------------------------------------------------------------------------------- 1 | # This script is an interestingness test script for C-reduce to hit InstCombine functions. 2 | gcc=gcc-11 3 | llvm=clang-13 4 | llvminst=/home/user42/git/cov/llvm-csmith-113/llvm-build-test-cases # REPLACE THIS WITH YOUR OWN COVERAGE INSTRUMENTED PATH 5 | 6 | src=instCombine.c 7 | includes="-Wno-unused-parameter -Wstrict-prototypes" 8 | 9 | rm -rf *.out 10 | rm -rf *out*.* 11 | rm -rf *.err.* 12 | 13 | ulimit -t 40 14 | 15 | $llvminst -O0 -pedantic -Wall -Wextra $includes $src -o llvminst.out >outc.txt 2>&1 &&\ 16 | $llvm -O0 -fsanitize=undefined -pedantic -Wall -Wextra $includes $src -o llvm.out >outa.txt 2>&1 &&\ 17 | ! grep 'conversions than data arguments' outa.txt &&\ 18 | ! grep 'incompatible redeclaration' outa.txt &&\ 19 | ! grep 'ordered comparison between pointer' outa.txt &&\ 20 | ! grep 'eliding middle term' outa.txt &&\ 21 | ! grep 'end of non-void function' outa.txt &&\ 22 | ! grep 'invalid in C99' outa.txt &&\ 23 | ! grep 'specifies type' outa.txt &&\ 24 | ! grep 'should return a value' outa.txt &&\ 25 | ! grep 'uninitialized' outa.txt &&\ 26 | ! grep 'incompatible pointer to' outa.txt &&\ 27 | ! grep 'incompatible integer to' outa.txt &&\ 28 | ! grep 'type specifier missing' outa.txt &&\ 29 | ! grep 'non-void function does not return a value' outa.txt &&\ 30 | ! grep 'missing-variable-declarations' outa.txt &&\ 31 | ! grep 'linker command failed with exit code 1' outa.txt &&\ 32 | ! grep 'at end of declaration list' outa.txt &&\ 33 | ! grep 'Wc2x-extensions' outa.txt &&\ 34 | ! grep 'was not declared, defaulting to type' outa.txt &&\ 35 | ! grep 'used in loop condition not modified in loop body' outa.txt &&\ 36 | ! grep 'Wgnu-empty-initializer' outa.txt &&\ 37 | ! grep 'Wgnu-statement-expression' outa.txt &&\ 38 | ! grep 'Wstrict-prototypes' outa.txt &&\ 39 | ! grep 'empty struct is a GNU extension' outa.txt &&\ 40 | $gcc -O0 -pedantic -Wall -Wextra $src $includes -o gcc.out >outb.txt 2>&1 &&\ 41 | ! grep 'ISO C does not support omitting parameter names in function definitions before C2X' outb.txt &&\ 42 | ! grep 'parameter name omitted' outb.txt &&\ 43 | ! grep '\-Wuninitialized' outb.txt &&\ 44 | ! grep 'without a cast' outb.txt &&\ 45 | ! grep 'expects a matching' outb.txt &&\ 46 | ! grep 'control reaches end' outb.txt &&\ 47 | ! grep 'no return statement' outb.txt &&\ 48 | ! grep 'return type defaults' outb.txt &&\ 49 | ! grep 'cast from pointer to integer' outb.txt &&\ 50 | ! grep 'useless type name in empty declaration' outb.txt &&\ 51 | ! grep 'no semicolon at end' outb.txt &&\ 52 | ! grep 'type defaults to' outb.txt &&\ 53 | ! grep 'too few arguments for format' outb.txt &&\ 54 | ! grep 'incompatible pointer' outb.txt | grep -ve'transparent_crc_bytes' &&\ 55 | ! grep 'ordered comparison of pointer with integer' outb.txt &&\ 56 | ! grep 'declaration does not declare anything' outb.txt &&\ 57 | ! grep 'expects type' outb.txt &&\ 58 | ! grep 'pointer from integer' outb.txt &&\ 59 | ! grep 'incompatible implicit' outb.txt &&\ 60 | ! grep 'excess elements in struct initializer' outb.txt &&\ 61 | ! grep 'comparison between pointer and integer' outb.txt &&\ 62 | ! grep 'assumed to have' outb.txt &&\ 63 | ! grep 'may be used uninitialized' outb.txt &&\ 64 | ! grep 'Wstrict-prototypes' outb.txt &&\ 65 | ! grep 'warning: excess elements in scalar initializer' outb.txt &&\ 66 | cat $src | grep 'puts("1");' &&\ 67 | cat $src | grep 'return 1;' &&\ 68 | ! ./llvminst.out 2>llvminst.err.txt > llvminst.out.txt &&\ 69 | ! ./llvm.out 2>llvm.err.txt > llvm.out.txt &&\ 70 | ! ./gcc.out 2>gcc.err.txt > gcc.out.txt &&\ 71 | ! cat llvminst.err.txt | grep "error" &&\ 72 | ! cat llvm.err.txt | grep "error" &&\ 73 | ! cat gcc.err.txt | grep "error" &&\ 74 | cat llvminst.out.txt | grep "__23__" &&\ 75 | diff llvminst.out.txt llvm.out.txt &&\ 76 | diff llvm.out.txt gcc.out.txt 77 | -------------------------------------------------------------------------------- /scripts/enhanCer/README.md: -------------------------------------------------------------------------------- 1 | # enhanCer 2 | 3 | The enhanCer is a set of scripts that are part of GrayC. It has two main functionalities: 4 | 5 | - The first takes a program and injects Csmith function calls thus the resultant program prints checksum in the end. 6 | 7 | - The other takes a fuzzed program that hits new coverage and transforms it into a small test for the LLVM test suite. 8 | 9 | - Another basic version of the second set generate a report of difference between two test suites' coverage. 10 | 11 | Scripts here start with (1-) or (2-) according to which functionality they perform. 12 | 13 | ## Requirements 14 | 15 | To be able to run these scripts you will need to install several packages: 16 | 17 | - Install Csmith 18 | - Install C-reduce 19 | 20 | For script 1-3-transform.py: 21 | ``` 22 | sudo apt-get install ctags 23 | sudo apt install python3 24 | sudo apt install python3-pip 25 | pip3 install pandas 26 | ``` 27 | 28 | ## Run the enhanCer (part-1) 29 | 30 | To transform programs to have a checksum print in the end (we used the Csmith mechanism to do so, but you can pull these and implement yours): 31 | ``` 32 | ./1-main-enhanCer-option-1.sh <1-2-zip-or-folder> 33 | ``` 34 | 35 | ## Run the enhanCer (part-2) 36 | 37 | TODO: need to copy from private repository. 38 | 39 | 40 | ## Run the enhanCer - coverage 41 | 42 | The following set of scripts takes coverage of two test suits and generate the delta of coverage between the first test suite and the second test suite. 43 | 44 | Start with measuring coverage of both test suites. 45 | -------------------------------------------------------------------------------- /scripts/enhanCer/examples/A_013d6729c7184ba4be35f0909cbbe8e9_2801_test251877490_copy.c: -------------------------------------------------------------------------------- 1 | #include "csmith.h" 2 | int make_global(char *); 3 | int make_global_a_b_o_r_t(); 4 | int make_global_e_x_i_t(); 5 | char __wrapper_val[256]="I"; 6 | 7 | 8 | /* corpus/013d6729c7184ba4be35f0909cbbe8e9_2801_test251877490.c */ 9 | #include "csmith.h" 10 | union a { 11 | uint32_t b; 12 | }; 13 | static uint8_t c[][1]={1}; 14 | static uint32_t d = 5; 15 | static int32_t e=0; 16 | static uint64_t f=0; 17 | static uint64_t *g = &f; 18 | static uint64_t *h = &g; 19 | static uint64_t ***i = &h; 20 | static uint16_t j=0; 21 | static uint32_t k=0; 22 | static uint16_t l=0; 23 | static uint16_t volatile *m = &l; 24 | static int32_t *n(union a, uint64_t, uint32_t); 25 | int32_t o() { 26 | union a p = {7}; 27 | n(p, ***i, 0); 28 | return 8; 29 | } 30 | int32_t *n(union a q, uint64_t r, uint32_t s) { 31 | int32_t t = &k == d; 32 | if(t ^= c[e][j] != q.b) 33 | *m; 34 | return 0; 35 | } 36 | int func_0() /* OK */ { 37 | int u = o(); 38 | platform_main_end(5, u); 39 | } 40 | 41 | int i_csmith_transform = 0; 42 | int i_print_hash_value = 0; 43 | int make_global_a_b_o_r_t(){ 44 | transparent_crc(i_csmith_transform, "abort call", i_print_hash_value); 45 | i_csmith_transform=i_csmith_transform+1; 46 | return 0; 47 | } 48 | 49 | int make_global_e_x_i_t(){ 50 | transparent_crc(i_csmith_transform, "abort exit", i_print_hash_value); 51 | i_csmith_transform=i_csmith_transform+1; 52 | return 0; 53 | } 54 | 55 | int make_global(char *val){ 56 | if ((val == 0) || (strlen(val) == 0)) { 57 | transparent_crc(i_csmith_transform, "empty string", i_print_hash_value); 58 | } else { 59 | char name[100]; sprintf(name, "gprnt%d", i_csmith_transform); 60 | transparent_crc_bytes(val, strlen(val), name , i_print_hash_value); 61 | } 62 | i_csmith_transform=i_csmith_transform+1; 63 | return 0; 64 | } 65 | int main(int argc, char* argv[]){ 66 | if (argc == 2 && strcmp(argv[1], "1") == 0) i_print_hash_value = 1; 67 | platform_main_begin(); 68 | crc32_gentab(); 69 | 70 | func_0(); /* Original main of the program */ 71 | make_global(__wrapper_val); /* Print the last use of the wrapper, or if never used it will print empty string */ 72 | for (int i_0_0 = 0 ; i_0_0 < 1; i_0_0++){ 73 | for (int i_0_1 = 0 ; i_0_1 < 1; i_0_1++){ 74 | transparent_crc(c[i_0_0][i_0_1], "c[i_0_0][i_0_1]", i_print_hash_value); 75 | } 76 | } 77 | transparent_crc(d, "d", i_print_hash_value); 78 | transparent_crc(e, "e", i_print_hash_value); 79 | transparent_crc(f, "f", i_print_hash_value); 80 | if (g != 0) 81 | transparent_crc((*g), "(*g)", i_print_hash_value); 82 | if (h != 0) 83 | transparent_crc((*h), "(*h)", i_print_hash_value); 84 | if (i != 0) 85 | transparent_crc((***i), "(***i)", i_print_hash_value); 86 | transparent_crc(j, "j", i_print_hash_value); 87 | transparent_crc(k, "k", i_print_hash_value); 88 | transparent_crc(l, "l", i_print_hash_value); 89 | if (m != 0) 90 | transparent_crc((*m), "(*m)", i_print_hash_value); 91 | platform_main_end(crc32_context ^ 0xFFFFFFFFUL, i_print_hash_value); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /scripts/enhanCer/examples/A_20010116-1_copy.c: -------------------------------------------------------------------------------- 1 | #include "csmith.h" 2 | int make_global(char *); 3 | int make_global_a_b_o_r_t(); 4 | int make_global_e_x_i_t(); 5 | char __wrapper_val[256]="I"; 6 | 7 | 8 | /* corpus/20010116-1.c */ 9 | /* Distilled from optimization/863. */ 10 | 11 | extern void abort (void); 12 | extern void exit (int); 13 | extern void ok (int); 14 | 15 | typedef struct 16 | { 17 | int x, y, z; 18 | } Data; 19 | 20 | void find (Data *first, Data *last) 21 | { 22 | int i; 23 | for (i = (last - first) >> 2; i > 0; --i) 24 | ok(i); 25 | make_global_a_b_o_r_t(); return; abort (); 26 | } 27 | 28 | void ok(int i) 29 | { 30 | if (i != 1) 31 | { make_global_a_b_o_r_t(); return; abort (); } 32 | return ; 33 | } 34 | 35 | int func_0() /* OK */ 36 | { 37 | Data DataList[4]; 38 | find (DataList + 0, DataList + 4); 39 | } 40 | 41 | int i_csmith_transform = 0; 42 | int i_print_hash_value = 0; 43 | int make_global_a_b_o_r_t(){ 44 | transparent_crc(i_csmith_transform, "abort call", i_print_hash_value); 45 | i_csmith_transform=i_csmith_transform+1; 46 | return 0; 47 | } 48 | 49 | int make_global_e_x_i_t(){ 50 | transparent_crc(i_csmith_transform, "abort exit", i_print_hash_value); 51 | i_csmith_transform=i_csmith_transform+1; 52 | return 0; 53 | } 54 | 55 | int make_global(char *val){ 56 | if ((val == 0) || (strlen(val) == 0)) { 57 | transparent_crc(i_csmith_transform, "empty string", i_print_hash_value); 58 | } else { 59 | char name[100]; sprintf(name, "gprnt%d", i_csmith_transform); 60 | transparent_crc_bytes(val, strlen(val), name , i_print_hash_value); 61 | } 62 | i_csmith_transform=i_csmith_transform+1; 63 | return 0; 64 | } 65 | int main(int argc, char* argv[]){ 66 | if (argc == 2 && strcmp(argv[1], "1") == 0) i_print_hash_value = 1; 67 | platform_main_begin(); 68 | crc32_gentab(); 69 | 70 | func_0(); /* Original main of the program */ 71 | make_global(__wrapper_val); /* Print the last use of the wrapper, or if never used it will print empty string */ 72 | platform_main_end(crc32_context ^ 0xFFFFFFFFUL, i_print_hash_value); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /scripts/enhanCer/examples/README.md: -------------------------------------------------------------------------------- 1 | This forlder contains some semi-manual examples of the enhancer part 1. 2 | -------------------------------------------------------------------------------- /scripts/general/1-download-gcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | working_folder=$1 3 | gcc_ver=$2 4 | 5 | # Downloading LLVM and Csmith sources, building Csmith 6 | TMP_SOURCE_FOLDER=$(mktemp -d $working_folder/.sources_$2V.XXXXXXX.tmp) 7 | cd $TMP_SOURCE_FOLDER 8 | ## Get gcc 9 | if [ -z "$2" ] ; then 10 | echo " >> Checking out master branch" 11 | git clone --depth 1 git://gcc.gnu.org/git/gcc.git 12 | else 13 | echo " >> Checking out releases/gcc-$gcc_ver tag" 14 | git clone git://gcc.gnu.org/git/gcc.git 15 | git checkout releases/gcc-"$gcc_ver" 16 | fi 17 | ## Get pre-req. isl-0.18.tar.bz2;gmp-6.1.0.tar.bz2;mpc-1.0.3.tar.gz; mpfr-3.1.4.tar.bz2 => works for gcc-10 18 | ## GMP 19 | wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 20 | bunzip2 gmp-6.1.0.tar.bz2 21 | tar xvf gmp-6.1.0.tar 22 | cd gmp-6.1.0 23 | ./configure --disable-shared --enable-static --prefix=/tmp/gcc 24 | make && make check && make install 25 | cd .. 26 | ## MPFR 27 | wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 28 | bunzip2 mpfr-3.1.4.tar.bz2 29 | tar xvf mpfr-3.1.4.tar 30 | cd mpfr-3.1.4 31 | ./configure --disable-shared --enable-static --prefix=/tmp/gcc --with-gmp=/tmp/gcc 32 | make && make check && make install 33 | cd .. 34 | ## MPC 35 | wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz 36 | tar zxvf mpc-1.0.3.tar.gz 37 | cd mpc-1.0.3 38 | ./configure --disable-shared --enable-static --prefix=/tmp/gcc --with-gmp=/tmp/gcc --with-mpfr=/tmp/gcc 39 | make && make check && make install 40 | cd .. 41 | ## ISL 42 | wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 43 | bunzip2 isl-0.18.tar.bz2 44 | tar xvf isl-0.18.tar 45 | cd isl-0.18 46 | ./configure --with-gmp-prefix=/tmp/gcc --disable-shared --enable-static --prefix=/tmp/isl 47 | make -j $THREADS && make install 48 | cd .. 49 | ## Cleaning 50 | rm gmp-6.1.0.tar 51 | rm isl-0.18.tar 52 | rm mpc-1.0.3.tar.gz 53 | rm mpfr-3.1.4.tar 54 | echo ">> Downloading GCC source ($TMP_SOURCE_FOLDER)" 55 | -------------------------------------------------------------------------------- /scripts/general/1-download-llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | working_folder=$1 3 | llvm_ver=$2 4 | 5 | # Downloading LLVM and Csmith sources, building Csmith 6 | TMP_SOURCE_FOLDER=$(mktemp -d $working_folder/.sources_$2VL.XXXXXXX.tmp) 7 | cd $TMP_SOURCE_FOLDER 8 | ## LLVM 9 | if [ -z "$2" ] ; then 10 | echo " >> Checking out main branch" 11 | git clone --depth 1 -b main https://github.com/llvm/llvm-project.git 12 | else 13 | echo " >> Checking out releases/gcc-$llvm_ver tag" 14 | git clone --depth 1 -b release/$llvm_ver.x https://github.com/llvm/llvm-project.git 15 | fi 16 | 17 | echo ">> Downloading LLVM source ($TMP_SOURCE_FOLDER)" 18 | 19 | ## CSMITH: 20 | cd $TMP_SOURCE_FOLDER 21 | git clone https://github.com/csmith-project/csmith.git 22 | cd ./csmith 23 | 24 | echo " >> Downloaded LLVM $llvm_ver and Csmith into $TMP_SOURCE_FOLDER." 25 | -------------------------------------------------------------------------------- /scripts/general/README.md: -------------------------------------------------------------------------------- 1 | # Download compilers source 2 | 3 | GrayC works with compiler source code. To download LLVM: 4 | ``` 5 | ./1-download-llvm.sh 6 | ``` 7 | and GCC: 8 | ``` 9 | ./1-download-gcc.sh 10 | ``` 11 | 12 | We recommend using swap files when building from source of these compilers. 13 | 14 | The current version of LLVM tested is LLVM-15. 15 | --------------------------------------------------------------------------------