diff --git a/.github/workflows/github-action.yml b/.github/workflows/github-action.yml index 7b38bae5f6..51e8dd0635 100644 --- a/.github/workflows/github-action.yml +++ b/.github/workflows/github-action.yml @@ -7,7 +7,7 @@ on: [push, pull_request] env: SVF_CTIR: 1 SVF_Z3: 1 - SVF_DIR: $GITHUB_WORKSPACE + SVF_DIR: ${{ github.workspace }} jobs: build: @@ -40,7 +40,10 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install cmake gcc g++ nodejs doxygen graphviz lcov libncurses5-dev libtinfo6 libzstd-dev astyle + sudo apt-get install -y cmake gcc g++ nodejs doxygen graphviz lcov libncurses5-dev libtinfo6 libzstd-dev astyle wget + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 22 # build-svf - name: build-svf @@ -49,6 +52,7 @@ jobs: echo $(pwd) if [ "${{matrix.sanitizer}}" != "" ]; then export SVF_SANITIZER="${{matrix.sanitizer}}"; fi if [ "$RUNNER_OS" == "Linux" ] && [ "${{matrix.sanitizer}}" == "" ]; then export SVF_COVERAGE=1; fi + export LLVM_DIR=/usr/lib/llvm-22 git clone "https://github.com/SVF-tools/Test-Suite.git"; source ${{github.workspace}}/build.sh @@ -173,3 +177,69 @@ jobs: verbose: true env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + windows-build: + name: windows-build (${{ matrix.compiler }}) + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + compiler: [mingw, msvc] + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies (MSVC only) + if: matrix.compiler == 'msvc' + shell: powershell + run: | + # 1. Install LLVM toolchain via Chocolatey (provides clang.exe) + choco install llvm -y + + # 2. Download and extract LLVM SDK from c3lang/llvm-for-c3 (provides LLVMConfig.cmake and static libraries) using curl.exe + curl.exe -L "https://github.com/c3lang/llvm-for-c3/releases/download/llvm_22.1.4/llvm-windows-amd64.tar.gz" -o llvm-sdk.tar.gz + New-Item -ItemType Directory -Force -Path C:\llvm-sdk | Out-Null + tar -xf llvm-sdk.tar.gz -C C:\llvm-sdk + + # 3. Copy Clang compiler binaries from Chocolatey LLVM to the SDK bin folder + Copy-Item -Path "C:\Program Files\LLVM\bin\clang.exe" -Destination "C:\llvm-sdk\bin\" -Force + Copy-Item -Path "C:\Program Files\LLVM\bin\clang++.exe" -Destination "C:\llvm-sdk\bin\" -Force + Copy-Item -Path "C:\Program Files\LLVM\bin\clang-cl.exe" -Destination "C:\llvm-sdk\bin\" -Force + + # 3.5. Strip the hardcoded MSVC diaguids.lib dependency from LLVMExports.cmake + $exportsFile = "C:\llvm-sdk\lib\cmake\llvm\LLVMExports.cmake" + if (Test-Path $exportsFile) { + $content = Get-Content $exportsFile -Raw + # Remove any absolute path ending in /DIA SDK/lib/amd64/diaguids.lib; + $newContent = $content -replace '[a-zA-Z]:/[^";]+?/DIA SDK/lib/amd64/diaguids\.lib;', "" + Set-Content $exportsFile $newContent -NoNewline + } + + # 4. Export environment variables using UTF-8 encoding + Add-Content -Path $env:GITHUB_PATH -Value "C:\llvm-sdk\bin" -Encoding UTF8 + Add-Content -Path $env:GITHUB_ENV -Value "LLVM_DIR=C:\llvm-sdk" -Encoding UTF8 + + - name: Add MSVC to PATH + if: matrix.compiler == 'msvc' + uses: ilammy/msvc-dev-cmd@v1 + + - name: Clone Test-Suite + shell: powershell + run: | + git clone "https://github.com/SVF-tools/Test-Suite.git" Test-Suite + + + - name: Build SVF + shell: powershell + run: | + if ("${{ matrix.compiler }}" -eq "msvc") { + powershell -ExecutionPolicy Bypass -File build.ps1 -BuildType Release -Compiler msvc -LLVMDir "$env:LLVM_DIR" + } else { + powershell -ExecutionPolicy Bypass -File build.ps1 -BuildType Release -Compiler mingw + } + + - name: Run CTests + shell: powershell + working-directory: ${{ github.workspace }}/Release-build + run: | + . ..\setup.ps1 Release + ctest --output-on-failure diff --git a/.github/workflows/svf-lib_binaries.yml b/.github/workflows/svf-lib_binaries.yml index c41c8241ba..335d361af9 100644 --- a/.github/workflows/svf-lib_binaries.yml +++ b/.github/workflows/svf-lib_binaries.yml @@ -102,7 +102,7 @@ jobs: if [ "$(uname -m)" == "x86_64" ]; then ctest -R diff-perf-cruxbc -VV git pull - cp -r ${{github.workspace}}/Release-build/Testing/Temporary/LastTest.log $GITHUB_WORKSPACE/Test-Suite/diff_tests/perf_history/perf-$(date +'%Y-%m-%dT%H:%M:%S').txt + cp -r ${{github.workspace}}/Release-build/Testing/Temporary/LastTest.log $GITHUB_WORKSPACE/Test-Suite/diff_tests/perf_history/perf-$(date +'%Y-%m-%dT%H-%M-%S').txt cp -r ${{github.workspace}}/Release-build/Testing/Temporary/LastTest.log $GITHUB_WORKSPACE/Test-Suite/diff_tests/perf-latest.txt cd $GITHUB_WORKSPACE/Test-Suite/diff_tests git add . diff --git a/.gitignore b/.gitignore index d62528d3b6..a77199e177 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,12 @@ doxygen/ *.svf cmake-build-debug/ compile_commands.json + +# Local agent files and logs +AGENTS.md +err.txt +wiki/ +docs/extending-handoffs/ +docs/images/ +svf-llvm/tools/GraphDB/ +docs/windows-port/IMPLEMENTATION-LOG.md diff --git a/CMakeLists.txt b/CMakeLists.txt index dc06781545..d1b7fd5e93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,17 @@ cmake_minimum_required(VERSION 3.23) +# Reset invalid cached compiler paths so project() can probe available compilers. +if(DEFINED CMAKE_C_COMPILER) + if(IS_ABSOLUTE "${CMAKE_C_COMPILER}" AND NOT EXISTS "${CMAKE_C_COMPILER}") + unset(CMAKE_C_COMPILER CACHE) + endif() +endif() +if(DEFINED CMAKE_CXX_COMPILER) + if(IS_ABSOLUTE "${CMAKE_CXX_COMPILER}" AND NOT EXISTS "${CMAKE_CXX_COMPILER}") + unset(CMAKE_CXX_COMPILER CACHE) + endif() +endif() + # ================================================================================= # SVF project definition # ================================================================================= @@ -14,6 +26,14 @@ project( # Export compile commands for clangd & IDE support set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +# Configure MSVC runtime library (default to static to match LLVM SDK, but allow override) +if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() +endif() # Set SVF's default C/C++ standards (C11/C++17) set(CMAKE_C_STANDARD 11) @@ -51,11 +71,12 @@ if(WIN32 OR MSYS OR CYGWIN ) - file( - COPY ${SVF_BINARY_DIR}/compile_commands.json - DESTINATION ${CMAKE_CURRENT_LIST_DIR} - RENAME compile_commands.json - ) + if(EXISTS ${SVF_BINARY_DIR}/compile_commands.json) + file( + COPY ${SVF_BINARY_DIR}/compile_commands.json + DESTINATION ${CMAKE_CURRENT_LIST_DIR} + ) + endif() else() file(CREATE_LINK ${SVF_BINARY_DIR}/compile_commands.json compile_commands.json COPY_ON_ERROR SYMBOLIC) endif() @@ -267,6 +288,13 @@ target_link_libraries(SvfFlags INTERFACE ${Z3_LIBRARIES}) # Ensure the interface library is exposed during installation install(TARGETS SvfFlags EXPORT SVFTargets) +# ================================================================================= +# SVF core definitions +# ================================================================================= + +add_subdirectory(svf) +add_subdirectory(svf-llvm) + # ================================================================================= # SVF test suite # ================================================================================= @@ -278,20 +306,17 @@ if(EXISTS "${SVF_SOURCE_DIR}/Test-Suite") add_subdirectory(Test-Suite) endif() -# ================================================================================= -# SVF core definitions -# ================================================================================= - -add_subdirectory(svf) -add_subdirectory(svf-llvm) - # ================================================================================= # SVF build configuration handling (post linking LLVM) # ================================================================================= # Expose the required ABI flags (e.g., whether RTTI was disabled) in the build & install trees -target_compile_options(SvfFlags INTERFACE $<$>:-fno-rtti>) -target_link_options(SvfFlags INTERFACE $<$>:-fno-rtti>) +if(MSVC) + target_compile_options(SvfFlags INTERFACE $<$>:/GR->) +else() + target_compile_options(SvfFlags INTERFACE $<$>:-fno-rtti>) + target_link_options(SvfFlags INTERFACE $<$>:-fno-rtti>) +endif() # Expose build/link flags not required for users of SVF only in the build tree target_compile_options( @@ -314,9 +339,9 @@ target_link_options( INTERFACE $:-Wall>> INTERFACE $:-Werror>> INTERFACE $:-Wno-deprecated-declarations>> - INTERFACE $:-fuse-ld=lld>> - INTERFACE $:-rdynamic>> - INTERFACE $:-Wl,--export-dynamic>> + INTERFACE $,$>>:-fuse-ld=lld>> + INTERFACE $,$>>:-rdynamic>> + INTERFACE $,$>>:-Wl,--export-dynamic>> INTERFACE $:-UNDEBUG>> INTERFACE $>:-fno-exceptions>> INTERFACE $,$>:-fprofile-arcs>> @@ -330,6 +355,7 @@ target_link_options( # ================================================================================= # (1) Generate config.h into /include/SVF/Util; (2) Install it under /include/SVF/Util +set(SVF_BUILD_DIR "${SVF_BINARY_DIR}") configure_file(${SVF_SOURCE_DIR}/cmake/SVFConfigHdr.cmake.in ${SVF_BINARY_DIR}/include/Util/config.h @ONLY) install(FILES ${SVF_BINARY_DIR}/include/Util/config.h DESTINATION ${SVF_INSTALL_INCLUDEDIR}/Util) diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..d34b67f306 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,347 @@ +<# +.SYNOPSIS + Builds SVF on Windows using llvm-mingw (clang++ with MinGW/UCRT runtime). + +.DESCRIPTION + Toolchain: llvm-mingw (clang++ + lld + libc++ + UCRT). + Does not require Visual Studio or MSYS2. + + LLVM_DIR points to the root of llvm-mingw, which contains both the compiler + (bin/clang++.exe) and the LLVM CMake files (lib/cmake/llvm/LLVMConfig.cmake). + + Z3 is compiled from source with the same toolchain to ensure + ABI compatibility. If Z3_DIR is already present, the step is skipped. + +.PARAMETER BuildType + Release (default) or Debug. + +.PARAMETER BuildSharedLibs + ON (default) for DLL, OFF for static libraries. + llvm-mingw includes RTTI, so ON works. + +.PARAMETER LLVMDir + Path to llvm-mingw. Default: .\llvm-mingw.obj + +.PARAMETER Z3Dir + Path to precompiled Z3 (layout: include/, lib/). Default: .\z3.obj + +.PARAMETER Jobs + Number of parallel jobs. Default: number of logical CPUs. + +.EXAMPLE + .\build.ps1 + .\build.ps1 -BuildType Debug + .\build.ps1 -BuildSharedLibs OFF + .\build.ps1 -LLVMDir C:\llvm-mingw -Z3Dir C:\z3-mingw +#> + +param( + [ValidateSet("Release", "Debug")] + [string]$BuildType = "Release", + + [ValidateSet("ON", "OFF")] + [string]$BuildSharedLibs = "OFF", + + [string]$LLVMDir = "", + [string]$Z3Dir = "", + + [ValidateSet("mingw", "msvc")] + [string]$Compiler = "mingw", + + [int]$Jobs = [Environment]::ProcessorCount +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$SVFHome = $ScriptDir + +# MSYS2 LLVM and Clang SDK packages. +# We download the local LLVM + Clang SDK from MSYS2 repository. +$LLVMSdkHome = Join-Path $SVFHome "llvm-sdk.obj" +$LLVMSdkUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-22.1.8-2-any.pkg.tar.zst" +$LLVMLibsUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-libs-22.1.8-2-any.pkg.tar.zst" +$LLVMToolsUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-llvm-tools-22.1.8-2-any.pkg.tar.zst" +$ClangUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-22.1.8-2-any.pkg.tar.zst" +$ClangLibsUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-clang-libs-22.1.8-2-any.pkg.tar.zst" +$CompilerRtUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-compiler-rt-22.1.8-2-any.pkg.tar.zst" +$LldUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-lld-22.1.8-2-any.pkg.tar.zst" +$CrtUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-crt-14.0.0.r98.g19f5121a2-1-any.pkg.tar.zst" +$HeadersUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-headers-14.0.0.r98.g19f5121a2-1-any.pkg.tar.zst" +$WinpthreadsUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-winpthreads-14.0.0.r98.g19f5121a2-1-any.pkg.tar.zst" +$LibwinpthreadUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libwinpthread-14.0.0.r98.g19f5121a2-1-any.pkg.tar.zst" +$LibffiUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libffi-3.7.1-1-any.pkg.tar.zst" +$Libxml2Url = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libxml2-2.15.3-1-any.pkg.tar.zst" +$ZstdUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zstd-1.5.7-2-any.pkg.tar.zst" +$ZlibUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-zlib-1.3.2-2-any.pkg.tar.zst" +$LibiconvUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libiconv-1.19-1-any.pkg.tar.zst" +$LibcxxUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libc%2B%2B-22.1.8-1-any.pkg.tar.zst" +$LibunwindUrl = "https://repo.msys2.org/mingw/clang64/mingw-w64-clang-x86_64-libunwind-22.1.8-1-any.pkg.tar.zst" + + +$Z3Ver = "4.15.4" +$Z3SrcUrl = "https://github.com/Z3Prover/z3/archive/refs/tags/z3-${Z3Ver}.zip" +$Z3Home = Join-Path $SVFHome "z3.obj" + +# --------------------------------------------------------------------------- +# Helper functions +# --------------------------------------------------------------------------- + +function Get-FileDownload { + param([string]$Url, [string]$Dest) + if (Test-Path $Dest) { + if ((Get-Item $Dest).Length -gt 1000) { + Write-Host " Already present: $Dest" + return + } else { + Remove-Item $Dest -ErrorAction SilentlyContinue + } + } + + $maxAttempts = 3 + $attempt = 1 + $success = $false + + while ($attempt -le $maxAttempts -and -not $success) { + try { + Write-Host " Downloading: $Url (Attempt $attempt of $maxAttempts)..." + Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing -TimeoutSec 180 + $success = $true + } catch { + Write-Host " Attempt $attempt failed: $_" -ForegroundColor Yellow + if (Test-Path $Dest) { Remove-Item $Dest -Force -ErrorAction SilentlyContinue } + $attempt++ + if ($attempt -le $maxAttempts) { + Write-Host " Waiting 5 seconds before the next attempt..." + Start-Sleep -Seconds 5 + } + } + } + + if (-not $success) { + throw "Download failed after $maxAttempts attempts for URL: $Url" + } +} + +function Assert-Tool { + param([string]$Name) + if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) { + throw "Tool not found in PATH: '$Name'. Verify prerequisites (cmake, ninja)." + } +} + +function Write-Step { + param([string]$Msg) + Write-Host "" + Write-Host "==> $Msg" -ForegroundColor Cyan +} + +# --------------------------------------------------------------------------- +# Resolve LLVM SDK and Compiler Toolchain (LLVM_DIR) +# --------------------------------------------------------------------------- + +Write-Step "Resolving LLVM SDK & Compiler Toolchain" + +if ($LLVMDir -ne "" -and (Test-Path $LLVMDir)) { + $env:LLVM_DIR = (Resolve-Path $LLVMDir).Path + Write-Host " Using provided LLVM SDK: $env:LLVM_DIR" +} elseif ($env:LLVM_DIR -and (Test-Path $env:LLVM_DIR)) { + Write-Host " Using LLVM_DIR from environment: $env:LLVM_DIR" +} else { + if ($Compiler -eq "mingw") { + $LLVMSdkDir = Join-Path $LLVMSdkHome "clang64" + if (-not (Test-Path $LLVMSdkDir)) { + Write-Host " Unified LLVM & Clang SDK not found. Automatic download in progress..." + New-Item -ItemType Directory -Force -Path $LLVMSdkHome | Out-Null + + $sdkComponents = @( + @{ Name = "llvm-sdk"; Url = $LLVMSdkUrl; File = "llvm-sdk.pkg.tar.zst" } + @{ Name = "llvm-libs"; Url = $LLVMLibsUrl; File = "llvm-libs.pkg.tar.zst" } + @{ Name = "llvm-tools"; Url = $LLVMToolsUrl; File = "llvm-tools.pkg.tar.zst" } + @{ Name = "clang-compiler"; Url = $ClangUrl; File = "clang-compiler.pkg.tar.zst" } + @{ Name = "clang-libs"; Url = $ClangLibsUrl; File = "clang-libs.pkg.tar.zst" } + @{ Name = "compiler-rt"; Url = $CompilerRtUrl; File = "compiler-rt.pkg.tar.zst" } + @{ Name = "lld-linker"; Url = $LldUrl; File = "lld-linker.pkg.tar.zst" } + @{ Name = "crt"; Url = $CrtUrl; File = "crt.pkg.tar.zst" } + @{ Name = "headers"; Url = $HeadersUrl; File = "headers.pkg.tar.zst" } + @{ Name = "winpthreads"; Url = $WinpthreadsUrl; File = "winpthreads.pkg.tar.zst" } + @{ Name = "libwinpthread"; Url = $LibwinpthreadUrl; File = "libwinpthread.pkg.tar.zst" } + @{ Name = "libffi"; Url = $LibffiUrl; File = "libffi.pkg.tar.zst" } + @{ Name = "libxml2"; Url = $Libxml2Url; File = "libxml2.pkg.tar.zst" } + @{ Name = "zstd"; Url = $ZstdUrl; File = "zstd.pkg.tar.zst" } + @{ Name = "zlib"; Url = $ZlibUrl; File = "zlib.pkg.tar.zst" } + @{ Name = "libiconv"; Url = $LibiconvUrl; File = "libiconv.pkg.tar.zst" } + @{ Name = "libc++"; Url = $LibcxxUrl; File = "libcxx.pkg.tar.zst" } + @{ Name = "libunwind"; Url = $LibunwindUrl; File = "libunwind.pkg.tar.zst" } + ) + + foreach ($comp in $sdkComponents) { + $compPath = Join-Path $SVFHome $comp.File + Get-FileDownload -Url $comp.Url -Dest $compPath + Write-Host " Extracting $($comp.Name) (tar)..." + & tar -xf $compPath -C $LLVMSdkHome + Remove-Item $compPath + } + + Write-Host " LLVM SDK and Compiler Toolchain installed in: $LLVMSdkDir" -ForegroundColor Green + } + $env:LLVM_DIR = $LLVMSdkDir + Write-Host " Using local LLVM SDK: $env:LLVM_DIR" + } else { + $defaultMsvcLvm = "C:\Program Files\LLVM" + if (Test-Path $defaultMsvcLvm) { + $env:LLVM_DIR = $defaultMsvcLvm + Write-Host " Using default MSVC LLVM SDK: $env:LLVM_DIR" + } else { + throw "LLVM SDK not found. For MSVC, please install LLVM (e.g., choco install llvm) or specify -LLVMDir." + } + } +} + +# Add LLVM_DIR\bin to PATH for compiler executables and library DLLs +$env:PATH = "$env:LLVM_DIR\bin;$env:PATH" + +# Verify that clang++ is available +Assert-Tool "clang++" +$clangVer = & clang++ --version | Select-Object -First 1 +Write-Host " Compiler: $clangVer" + +# --------------------------------------------------------------------------- +# Resolve Z3_DIR (compiling from source with llvm-mingw) +# --------------------------------------------------------------------------- + +Write-Step "Resolving Z3_DIR" + +if ($Z3Dir -ne "" -and (Test-Path $Z3Dir)) { + $env:Z3_DIR = (Resolve-Path $Z3Dir).Path + Write-Host " Using provided Z3Dir: $env:Z3_DIR" +} elseif ($env:Z3_DIR -and (Test-Path $env:Z3_DIR)) { + Write-Host " Using Z3_DIR from environment: $env:Z3_DIR" +} elseif (Test-Path $Z3Home) { + $env:Z3_DIR = $Z3Home + Write-Host " Found local Z3: $env:Z3_DIR" +} else { + Write-Host " Z3 not found. Compiling from source with llvm-mingw..." + Write-Host " (The prebuilt Z3 binary for Windows uses the MSVC ABI - incompatible with MinGW)" + + Assert-Tool "cmake" + Assert-Tool "ninja" + + $z3ZipPath = "$SVFHome\z3-src.zip" + $z3SrcDir = "$SVFHome\z3-source" + $z3BuildDir = "$SVFHome\z3-build" + + Get-FileDownload -Url $Z3SrcUrl -Dest $z3ZipPath + Write-Host " Extracting Z3 sources..." + if (Test-Path $z3SrcDir) { Remove-Item -Recurse -Force $z3SrcDir } + Expand-Archive -Path $z3ZipPath -DestinationPath $SVFHome -Force + # The internal folder name is z3-z3-4.8.8 (or z3-z3-) + $z3ExtractedName = "z3-z3-${Z3Ver}" + Rename-Item "$SVFHome\$z3ExtractedName" $z3SrcDir + + Write-Host " CMake configuration for Z3..." + New-Item -ItemType Directory -Force -Path $z3BuildDir | Out-Null + $z3CmakeArgs = @( + "-G", "Ninja", + "-S", $z3SrcDir, + "-B", $z3BuildDir, + "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_INSTALL_PREFIX=$Z3Home", + "-DZ3_BUILD_LIBZ3_SHARED=OFF", + "-DZ3_BUILD_EXECUTABLE=OFF", + "-DZ3_BUILD_TEST_EXECUTABLES=OFF", + "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded" + ) + if ($Compiler -eq "mingw") { + $z3CmakeArgs += "-DCMAKE_C_COMPILER=$env:LLVM_DIR\bin\clang.exe" + $z3CmakeArgs += "-DCMAKE_CXX_COMPILER=$env:LLVM_DIR\bin\clang++.exe" + } + & cmake @z3CmakeArgs + if ($LASTEXITCODE -ne 0) { throw "CMake configuration for Z3 failed." } + + Write-Host " Building Z3 (static library)..." + & cmake --build $z3BuildDir --parallel $Jobs + if ($LASTEXITCODE -ne 0) { throw "Build Z3 failed." } + + Write-Host " Installing Z3 in $Z3Home..." + & cmake --install $z3BuildDir + if ($LASTEXITCODE -ne 0) { throw "Z3 installation failed." } + + Remove-Item -Recurse -Force $z3SrcDir, $z3BuildDir, $z3ZipPath + $env:Z3_DIR = $Z3Home + Write-Host " Z3 installed in: $env:Z3_DIR" -ForegroundColor Green +} + +Write-Host "" +Write-Host " LLVM_DIR = $env:LLVM_DIR" +Write-Host " Z3_DIR = $env:Z3_DIR" + +# --------------------------------------------------------------------------- +# Verify build tools +# --------------------------------------------------------------------------- + +Write-Step "Verifying build tools" +Assert-Tool "cmake" +Assert-Tool "ninja" +$cmakeVer = cmake --version | Select-Object -First 1 +$ninjaVer = ninja --version +Write-Host " cmake: $cmakeVer" +Write-Host " ninja: $ninjaVer" + +# --------------------------------------------------------------------------- +# CMake configure and build SVF +# --------------------------------------------------------------------------- + +Write-Step "Configuring and building SVF" + +$BuildDir = Join-Path $SVFHome "$BuildType-build" +$LLVMCMakeDir = Join-Path $env:LLVM_DIR "lib\cmake\llvm" + +if (-not (Test-Path $LLVMCMakeDir)) { + Write-Host "[ERROR] LLVMConfig.cmake not found in '$LLVMCMakeDir'." -ForegroundColor Red + Write-Host "Note: llvm-mingw is only the compiler toolchain (clang/clang++) and does not contain the LLVM development SDK." -ForegroundColor Yellow + Write-Host "To resolve this, you can:" -ForegroundColor Yellow + Write-Host " 1. Compile LLVM from source with RTTI enabled and pass the path with '-LLVMDir '." -ForegroundColor Yellow + Write-Host " 2. Use MSYS2 (recommended for MinGW) by installing the 'mingw-w64-clang-x86_64-llvm' package and running './build.sh'." -ForegroundColor Yellow + throw "LLVM SDK not configured correctly." +} + +if (Test-Path $BuildDir) { Remove-Item -Recurse -Force $BuildDir } +New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null + +Write-Host " BuildType: $BuildType" +Write-Host " BuildSharedLibs: $BuildSharedLibs" +Write-Host " BuildDir: $BuildDir" + +$svfCmakeArgs = @( + "-G", "Ninja", + "-S", $SVFHome, + "-B", $BuildDir, + "-DCMAKE_BUILD_TYPE=$BuildType", + "-DLLVM_DIR=$LLVMCMakeDir", + "-DZ3_DIR=$env:Z3_DIR", + "-DBUILD_SHARED_LIBS=$BuildSharedLibs", + "-DSVF_WARN_AS_ERROR=OFF", + "-DSVF_EXPORT_DYNAMIC=OFF", + "-DCMAKE_CXX_STANDARD=17", + "-DCMAKE_CXX_STANDARD_REQUIRED=ON" +) +if ($Compiler -eq "mingw") { + $svfCmakeArgs += "-DCMAKE_C_COMPILER=$env:LLVM_DIR\bin\clang.exe" + $svfCmakeArgs += "-DCMAKE_CXX_COMPILER=$env:LLVM_DIR\bin\clang++.exe" +} elseif ($Compiler -eq "msvc") { + $svfCmakeArgs += "-DCMAKE_C_COMPILER=cl" + $svfCmakeArgs += "-DCMAKE_CXX_COMPILER=cl" +} +& cmake @svfCmakeArgs + +if ($LASTEXITCODE -ne 0) { throw "CMake configure SVF failed." } + +& cmake --build $BuildDir --parallel $Jobs + +if ($LASTEXITCODE -ne 0) { throw "Build SVF failed." } + +Write-Host "" +Write-Host "Build completed in: $BuildDir" -ForegroundColor Green +Write-Host "Run '. .\setup.ps1' to configure the environment." diff --git a/build.sh b/build.sh index 6eb7e918e3..50853f8f23 100755 --- a/build.sh +++ b/build.sh @@ -107,29 +107,40 @@ normalise_options() { } detect_platform() { - case "${sysOS}-${arch}" in - Linux-x86_64|Linux-amd64) - PLATFORM="ubuntu-x86_64" - ;; - Linux-aarch64|Linux-arm64) - PLATFORM="ubuntu-aarch64" - ;; - Darwin-arm64) - PLATFORM="macos-arm64" - ;; - Darwin-x86_64|Darwin-amd64) - PLATFORM="macos-x86_64" + case "${sysOS}" in + MINGW*|MSYS*|CYGWIN*) + PLATFORM="windows-mingw" ;; *) - echo "Unsupported platform: ${sysOS}/${arch}" - echo "Supported platforms: Linux x86_64, Linux aarch64/arm64, macOS arm64, macOS x86_64." - exit 1 + case "${sysOS}-${arch}" in + Linux-x86_64|Linux-amd64) + PLATFORM="ubuntu-x86_64" + ;; + Linux-aarch64|Linux-arm64) + PLATFORM="ubuntu-aarch64" + ;; + Darwin-arm64) + PLATFORM="macos-arm64" + ;; + Darwin-x86_64|Darwin-amd64) + PLATFORM="macos-x86_64" + ;; + *) + echo "Unsupported platform: ${sysOS}/${arch}" + echo "Supported platforms: Linux x86_64, Linux aarch64/arm64, macOS arm64, macOS x86_64, Windows MinGW/MSYS2." + exit 1 + ;; + esac ;; esac } select_dependency_urls() { case "$PLATFORM" in + windows-mingw) + urlLLVM="https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVMVer}/clang+llvm-${LLVMVer}-x86_64-pc-windows-msvc.tar.xz" + urlZ3="https://github.com/Z3Prover/z3/releases/download/z3-${Z3Ver}/z3-${Z3Ver}-x64-win.zip" + ;; ubuntu-x86_64) if [[ "$RTTI" == "ON" ]]; then urlLLVM="$UbuntuLLVM_RTTI" @@ -286,7 +297,7 @@ ensure_llvm() { macos-*) install_llvm_with_brew ;; - ubuntu-*) + ubuntu-*|windows-mingw) download_llvm_prebuilt ;; *) @@ -396,6 +407,7 @@ configure_runtime_env() { build_svf() { local build_dir="./${BUILD_TYPE}-build" local cmake_rpath_args=() + local cmake_generator_args=() if [[ "$sysOS" == "Darwin" ]]; then cmake_rpath_args=( @@ -405,13 +417,26 @@ build_svf() { ) fi + if [[ "$PLATFORM" == "windows-mingw" ]]; then + cmake_generator_args=( + -G "Ninja" + -DCMAKE_C_COMPILER=clang + -DCMAKE_CXX_COMPILER=clang++ + -DSVF_WARN_AS_ERROR=OFF + -DSVF_EXPORT_DYNAMIC=OFF + ) + fi + rm -rf "$build_dir" mkdir "$build_dir" cmake -D CMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \ -DSVF_ENABLE_ASSERTIONS:BOOL=true \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ ${SVF_SANITIZER:+-DSVF_SANITIZE="$SVF_SANITIZER"} \ -DBUILD_SHARED_LIBS="$BUILD_DYN_LIB" \ + "${cmake_generator_args[@]}" \ "${cmake_rpath_args[@]}" \ -S "$SVFHOME" -B "$build_dir" diff --git a/docs/windows-port/README.md b/docs/windows-port/README.md new file mode 100644 index 0000000000..1177dca2a7 --- /dev/null +++ b/docs/windows-port/README.md @@ -0,0 +1,126 @@ +--- +title: "SVF Windows Port — Guide & Documentation" +tags: + - svf + - documentation + - ide + - setup + - build + - pointer-analysis + - saber + - llvm + - testing + - windows +--- + +# SVF Windows Port — Guide & Documentation + +This directory contains the documentation for compiling and running **SVF** on Windows. The port is built using a modern, standalone **PowerShell + llvm-mingw** toolchain, which requires no emulation layers (MSYS2) or heavy installations (Visual Studio). + +--- + +## 1. Overview & Architecture + +The Windows port uses the **llvm-mingw** (LLVM-Clang with MinGW/UCRT runtime) compiler toolchain. + +| Aspect | PowerShell + llvm-mingw (Recommended) | +|---|---| +| **Build Shell** | PowerShell (`build.ps1` / `setup-windows.ps1`) | +| **Compiler** | `clang++` via llvm-mingw (MinGW ABI) | +| **C/C++ Runtime** | Universal CRT (UCRT) | +| **POSIX Headers** | Provided natively by MinGW-w64 | +| **LLVM SDK** | Portable MSYS2 Clang64 LLVM package (~80 MB) | +| **Build Type** | Static libraries (`BuildSharedLibs = OFF`) | + +> [!IMPORTANT] +> **Static Build Recommendation:** +> Building dynamic libraries (`BUILD_SHARED_LIBS=ON`) on Windows is unstable due to C++ class symbols not being exported by default in DLLs. Always prefer static builds (`-BuildSharedLibs OFF`), which is the default in both script configurations. + +--- + +## 2. Scripts Description & Status + +All Windows build and environment scripts are located in the SVF root directory and are **fully functional**: + +1. **[setup-windows.ps1](../../setup-windows.ps1)** + - **Status:** Fully Functional. + - **Purpose:** All-in-one requirements validator. Verifies system tools, sets the execution policy, installs `cmake` and `ninja` via `winget` if missing, and then delegates execution to `build.ps1`. + +2. **[build.ps1](../../build.ps1)** + - **Status:** Fully Functional. + - **Purpose:** Downloads and extracts the `llvm-mingw` compiler toolchain, downloads the LLVM 22.x SDK & dependencies, compiles the Z3 solver from source using MinGW, and runs CMake/Ninja to compile SVF statically. + +3. **[setup.ps1](../../setup.ps1)** + - **Status:** Fully Functional. + - **Purpose:** Environment configuration script. Must be dot-sourced (`. .\setup.ps1`) to append the directories of `llvm-mingw` DLLs, `llvm-sdk` tools, Z3, and the newly built SVF binaries to the environment `PATH`. + +--- + +## 3. Quickstart Build Guide + +To build SVF on a clean Windows machine: + +1. Open a PowerShell terminal. +2. Clone the repository and navigate into it: + ```powershell + git clone https://github.com/SVF-tools/SVF.git + cd SVF + ``` +3. Run the setup script to install tools and build the project: + ```powershell + .\setup-windows.ps1 + ``` + *(Note: This automatically defaults to a static build and downloads all required compile-time dependencies).* + +4. Source the environment to make SVF tools executable: + ```powershell + . .\setup.ps1 + ``` + +5. Verify the build: + ```powershell + wpa.exe --help + ``` + +--- + +## 4. Running the Test Suite (CTest) + +To verify the build using the SVF test cases: + +1. Clone the `Test-Suite` submodule inside the SVF folder if you haven't already, using sparse checkout to avoid invalid NTFS filenames containing colons (`:`): + ```powershell + git clone --sparse https://github.com/SVF-tools/Test-Suite.git + cd Test-Suite + git sparse-checkout set --cone "src" "test_cases_bc" + git checkout HEAD -- .github .gitignore .travis.yml CMakeLists.txt README.md aliascheck.h clean.sh diff_tests/difftest.py diff_tests/perf-latest.txt diff_tests/perf_compare.py diff_tests/requirements.txt doublefree_check.h generate_bc.sh memleak_check.h std_testcase.h type_check.h + cd .. + ``` +2. Re-run CMake to register the tests, then run `ctest`: + ```powershell + cmake -S . -B Release-build + cd Release-build + ``` +3. Run parallel-safe tests (Andersen, CFL, Saber, AE): + ```powershell + ctest -E "diff_tests-wr" -j 8 --output-on-failure + ``` +4. Run read-write differential tests sequentially to avoid parallel file-writing conflicts: + ```powershell + ctest -R "diff_tests-wr" -j 1 --output-on-failure + ``` + +--- + +## 5. Pathnames and Special Notes + + + +--- + +## 6. Document Directory + +- [minimal-dependencies.md](minimal-dependencies.md): Details of compiler toolchain & SDK archives structure. +- [patch-cpp-sources.md](patch-cpp-sources.md): Explanation of preprocessor guards added to C++ source files. +- [testing-windows.md](testing-windows.md): Local environment verification steps. +- [IMPLEMENTATION-LOG.md](IMPLEMENTATION-LOG.md): Full engineering log of the porting process. diff --git a/docs/windows-port/build-sh-windows.md b/docs/windows-port/build-sh-windows.md new file mode 100644 index 0000000000..61d25ae9e3 --- /dev/null +++ b/docs/windows-port/build-sh-windows.md @@ -0,0 +1,207 @@ +--- +title: "Modifications to `build.sh` for Windows (MSYS2 + MinGW-w64 + Clang)" +tags: + - svf + - documentation + - setup + - build + - llvm + - windows + - api +--- + +# Modifications to `build.sh` for Windows (MSYS2 + MinGW-w64 + Clang) + +This file describes each modification to be applied to `build.sh`, with the exact context of where and how to insert it. + +--- + +## Modification 1 — Adding Windows URLs (after line 35) + +**Location:** immediately after the line `SourceZ3="..."`, before the `LLVMHome=...` block. + +```bash +# Windows binaries (MSYS2 CLANG64 environment) +WindowsLLVM_RTTI="https://github.com/SVF-tools/SVF/releases/download/SVF-3.1/llvm-16.0.0-win64-rtti.tar.gz" +WindowsLLVM="https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVMVer}/clang+llvm-${LLVMVer}-x86_64-pc-windows-msvc.tar.xz" +WindowsZ3="https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-win.zip" +``` + +> **Warning:** `WindowsLLVM_RTTI` points to a custom SVF binary with RTTI enabled. +> If SVF has not published a Windows binary yet, always use `WindowsLLVM` and +> compile with `./build.sh sta_lib nortti`. + +--- + +## Modification 2 — Adding the `check_msys2_deps` function (after `check_and_install_brew`) + +```bash +function check_msys2_deps { + local missing=() + for tool in clang++ clang cmake ninja unzip curl; do + if ! command -v "$tool" &>/dev/null; then + missing+=("$tool") + fi + done + if [[ ${#missing[@]} -gt 0 ]]; then + echo "ERROR: missing tools in the MSYS2 CLANG64 environment:" + echo " ${missing[*]}" + echo "" + echo "Run in MSYS2:" + echo " pacman -S mingw-w64-clang-x86_64-toolchain" + echo " pacman -S mingw-w64-clang-x86_64-cmake" + echo " pacman -S mingw-w64-clang-x86_64-ninja" + exit 1 + fi +} +``` + +--- + +## Modification 3 — Extending the OS detection block (lines 190–215) + +**Before (current):** +```bash +if [[ $sysOS == "Darwin" ]]; then + check_and_install_brew +elif [[ $sysOS == "Linux" ]]; then + if [[ "$arch" == "aarch64" ]]; then + ... + else + ... + fi +else + echo "Builds outside Ubuntu and macOS are not supported." +fi +``` + +**After:** +```bash +if [[ $sysOS == "Darwin" ]]; then + check_and_install_brew + # ... existing macOS logic unchanged ... + +elif [[ $sysOS == "Linux" ]]; then + # ... existing Linux logic unchanged ... + +elif [[ $sysOS == MINGW* || $sysOS == MSYS* || $sysOS == CYGWIN* ]]; then + check_msys2_deps + if [[ "$BUILD_DYN_LIB" == "ON" ]]; then + urlLLVM="$WindowsLLVM_RTTI" + else + if [[ "$RTTI" == "ON" ]]; then + urlLLVM="$WindowsLLVM_RTTI" + else + urlLLVM="$WindowsLLVM" + fi + fi + urlZ3="$WindowsZ3" + +else + echo "Builds outside Ubuntu, macOS and MSYS2/MinGW are not supported." + exit 1 +fi +``` + +--- + +## Modification 4 — Extracting LLVM for Windows + +**Location:** in the LLVM download block (after line 220), add a branch for Windows inside the `else` section (anything that is not Darwin): + +```bash +# Current line (approx. 237): +echo "Downloading LLVM binary for $OSDisplayName" +generic_download_file "$urlLLVM" llvm.tar.xz +check_xz +echo "Unzipping llvm package..." +mkdir -p "./$LLVMHome" && tar -xf llvm.tar.xz -C "./$LLVMHome" --strip-components 1 +rm llvm.tar.xz +``` + +If the LLVM Windows binary is distributed as a `.zip` instead of `.tar.xz`, add extension detection: + +```bash +if [[ $sysOS == MINGW* || $sysOS == MSYS* ]]; then + llvm_archive="llvm.zip" + generic_download_file "$urlLLVM" "$llvm_archive" + check_unzip + echo "Unzipping LLVM package..." + mkdir -p "./$LLVMHome" + unzip -q "$llvm_archive" -d "./$LLVMHome" && \ + # remove any root directory in the archive + shopt -s dotglob && \ + mv "./$LLVMHome"/clang+llvm-*/* "./$LLVMHome/" 2>/dev/null || true + rm "$llvm_archive" +else + llvm_archive="llvm.tar.xz" + generic_download_file "$urlLLVM" "$llvm_archive" + check_xz + echo "Unzipping LLVM package..." + mkdir -p "./$LLVMHome" && tar -xf "$llvm_archive" -C "./$LLVMHome" --strip-components 1 + rm "$llvm_archive" +fi +``` + +> **Note:** verify the internal structure of the chosen Windows LLVM archive before +> finalizing this block. The number of levels to strip depends on the specific archive. + +--- + +## Modification 5 — CMake block with generator and Windows flags + +**Location:** replace the cmake block (lines 299–304). + +**Before:** +```bash +cmake -D CMAKE_BUILD_TYPE:STRING="${BUILD_TYPE}" \ + -DSVF_ENABLE_ASSERTIONS:BOOL=true \ + -DSVF_SANITIZE="${SVF_SANITIZER}" \ + -DBUILD_SHARED_LIBS=${BUILD_DYN_LIB} \ + -S "${SVFHOME}" -B "${BUILD_DIR}" +cmake --build "${BUILD_DIR}" -j ${jobs} +``` + +**After:** +```bash +# Select generator and extra flags based on the OS +if [[ $sysOS == MINGW* || $sysOS == MSYS* ]]; then + CMAKE_GENERATOR="Ninja" + CMAKE_EXTRA=( + -DCMAKE_C_COMPILER=clang + -DCMAKE_CXX_COMPILER=clang++ + -DSVF_WARN_AS_ERROR=OFF + -DSVF_EXPORT_DYNAMIC=OFF + ) +else + CMAKE_GENERATOR="Unix Makefiles" + CMAKE_EXTRA=() +fi + +cmake -G "$CMAKE_GENERATOR" \ + -D CMAKE_BUILD_TYPE:STRING="${BUILD_TYPE}" \ + -DSVF_ENABLE_ASSERTIONS:BOOL=true \ + -DSVF_SANITIZE="${SVF_SANITIZER}" \ + -DBUILD_SHARED_LIBS=${BUILD_DYN_LIB} \ + "${CMAKE_EXTRA[@]}" \ + -S "${SVFHOME}" -B "${BUILD_DIR}" +cmake --build "${BUILD_DIR}" -j ${jobs} +``` + +**Why `SVF_WARN_AS_ERROR=OFF`:** Clang on Windows emits some warnings on Windows APIs (padding, MSVC deprecations) that do not appear on Linux. With `-Werror` active, these would break the build. + +**Why `SVF_EXPORT_DYNAMIC=OFF`:** `-rdynamic` and `-Wl,--export-dynamic` are not supported by the PE linker (Windows). The patch to CMakeLists.txt (§6.1 of the README) already adds the guard, but setting the flag to OFF avoids CMake warnings. + +**Why `Ninja`:** on MSYS2, `ninja` is more reliable than `make` for parallel builds with Clang, and it has significantly better build times. + +--- + +## Summary of touched lines in `build.sh` + +| Modification | Approximate position | Type | +|---|---|---| +| Windows URLs | after line 35 | Variable addition | +| `check_msys2_deps` | after line 180 | Function addition | +| OS detection | lines 190–215 | Branch extension | +| LLVM Download | lines 235–241 | Extraction logic modification | +| CMake Block | lines 299–304 | Replacement | diff --git a/docs/windows-port/cmake-windows.md b/docs/windows-port/cmake-windows.md new file mode 100644 index 0000000000..279e3c4188 --- /dev/null +++ b/docs/windows-port/cmake-windows.md @@ -0,0 +1,145 @@ +--- +title: "Modifications to `CMakeLists.txt` for Windows" +tags: + - svf + - documentation + - setup + - build + - value-flow + - saber + - llvm + - windows + - api +--- + +# Modifications to `CMakeLists.txt` for Windows + +This file describes the modifications to the CMake build system required for a clean build on Windows using MinGW-w64 + Clang. + +--- + +## Modification 1 — Guarding `-rdynamic` and `-Wl,--export-dynamic` flags + +**Location:** `CMakeLists.txt`, `target_link_options` block (lines 311–326). + +These flags are specific to ELF (Linux/macOS) and do not work with the PE format (Windows). CMake does not filter them automatically with Clang on Windows. + +**Before:** +```cmake +target_link_options( + SvfFlags + INTERFACE $:-rdynamic>> + INTERFACE $:-Wl,--export-dynamic>> + ... +) +``` + +**After:** +```cmake +target_link_options( + SvfFlags + # -rdynamic and --export-dynamic are ELF-only flags, not supported on Windows PE + INTERFACE $,$>>:-rdynamic>> + INTERFACE $,$>>:-Wl,--export-dynamic>> + ... +) +``` + +**Note:** `$` is a CMake generator expression that evaluates to `1` on both MSVC and MinGW when targeting Windows. + +--- + +## Modification 2 — Stack size for executables on Windows (optional) + +**Location:** `svf-llvm/tools/CMakeLists.txt` or in the `CMakeLists.txt` of each tool (`wpa`, `dvf`, `saber`, etc.). + +On Windows, `SVFUtil::increaseStackSize()` becomes a no-op (guard `#ifndef _WIN32`). To guarantee a sufficient stack size for deep analyses, add the linker flag: + +```cmake +if(WIN32) + # 256 MB stack — equivalent to RLIMIT_STACK on Linux + foreach(_svf_tool wpa dvf saber dda cfl mta) + if(TARGET ${_svf_tool}) + if(MSVC) + target_link_options(${_svf_tool} PRIVATE /STACK:268435456) + else() + # MinGW / Clang on Windows + target_link_options(${_svf_tool} PRIVATE -Wl,--stack,268435456) + endif() + endif() + endforeach() +endif() +``` + +--- + +## Modification 3 — DLL output directory on Windows + +On Windows with dynamic libraries, CMake puts the `.dll` files in `bin/` (not `lib/`) when using `RUNTIME DESTINATION`. This is already correct in the existing `CMakeLists.txt` (it uses `RUNTIME DESTINATION ${SVF_INSTALL_BINDIR}`), but it is good practice to verify that `CMAKE_RUNTIME_OUTPUT_DIRECTORY` points to `/bin`: + +```cmake +# Already present in the main CMakeLists.txt (line 27) — verify: +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${SVF_BINARY_DIR}/bin) +``` + +On Windows, DLLs generated by `add_library(SvfCore SHARED)` will go to `/bin/` (because they are runtime artifacts), while the import `.lib` files will go to `/lib/`. This is the correct behavior. + +--- + +## Modification 4 — `fuse-ld=lld` on Windows + +**Location:** `CMakeLists.txt`, `target_link_options` block (line 317). + +```cmake +# Before: +INTERFACE $:-fuse-ld=lld>> +``` + +On Clang for Windows, the LLD linker is already the default (there is no need for `-fuse-ld=lld` and it can actually cause warnings). Add a guard: + +```cmake +# After: +INTERFACE $,$>>:-fuse-ld=lld>> +``` + +--- + +## Modification 5 — `extapi.bc` on Windows: verifying clang flags + +**Location:** `svf-llvm/CMakeLists.txt`, custom command `gen_extapi_ir` (line 96). + +```cmake +add_custom_command( + OUTPUT ${SVF_BUILD_EXTAPI_BC} + COMMAND ${LLVM_CLANG} -w -S -c -fPIC -std=gnu11 -emit-llvm -o ${SVF_BUILD_EXTAPI_BC} ${EXTAPI_SRC} + ... +) +``` + +**Problem:** `-fPIC` is not necessary on Windows (all PE binary code is position-independent by default) and some versions of Clang for Windows ignore it or emit a warning. Add a guard: + +```cmake +if(WIN32) + set(EXTAPI_PIC_FLAG "") +else() + set(EXTAPI_PIC_FLAG "-fPIC") +endif() + +add_custom_command( + OUTPUT ${SVF_BUILD_EXTAPI_BC} + COMMAND ${LLVM_CLANG} -w -S -c ${EXTAPI_PIC_FLAG} -std=gnu11 -emit-llvm + -o ${SVF_BUILD_EXTAPI_BC} ${EXTAPI_SRC} + ... +) +``` + +--- + +## Summary of CMake modifications + +| File | Modification | Priority | +|---|---|---| +| `CMakeLists.txt` | Guard `-rdynamic`/`--export-dynamic` | High — the build fails without this | +| `CMakeLists.txt` | Guard `-fuse-ld=lld` | Medium — warning, not error | +| `svf-llvm/CMakeLists.txt` | Guard `-fPIC` in extapi.bc | Medium — warning, not error | +| `svf-llvm/tools/CMakeLists.txt` | Stack size `/STACK:268435456` | Low — optional | diff --git a/docs/windows-port/minimal-dependencies.md b/docs/windows-port/minimal-dependencies.md new file mode 100644 index 0000000000..7ddc39bfe0 --- /dev/null +++ b/docs/windows-port/minimal-dependencies.md @@ -0,0 +1,185 @@ +--- +title: "SVF Windows — Minimal Dependencies (llvm-mingw)" +tags: + - svf + - documentation + - ide + - setup + - build + - value-flow + - llvm + - windows + - api +--- + +# SVF Windows — Minimal Dependencies (llvm-mingw) + +This document describes the minimal dependencies approach to compile SVF on Windows. The goal is for the user to run a single PowerShell script without installing anything manually. + +--- + +## Comparing Dependencies + +| | MSYS2 + bash | PowerShell + clang-cl | **PowerShell + llvm-mingw** | +|---|---|---|---| +| MSYS2 | Required | No | **No** | +| Visual Studio / Build Tools | No | Required | **No** | +| CMake installer | No (via MSYS2) | Required | **No (portable zip)** | +| Ninja installer | No (via MSYS2) | Required | **No (single .exe)** | +| What the user installs | MSYS2 | VS Build Tools | **Nothing** | +| Downloaded automatically | LLVM, Z3 | LLVM, Z3 | **llvm-mingw, Z3, CMake, Ninja** | + +With llvm-mingw, everything is downloaded and managed by `build.ps1`. The user only needs **PowerShell** (included in Windows 10/11) and **Git** to clone the repository. + +--- + +## What is llvm-mingw + +**llvm-mingw** (https://github.com/mstorsjo/llvm-mingw) is a self-contained distribution of the LLVM/Clang toolchain for Windows that includes: + +- `clang++` / `clang` — compiler +- `lld` — linker +- **MinGW-w64 Headers** — provides `unistd.h`, `sys/resource.h`, `popen`, `stat`, and all POSIX headers required by SVF +- **MinGW-w64 CRT** — C/C++ runtime without MSVC dependencies + +It is a single `.zip` archive to extract, without installers, without system dependencies, and without modifying the Windows registry. + +### Why MinGW-w64 resolves the POSIX headers issue + +With llvm-mingw, the MinGW ABI is used (similar to the MSYS2 approach), so C++ patches to SVF sources remain identical and minimal — just a `#ifndef _WIN32` guard where necessary. No API replacements (`_stat`, `_popen`, etc.) are needed because MinGW already exposes them with their POSIX names. + +--- + +## Versions and download URLs + +| Component | Version | Size | URL | +|---|---|---|---| +| llvm-mingw | 20240619 (LLVM 18) or newer | ~200 MB zip | https://github.com/mstorsjo/llvm-mingw/releases | +| Z3 | 4.8.8 | ~8 MB zip | https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-win.zip | +| CMake | 3.29+ | ~50 MB zip | https://github.com/Kitware/CMake/releases | +| Ninja | 1.11+ | ~400 KB zip | https://github.com/ninja-build/ninja/releases | + +> **Note LLVM vs llvm-mingw:** llvm-mingw carries a different version of LLVM (e.g., 18.x or 22.x) compared to the one used internally by SVF for analysis (e.g., 16.x or 22.x). The two versions coexist: llvm-mingw is the *compiler* used to build SVF itself, while the *LLVM SDK* is the library SVF relies on to read bitcode. Both must be downloaded. + +### Structure of downloaded dependencies + +``` +SVF/ +├── llvm-mingw.obj/ ← toolchain: clang++, lld, MinGW headers +├── llvm-16.0.0.obj/ ← LLVM SDK 16.x: headers + libs for SVF +├── z3.obj/ ← Z3 solver +├── cmake.obj/ ← portable CMake +├── ninja.obj/ ← Ninja build tool +└── Release-build/ ← build output +``` + +--- + +## Download sequence in `build.ps1` + +The `build.ps1` script downloads the components in this order: + +``` +1. llvm-mingw → compiler (clang++, lld, MinGW headers) +2. LLVM SDK 16 → libraries that SVF depends on +3. Z3 → solver +4. CMake → build system (if not already in PATH) +5. Ninja → CMake generator (if not already in PATH) +``` + +CMake and Ninja are skipped if they are already present in the system PATH. + +--- + +## CMake configuration with llvm-mingw + +```powershell +$LLVMMingwBin = ".\llvm-mingw.obj\bin" +$LLVMSdkDir = ".\llvm-16.0.0.obj\lib\cmake\llvm" +$Z3Dir = ".\z3.obj" + +cmake -G Ninja ` + -S . -B Release-build ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_C_COMPILER="$LLVMMingwBin\clang.exe" ` + -DCMAKE_CXX_COMPILER="$LLVMMingwBin\clang++.exe" ` + -DLLVM_DIR=$LLVMSdkDir ` + -DZ3_DIR=$Z3Dir ` + -DBUILD_SHARED_LIBS=ON ` + -DSVF_WARN_AS_ERROR=OFF ` + -DSVF_EXPORT_DYNAMIC=OFF +``` + +Key points: +- `CMAKE_C_COMPILER` and `CMAKE_CXX_COMPILER` point to llvm-mingw (not to LLVM SDK) +- `LLVM_DIR` points to the LLVM SDK (not to llvm-mingw) +- No RTTI flags to specify — llvm-mingw supports RTTI + +--- + +## C++ Source Patches — Unchanged + +The C++ source patches are **identical** to those documented in `patch-cpp-sources.md`. With MinGW-w64 (provided by llvm-mingw), no API replacements are needed: + +| Symbol | With clang-cl (MSVC) | With llvm-mingw (MinGW) | +|---|---|---| +| `stat()` | `_stat()` + `#define` | Available natively | +| `popen()` | `_popen()` + `#define` | Available natively | +| `unistd.h` | Does not exist | Available in MinGW | +| `sys/resource.h` | Does not exist | Available but `setrlimit` is limited | + +The only mandatory patch remains the guard on `sys/resource.h` / `increaseStackSize()`, because `setrlimit(RLIMIT_STACK, ...)` has no effect on Windows even with MinGW. + +--- + +## ABI Comparison and Binary Compatibility + +| | clang-cl | llvm-mingw | +|---|---|---| +| ABI | MSVC | GNU/MinGW | +| Compatible with DLL MSVC | Yes | No | +| Compatible with DLL MinGW | No | Yes | +| Requires VS installed | Yes | **No** | +| SVF as a library usable from C# | P/Invoke with MSVC DLLs | P/Invoke with MinGW DLLs | + +For P/Invoke, both ABIs work — the important thing is that the C# project loads the DLL compiled with the same ABI. + +--- + +## Limitations + +### LLVM SDK prebuilt for Windows + +SVF requires LLVM as an SDK. SVF binaries for Linux include a custom version with RTTI enabled. An equivalent binary does not exist for Windows yet. + +Options: +1. Use the official LLVM binary for Windows-MSVC and compile it as static libraries with RTTI off (`-DSVF_ENABLE_RTTI=OFF`) +2. Compile LLVM from source with llvm-mingw and RTTI on (slow, ~45 min) +3. Wait for SVF to publish an official Windows binary + +### `setrlimit` on Windows with MinGW + +MinGW exposes `setrlimit` in the header, but the implementation is a no-op for `RLIMIT_STACK` on Windows. The `#ifndef _WIN32` guard is still necessary for clarity and to prevent unexpected behavior. + +### Total download size + +The first execution of `build.ps1` downloads about 500–600 MB of dependencies. Subsequent runs reuse the local cache. + +--- + +## Files to Create/Modify (Summary) + +| File | Type | Notes | +|---|---|---| +| `build.ps1` | New | Automatic download of all dependencies | +| `setup.ps1` | New | Configures PATH for the current session | +| `svf/lib/Util/SVFUtil.cpp` | Patch | Guard `sys/resource.h` — see `patch-cpp-sources.md` | +| `svf/lib/Util/ExtAPI.cpp` | Patch | Removal of `dlfcn.h` — see `patch-cpp-sources.md` | +| `svf/include/MemoryModel/PointerAnalysis.h` | Patch | Guard `unistd.h` — see `patch-cpp-sources.md` | +| `CMakeLists.txt` | Patch | Guard `-rdynamic`, `-fuse-ld=lld` — see `cmake-windows.md` | +| `svf-llvm/CMakeLists.txt` | Patch | Guard `-fPIC` in `extapi.bc` — see `cmake-windows.md` | + +--- + +*Document created: 2026-06-03* +*Approach: PowerShell + llvm-mingw (zero dependencies to install manually)* diff --git a/docs/windows-port/patch-cpp-sources.md b/docs/windows-port/patch-cpp-sources.md new file mode 100644 index 0000000000..f46a1575bc --- /dev/null +++ b/docs/windows-port/patch-cpp-sources.md @@ -0,0 +1,132 @@ +--- +title: "C++ Source Patches — Complete Details" +tags: + - svf + - documentation + - build + - llvm + - testing + - windows + - api +--- + +# C++ Source Patches — Complete Details + +This file contains the exact diffs to be applied to the three C++ files that use POSIX-only APIs not available on native Windows. + +--- + +## File 1: `svf/lib/Util/SVFUtil.cpp` + +### Diff — include (line 36) + +```diff +-#include /// increase stack size ++#ifndef _WIN32 ++#include /// increase stack size ++#endif +``` + +### Diff — `increaseStackSize()` function (line 229) + +```diff + void SVFUtil::increaseStackSize() + { ++#ifndef _WIN32 + const rlim_t kStackSize = 256L * 1024L * 1024L; // min stack size = 256 Mb + struct rlimit rl; + int result = getrlimit(RLIMIT_STACK, &rl); + if (result == 0) + { + if (rl.rlim_cur < kStackSize) + { + rl.rlim_cur = kStackSize; + result = setrlimit(RLIMIT_STACK, &rl); + if (result != 0) + writeWrnMsg("setrlimit returned result !=0 \n"); + } + } ++#endif + } +``` + +**Motivation:** `getrlimit`/`setrlimit` with `RLIMIT_STACK` do not exist on Windows. On Windows, the stack grows dynamically and the limit is set at compile-time via linker flags (`/STACK:N` with MSVC or MinGW). The function becomes a no-op on Windows; to increase the stack, see the script configurations. + +--- + +## File 2: `svf/lib/Util/ExtAPI.cpp` + +### Diff — includes (lines 35–37) + +```diff +-#include + #include "SVFIR/SVFVariables.h" +-#include ++#ifdef _WIN32 ++# include ++# include ++# define stat _stat ++# define popen _popen ++# define pclose _pclose ++#else ++# include ++#endif ++#include "SVFIR/SVFVariables.h" +``` + +**Motivations:** + +- `dlfcn.h` was included but not used (no call to `dlopen`, `dlsym`, `dlclose`, `dlerror` in the file). Removed completely. +- `sys/stat.h` on MSVC uses `_stat` instead of `stat`. On MinGW, `stat` is directly available, but the `#defines` guarantee future compatibility with builds using clang-cl or MSVC. +- `popen`/`pclose` on MSVC are named `_popen`/`_pclose`. The `#define` avoids touching the code that calls them in the `GetStdoutFromCommand` function. + +--- + +## File 3: `svf/include/MemoryModel/PointerAnalysis.h` + +### Diff — includes (lines 33–34) + +```diff +-#include +-#include ++#ifndef _WIN32 ++# include ++# include ++#endif +``` + +**Motivations:** + +- `unistd.h` does not exist on MSVC. MinGW provides it, but it is a public SVF header, so the guard is required for anyone using SVF as an external library with non-MinGW compilers. +- `signal.h` exists on Windows but with a reduced subset of signals (only `SIGABRT`, `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV`, `SIGTERM`). If POSIX-only signals (`SIGUSR1`, `SIGPIPE`, etc.) are used in the SVF code, they must be wrapped separately. + +### Verifying the usage of `signal.h` + +Before applying the patch, verify which symbols from `signal.h` are used in the files that include `PointerAnalysis.h`: + +```bash +grep -rn "signal\|SIGTERM\|SIGUSR\|SIG_" \ + svf/include/MemoryModel/ \ + svf/lib/MemoryModel/ \ + --include="*.h" --include="*.cpp" +``` + +If the used signals are only `SIGINT`/`SIGTERM`/`SIGABRT`, add `#include ` in the `_WIN32` branch as well (they are supported). + +--- + +## Recommended application order + +1. `svf/include/MemoryModel/PointerAnalysis.h` — public header, must be done first to avoid breaking incremental builds +2. `svf/lib/Util/SVFUtil.cpp` +3. `svf/lib/Util/ExtAPI.cpp` + +## Linux regression test after patches + +```bash +# From the repository root on Linux: +./build.sh +cd Release-build +ctest --output-on-failure # if Test-Suite is present +bin/wpa --help # smoke test +``` diff --git a/docs/windows-port/powershell-approach.md b/docs/windows-port/powershell-approach.md new file mode 100644 index 0000000000..777ded76bd --- /dev/null +++ b/docs/windows-port/powershell-approach.md @@ -0,0 +1,587 @@ +--- +title: "SVF Windows Port — PowerShell Approach (without MSYS2)" +tags: + - svf + - documentation + - ide + - setup + - build + - saber + - llvm + - testing + - windows + - api +--- + +# SVF Windows Port — PowerShell Approach (without MSYS2) + +This document describes how to compile SVF on Windows using **PowerShell** as the build shell, **clang-cl** as the compiler, and **Visual Studio Build Tools** as the CRT/SDK. It does not require MSYS2 or any emulated Unix environment. + +--- + +## Table of Contents + +1. [Comparison with the MSYS2 Approach](#1-comparison-with-the-msys2-approach) +2. [Prerequisites](#2-prerequisites) +3. [C++ Source Patches](#3-c-source-patches) +4. [build.ps1 Script](#4-buildps1-script) +5. [setup.ps1 Script](#5-setupps1-script) +6. [CMakeLists.txt Modifications](#6-cmakeliststxt-modifications) +7. [Quickstart](#7-quickstart) +8. [Known Issues](#8-known-issues) + +--- + +## 1. Comparison with the MSYS2 Approach + +| Aspect | MSYS2 + bash | PowerShell + clang-cl | +|---|---|---| +| Build Shell | `build.sh` (modified) | `build.ps1` (new file) | +| Compiler | `clang++` (MinGW ABI) | `clang-cl` (MSVC ABI) | +| POSIX Headers | Provided by MinGW-w64 | Not available — replaced by Windows SDK | +| CRT | msvcrt / ucrt via MinGW | MSVC CRT via VS Build Tools | +| Extra dependency | MSYS2 | Visual Studio Build Tools | +| Download tools | `curl`, `unzip`, `tar` from MSYS2 | Native `Invoke-WebRequest`, `Expand-Archive`, `tar.exe` | +| Runtime DLLs | Needed in PATH | Needed next to the `.exe` or in PATH | +| C++ Patches | 3 files, identical | 3 files, **identical** | + +C++ source patches are **identical** in both approaches. Only the toolchain and build scripts differ. + +--- + +## 2. Prerequisites + +Install in the specified order: + +### 2.1 Visual Studio Build Tools (required) + +Download from: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022 + +During installation, select: +- **Desktop development with C++** +- Component: **MSVC v143** (or higher) +- Component: **Windows 11 SDK** (or Windows 10 SDK) +- Component: **CMake tools** (optional, otherwise install CMake separately) + +> The "Build Tools" version is free and does not require a Visual Studio license. + +### 2.2 LLVM for Windows + +Download the official LLVM 16.x binary for Windows from: +https://github.com/llvm/llvm-project/releases/tag/llvmorg-16.0.4 + +File: `LLVM-16.0.4-win64.exe` or `clang+llvm-16.0.4-x86_64-pc-windows-msvc.tar.xz` + +Extract to `C:\llvm-16.0.4` (path without spaces). + +> **Note RTTI:** the official LLVM binary is compiled **without RTTI**. SVF with clang-cl on Windows must therefore be compiled with `nortti`. If you want RTTI, you must compile LLVM from source with `-DLLVM_ENABLE_RTTI=ON` (see §8.1). + +### 2.3 Z3 for Windows + +Download from: +https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-win.zip + +Extract to `C:\z3-4.8.8`. + +### 2.4 CMake (if not installed with VS Build Tools) + +```powershell +winget install Kitware.CMake +# or +choco install cmake +``` + +### 2.5 Ninja (recommended) + +```powershell +winget install Ninja-build.Ninja +# or +choco install ninja +``` + +--- + +## 3. C++ Source Patches + +The patches are **identical** to those documented in `patch-cpp-sources.md`. Below is a summary, with specific notes for the MSVC/clang-cl compiler. + +### 3.1 `svf/lib/Util/SVFUtil.cpp` + +```diff +-#include /// increase stack size ++#ifndef _WIN32 ++#include /// increase stack size ++#endif +``` + +And in the body of `increaseStackSize()`: + +```diff + void SVFUtil::increaseStackSize() + { ++#ifndef _WIN32 + const rlim_t kStackSize = 256L * 1024L * 1024L; + struct rlimit rl; + int result = getrlimit(RLIMIT_STACK, &rl); + if (result == 0) + { + if (rl.rlim_cur < kStackSize) + { + rl.rlim_cur = kStackSize; + result = setrlimit(RLIMIT_STACK, &rl); + if (result != 0) + writeWrnMsg("setrlimit returned result !=0 \n"); + } + } ++#endif + } +``` + +With clang-cl, the stack is set via linker flags in `CMakeLists.txt` (see §6). + +### 3.2 `svf/lib/Util/ExtAPI.cpp` + +With clang-cl / MSVC, `sys/stat.h` is available in the Windows SDK but uses `_stat` instead of `stat`. `popen`/`pclose` are named `_popen`/`_pclose`. + +```diff +-#include + #include "SVFIR/SVFVariables.h" +-#include ++#ifdef _WIN32 ++# include ++# include ++# define stat _stat ++# define popen _popen ++# define pclose _pclose ++#else ++# include ++#endif ++#include "SVFIR/SVFVariables.h" +``` + +`dlfcn.h` removed because it is unused (no calls to `dlopen`/`dlsym` in the file). + +### 3.3 `svf/include/MemoryModel/PointerAnalysis.h` + +`unistd.h` does not exist in MSVC/Windows SDK. No symbol in the `.h` file uses it directly. + +```diff +-#include +-#include ++#ifndef _WIN32 ++# include ++# include ++#endif +``` + +--- + +## 4. `build.ps1` Script + +Create the file `build.ps1` in the repository root with the following content: + +```powershell +<# +.SYNOPSIS + Builds SVF on Windows using clang-cl and Visual Studio Build Tools. + +.PARAMETER BuildType + Build type: Release (default) or Debug. + +.PARAMETER BuildSharedLibs + ON (default) for DLL, OFF for static libraries. + +.PARAMETER LLVMDir + Path to prebuilt LLVM. Default: .\llvm-16.0.0.obj + +.PARAMETER Z3Dir + Path to prebuilt Z3. Default: .\z3.obj + +.EXAMPLE + .\build.ps1 + .\build.ps1 -BuildType Debug + .\build.ps1 -BuildSharedLibs OFF + .\build.ps1 -LLVMDir C:\llvm-16.0.4 -Z3Dir C:\z3-4.8.8 +#> + +param( + [ValidateSet("Release", "Debug")] + [string]$BuildType = "Release", + + [ValidateSet("ON", "OFF")] + [string]$BuildSharedLibs = "ON", + + [string]$LLVMDir = "", + [string]$Z3Dir = "" +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$SVFHome = $ScriptDir +$LLVMHome = Join-Path $SVFHome "llvm-16.0.0.obj" +$Z3Home = Join-Path $SVFHome "z3.obj" +$Jobs = [Environment]::ProcessorCount + +$LLVMVer = "16.0.4" +$LLVMUrl = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVMVer/clang+llvm-$LLVMVer-x86_64-pc-windows-msvc.tar.xz" +$Z3Url = "https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-win.zip" + +# --------------------------------------------------------------------------- +# Helper functions +# --------------------------------------------------------------------------- + +function Get-File { + param([string]$Url, [string]$Dest) + if (Test-Path $Dest) { + Write-Host "File $Dest already present, skipping download." + return + } + Write-Host "Downloading: $Url" + Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing +} + +function Expand-TarXz { + param([string]$Archive, [string]$Dest) + New-Item -ItemType Directory -Force -Path $Dest | Out-Null + # tar.exe is available natively on Windows 10+ + & tar -xf $Archive -C $Dest --strip-components 1 + if ($LASTEXITCODE -ne 0) { throw "tar failed on $Archive" } +} + +function Find-VsDevShell { + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { + throw "Visual Studio Build Tools not found. Install from: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022" + } + $vsPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if (-not $vsPath) { + throw "C++ component not found in Visual Studio. Install 'Desktop development with C++'." + } + return $vsPath +} + +function Initialize-VsEnv { + param([string]$VsPath) + $devShell = Join-Path $VsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll" + if (Test-Path $devShell) { + Import-Module $devShell + Enter-VsDevShell -VsInstallPath $VsPath -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -host_arch=x64" + Write-Host "Visual Studio environment initialized." + } else { + # Fallback: use vcvars64.bat + $vcvars = Join-Path $VsPath "VC\Auxiliary\Build\vcvars64.bat" + if (-not (Test-Path $vcvars)) { throw "vcvars64.bat not found." } + $envDump = & cmd /c "`"$vcvars`" x64 && set" + $envDump | ForEach-Object { + if ($_ -match "^([^=]+)=(.*)$") { + [System.Environment]::SetEnvironmentVariable($Matches[1], $Matches[2], "Process") + } + } + Write-Host "Visual Studio environment initialized via vcvars64.bat." + } +} + +function Assert-Tool { + param([string]$Name) + if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) { + throw "Tool not found in PATH: $Name. Verify prerequisites." + } +} + +# --------------------------------------------------------------------------- +# Resolve LLVM_DIR and Z3_DIR +# --------------------------------------------------------------------------- + +if ($LLVMDir -ne "" -and (Test-Path $LLVMDir)) { + $env:LLVM_DIR = $LLVMDir +} elseif ($env:LLVM_DIR -and (Test-Path $env:LLVM_DIR)) { + Write-Host "Using LLVM_DIR from environment: $env:LLVM_DIR" +} elseif (Test-Path $LLVMHome) { + $env:LLVM_DIR = $LLVMHome +} else { + Write-Host "Downloading LLVM $LLVMVer for Windows..." + Get-File -Url $LLVMUrl -Dest "$SVFHome\llvm.tar.xz" + Expand-TarXz -Archive "$SVFHome\llvm.tar.xz" -Dest $LLVMHome + Remove-Item "$SVFHome\llvm.tar.xz" + $env:LLVM_DIR = $LLVMHome +} + +if ($Z3Dir -ne "" -and (Test-Path $Z3Dir)) { + $env:Z3_DIR = $Z3Dir +} elseif ($env:Z3_DIR -and (Test-Path $env:Z3_DIR)) { + Write-Host "Using Z3_DIR from environment: $env:Z3_DIR" +} elseif (Test-Path $Z3Home) { + $env:Z3_DIR = $Z3Home +} else { + Write-Host "Downloading Z3 for Windows..." + Get-File -Url $Z3Url -Dest "$SVFHome\z3.zip" + Expand-Archive -Path "$SVFHome\z3.zip" -DestinationPath $SVFHome + $z3extracted = Get-Item "$SVFHome\z3-*" | Select-Object -First 1 + Rename-Item $z3extracted.FullName $Z3Home + Remove-Item "$SVFHome\z3.zip" + $env:Z3_DIR = $Z3Home +} + +Write-Host "LLVM_DIR=$env:LLVM_DIR" +Write-Host "Z3_DIR=$env:Z3_DIR" + +# --------------------------------------------------------------------------- +# Initialize Visual Studio environment +# --------------------------------------------------------------------------- + +$vsPath = Find-VsDevShell +Initialize-VsEnv -VsPath $vsPath + +# --------------------------------------------------------------------------- +# Verify tools in the PATH +# --------------------------------------------------------------------------- + +$env:PATH = "$env:LLVM_DIR\bin;$env:Z3_DIR\bin;$env:PATH" + +Assert-Tool "clang-cl" +Assert-Tool "cmake" +Assert-Tool "ninja" + +# --------------------------------------------------------------------------- +# CMake configure and build +# --------------------------------------------------------------------------- + +$BuildDir = Join-Path $SVFHome "$BuildType-build" +if (Test-Path $BuildDir) { Remove-Item -Recurse -Force $BuildDir } +New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null + +$LLVMCMakeDir = Join-Path $env:LLVM_DIR "lib\cmake\llvm" + +& cmake -G Ninja ` + -S $SVFHome ` + -B $BuildDir ` + -DCMAKE_BUILD_TYPE=$BuildType ` + -DCMAKE_C_COMPILER=clang-cl ` + -DCMAKE_CXX_COMPILER=clang-cl ` + -DLLVM_DIR=$LLVMCMakeDir ` + -DZ3_DIR=$env:Z3_DIR ` + -DBUILD_SHARED_LIBS=$BuildSharedLibs ` + -DSVF_WARN_AS_ERROR=OFF ` + -DSVF_EXPORT_DYNAMIC=OFF ` + -DSVF_ENABLE_RTTI=OFF ` + -DSVF_ENABLE_EXCEPTIONS=OFF + +if ($LASTEXITCODE -ne 0) { throw "CMake configure failed." } + +& cmake --build $BuildDir --parallel $Jobs + +if ($LASTEXITCODE -ne 0) { throw "Build failed." } + +Write-Host "" +Write-Host "Build completed in: $BuildDir" +Write-Host "Run '.\setup.ps1 $BuildType' to configure the environment." +``` + +--- + +## 5. `setup.ps1` Script + +Create the file `setup.ps1` in the repository root: + +```powershell +<# +.SYNOPSIS + Configures the PATH to use SVF compiled on Windows. + +.PARAMETER BuildType + Release (default) or Debug. + +.EXAMPLE + . .\setup.ps1 # dot-source to modify the PATH in the current session + . .\setup.ps1 Debug +#> + +param( + [ValidateSet("Release", "Debug")] + [string]$BuildType = "Release" +) + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$BuildDir = Join-Path $ScriptDir "$BuildType-build" + +if (-not (Test-Path $BuildDir)) { + Write-Error "Build directory not found: $BuildDir. Run build.ps1 first." + return +} + +# Resolve LLVM_DIR and Z3_DIR (same logic as build.ps1) +$LLVMHome = Join-Path $ScriptDir "llvm-16.0.0.obj" +$Z3Home = Join-Path $ScriptDir "z3.obj" + +if (-not $env:LLVM_DIR) { + if (Test-Path $LLVMHome) { $env:LLVM_DIR = $LLVMHome } +} +if (-not $env:Z3_DIR) { + if (Test-Path $Z3Home) { $env:Z3_DIR = $Z3Home } +} + +# On Windows, DLLs must be in the PATH (not LD_LIBRARY_PATH) +$additions = @( + "$env:LLVM_DIR\bin", + "$env:Z3_DIR\bin", + "$BuildDir\bin", # SVF binaries (.exe) and DLL SvfCore/SvfLLVM + "$BuildDir\lib" # import libraries and any additional DLLs +) + +foreach ($p in $additions) { + if ((Test-Path $p) -and ($env:PATH -notlike "*$p*")) { + $env:PATH = "$p;$env:PATH" + } +} + +$env:SVF_DIR = $ScriptDir + +Write-Host "SVF_DIR = $env:SVF_DIR" +Write-Host "LLVM_DIR = $env:LLVM_DIR" +Write-Host "Z3_DIR = $env:Z3_DIR" +Write-Host "PATH updated. Now you can use: wpa, dvf, saber, ..." +``` + +> **Important:** use dot-sourcing (`. .\setup.ps1`) to modify the PATH in the current session. Without it, the PATH is set in a sub-process and then lost. + +--- + +## 6. `CMakeLists.txt` Modifications + +The same patches documented in `cmake-windows.md` also apply with clang-cl, with one difference: the stack size uses MSVC syntax. + +### Stack size (replacement of the guard in `cmake-windows.md` §2) + +```cmake +if(WIN32) + foreach(_svf_tool wpa dvf saber dda cfl mta) + if(TARGET ${_svf_tool}) + if(MSVC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # clang-cl accepts both /STACK and -Wl,--stack + target_link_options(${_svf_tool} PRIVATE /STACK:268435456) + endif() + endif() + endforeach() +endif() +``` + +### Guards `-rdynamic` and `-fuse-ld=lld` — identical to `cmake-windows.md` + +Nothing changes compared to the MSYS2 approach; the same generator expressions `$>` also work with clang-cl. + +### `extapi.bc` — `-fPIC` flag with clang-cl + +With clang-cl, the `-fPIC` flag generates an error instead of a warning. The guard becomes mandatory: + +```cmake +if(WIN32) + set(EXTAPI_PIC_FLAG "") +else() + set(EXTAPI_PIC_FLAG "-fPIC") +endif() + +add_custom_command( + OUTPUT ${SVF_BUILD_EXTAPI_BC} + COMMAND ${LLVM_CLANG} -w -S -c ${EXTAPI_PIC_FLAG} -std=gnu11 -emit-llvm + -o ${SVF_BUILD_EXTAPI_BC} ${EXTAPI_SRC} + ... +) +``` + +--- + +## 7. Quickstart + +```powershell +# 1. Open PowerShell (does not require admin privileges) +# 2. Install VS Build Tools with the C++ component (one-time) +# 3. Clone the repository +git clone https://github.com/SVF-tools/SVF.git +cd SVF + +# 4. Build +.\build.ps1 + +# 5. Configure the PATH (dot-source) +. .\setup.ps1 + +# 6. Smoke test +wpa --help + +# 7. Test with bitcode +clang -emit-llvm -c -g test.c -o test.bc +wpa -ander -print-fp -stat=false test.bc +``` + +--- + +## 8. Known Issues + +### 8.1 LLVM without RTTI + +The official LLVM binary for Windows is compiled without RTTI. SVF must be compiled accordingly: + +```powershell +.\build.ps1 -BuildSharedLibs OFF # equivalent to sta_lib +# CMake automatically receives -DSVF_ENABLE_RTTI=OFF (already in build.ps1) +``` + +To enable RTTI, you must compile LLVM from source: +```powershell +cmake -S llvm-source\llvm -B llvm-build -G Ninja ` + -DCMAKE_BUILD_TYPE=Release ` + -DLLVM_ENABLE_PROJECTS="clang" ` + -DLLVM_ENABLE_RTTI=ON ` + -DLLVM_BUILD_LLVM_DYLIB=ON ` + -DCMAKE_C_COMPILER=clang-cl ` + -DCMAKE_CXX_COMPILER=clang-cl +cmake --build llvm-build --parallel +``` + +### 8.2 PowerShell Execution Policy + +If PowerShell blocks the script execution: +```powershell +Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned +``` + +### 8.3 `tar.exe` not found + +Available from Windows 10 build 17063. Verify with: +```powershell +Get-Command tar +# if missing: winget install GnuWin32.Tar +``` + +### 8.4 Missing DLLs at startup + +Verify that `setup.ps1` was executed with dot-sourcing in the current session. Alternatively, copy the DLLs next to the executable: +```powershell +Copy-Item "$env:LLVM_DIR\bin\LLVM-16.dll" "Release-build\bin\" +Copy-Item "Release-build\lib\*.dll" "Release-build\bin\" -ErrorAction SilentlyContinue +``` + +### 8.5 clang-cl vs clang++ ABI + +Binaries produced with `clang-cl` (MSVC ABI) are not compatible with those produced with `clang++` via MinGW (GNU ABI). Do not mix the two toolchains for dependencies. + +--- + +## Summary of Files to Create/Modify + +| File | Type | Section | +|---|---|---| +| `build.ps1` | New | §4 | +| `setup.ps1` | New | §5 | +| `svf/lib/Util/SVFUtil.cpp` | Patch (identical to MSYS2) | §3.1 | +| `svf/lib/Util/ExtAPI.cpp` | Patch (identical to MSYS2) | §3.2 | +| `svf/include/MemoryModel/PointerAnalysis.h` | Patch (identical to MSYS2) | §3.3 | +| `CMakeLists.txt` | Patch flags | §6 | +| `svf-llvm/CMakeLists.txt` | Patch `-fPIC` and stack | §6 | + +--- + +*Document created: 2026-06-03* +*Approach: PowerShell + clang-cl + VS Build Tools (without MSYS2)* diff --git a/docs/windows-port/quickstart-windows.md b/docs/windows-port/quickstart-windows.md new file mode 100644 index 0000000000..9a9591ba2d --- /dev/null +++ b/docs/windows-port/quickstart-windows.md @@ -0,0 +1,168 @@ +--- +title: "Quickstart — Compiling SVF on Windows with MSYS2" +tags: + - svf + - documentation + - setup + - build + - saber + - llvm + - testing + - windows + - api +--- + +# Quickstart — Compiling SVF on Windows with MSYS2 + +Step-by-step guide to compile SVF on Windows using MSYS2 with the CLANG64 toolchain. It assumes that the patches described in the other documents have already been applied. + +--- + +## Step 1 — Install MSYS2 + +1. Download the installer from https://www.msys2.org +2. Install to `C:\msys64` (path without spaces) +3. Open the **MSYS2 CLANG64** terminal (not MINGW64, not UCRT64) + +--- + +## Step 2 — Install dependencies in MSYS2 + +```bash +# Update system packages +pacman -Syu + +# Install the CLANG64 toolchain and required tools +pacman -S \ + mingw-w64-clang-x86_64-toolchain \ + mingw-w64-clang-x86_64-cmake \ + mingw-w64-clang-x86_64-ninja \ + mingw-w64-clang-x86_64-clang \ + unzip curl tar xz +``` + +--- + +## Step 3 — Clone the repository + +```bash +# In MSYS2, Windows drives are accessible as /c, /d, etc. +cd /c/ +git clone https://github.com/SVF-tools/SVF.git +cd SVF +``` + +--- + +## Step 4 — Apply C++ patches (before building) + +If they have not been applied yet, modify the three files described in `patch-cpp-sources.md`: + +```bash +# Verify that the guards are present: +grep -n "_WIN32" svf/lib/Util/SVFUtil.cpp +grep -n "_WIN32" svf/lib/Util/ExtAPI.cpp +grep -n "_WIN32" svf/include/MemoryModel/PointerAnalysis.h +``` + +--- + +## Step 5 — Build + +```bash +# Release build with dynamic libraries (default) +./build.sh + +# Or debug build +./build.sh debug + +# Or build with static libraries (useful if LLVM lacks RTTI) +./build.sh sta_lib nortti +``` + +The script: +1. Detects the MSYS2/MINGW environment +2. Downloads prebuilt LLVM and Z3 for Windows +3. Runs CMake with Ninja and Clang +4. Compiles SVF + +--- + +## Step 6 — Configure the environment + +```bash +source ./setup.sh Release +``` + +After this command: +- `wpa`, `dvf`, `saber`, etc. are in the PATH +- SVF DLLs are in the PATH + +--- + +## Step 7 — Verification + +```bash +# Smoke test +wpa --help + +# Test with an example bitcode +cat > test.c << 'EOF' +#include +void foo(void) { printf("foo\n"); } +void bar(void) { printf("bar\n"); } +int main(void) { + void (*fp)(void) = foo; + fp(); + return 0; +} +EOF + +clang -emit-llvm -c -g test.c -o test.bc +wpa -ander -print-fp -stat=false test.bc +``` + +Expected output: +``` +==================Function Pointer Targets================== +NodeID: ... +CallSite: ... + Location: { "ln": ..., "cl": ..., "fl": "test.c" } + with Targets: + foo +``` + +--- + +## Troubleshooting Common Issues + +### `clang not found` or `cmake not found` +Ensure you are using the **CLANG64** terminal (not MINGW64). Verify with: +```bash +echo $MSYSTEM # must print "CLANG64" +which clang # must return /clang64/bin/clang +``` + +### `LLVM_CLANG not found` during CMake +Ensure that `clang` is in the PATH before running `./build.sh`. + +### Missing DLLs at `wpa` startup +Run `source ./setup.sh Release` before using the binaries. +Verify with: +```bash +ldd Release-build/bin/wpa.exe | grep "not found" +``` + +### Build fails with warnings treated as errors +Ensure that `SVF_WARN_AS_ERROR=OFF` is passed to CMake (already handled by the modified `build.sh` for Windows). Alternatively, pass it manually: +```bash +cmake -DSVF_WARN_AS_ERROR=OFF ... +``` + +### Stack overflow on large programs +Increase the stack size of the executable after building: +```bash +# With MinGW objcopy (available in MSYS2): +objcopy --add-gnu-debuglink=/dev/null Release-build/bin/wpa.exe # no-op, verification only +# Or recompile with -DSVF_STACK_SIZE=268435456 once the CMake flag is added +``` diff --git a/docs/windows-port/setup-sh-windows.md b/docs/windows-port/setup-sh-windows.md new file mode 100644 index 0000000000..e1e28e508d --- /dev/null +++ b/docs/windows-port/setup-sh-windows.md @@ -0,0 +1,137 @@ +--- +title: "Modifications to `setup.sh` for Windows (MSYS2 + MinGW-w64 + Clang)" +tags: + - svf + - documentation + - setup + - build + - value-flow + - llvm + - testing + - windows +--- + +# Modifications to `setup.sh` for Windows (MSYS2 + MinGW-w64 + Clang) + +This file describes each modification to be applied to `setup.sh` to support the Windows MSYS2 environment. + +--- + +## Main problem: `LD_LIBRARY_PATH` does not work on Windows + +On Linux/macOS, the dynamic linker looks for `.so`/`.dylib` files in `LD_LIBRARY_PATH` and `DYLD_LIBRARY_PATH`. On Windows, `.dll` files are searched for in the `PATH`. `LD_LIBRARY_PATH` is ignored by the Windows loader even inside MSYS2. + +--- + +## Modification 1 — `LLVMHome` path: `lib` vs `bin` + +LLVM for Linux has the `.so` files in `lib/`. LLVM for Windows has the `.dll` files in `bin/`. + +**Location:** `set_llvm` function (lines 16–26), add explanatory comment. It does not require code modifications if `LLVM_DIR` is correctly set by `build.sh` — but the `PATH` section must include `$LLVM_DIR/bin` on Windows. + +--- + +## Modification 2 — PATH and library path block (lines 68–76) + +**Before (current):** +```bash +# Add LLVM & Z3 to $PATH and $LD_LIBRARY_PATH (prepend so that selected instances will be used first) +export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$PATH +export LD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$DYLD_LIBRARY_PATH + +# Add compiled SVF binaries dir to $PATH +export PATH=$SVF_DIR/$Build/bin:$PATH + +# Add compiled library directories to $LD_LIBRARY_PATH +export LD_LIBRARY_PATH=$SVF_DIR/$Build/svf:$SVF_DIR/$Build/svf-llvm:$LD_LIBRARY_PATH +``` + +**After:** +```bash +_os=$(uname -s) + +if [[ $_os == MINGW* || $_os == MSYS* || $_os == CYGWIN* ]]; then + # On Windows, DLLs must be in the PATH + # LLVM for Windows has the DLLs in bin/ (not in lib/) + export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$PATH + + # SVF binaries and DLLs + export PATH=$SVF_DIR/$Build/bin:$PATH + export PATH=$SVF_DIR/$Build/lib:$PATH + + echo "Windows mode: DLL path configured via PATH" +else + # Linux / macOS + export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$PATH + export LD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$LD_LIBRARY_PATH + export DYLD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$DYLD_LIBRARY_PATH + + export PATH=$SVF_DIR/$Build/bin:$PATH + export LD_LIBRARY_PATH=$SVF_DIR/$Build/svf:$SVF_DIR/$Build/svf-llvm:$LD_LIBRARY_PATH +fi +``` + +--- + +## Modification 3 — `SVF_DIR` variable on Windows + +On Windows, paths may contain backslashes or a drive letter (`C:\...`). Within MSYS2, these are automatically converted (`/c/...`), but it is good practice to add a note to the output log. + +**Added after `export SVF_DIR` (line 13):** +```bash +export SVF_DIR + +# On Windows/MSYS2, convert the path to MSYS2 format if necessary +if [[ "$(uname -s)" == MINGW* || "$(uname -s)" == MSYS* ]]; then + # SVF_DIR is already in MSYS2 format (/c/...) if the script is run + # from the MSYS2 terminal. Verification: + echo "SVF_DIR=$SVF_DIR (MSYS2 format)" +else + echo "SVF_DIR=$SVF_DIR" +fi +``` + +--- + +## Modification 4 — `DYLD_LIBRARY_PATH` (macOS only) + +`DYLD_LIBRARY_PATH` is a macOS-only variable. On Linux it is already ignored, but on Windows it can cause confusion. Wrap it with an explicit check: + +**Before:** +```bash +export DYLD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$DYLD_LIBRARY_PATH +``` + +This line is already contained within the `else` branch of Modification 2 — no further action is required if that modification is applied. + +--- + +## Summary of touched lines in `setup.sh` + +| Modification | Approximate position | Type | +|---|---|---| +| Windows `SVF_DIR` Log | after line 13 | Optional addition | +| PATH/LD_LIBRARY_PATH block | lines 68–76 | Replacement with OS branch | + +--- + +## Notes for the end user on Windows + +After running `./build.sh` from the MSYS2 terminal: + +```bash +# Add to your ~/.bashrc in MSYS2 for permanent use: +source /c/path/to/SVF/setup.sh + +# Or run manually in each session: +cd /c/path/to/SVF +source ./setup.sh Release +``` + +To verify that the DLLs are found: +```bash +which wpa # must return the path of the compiled binary +wpa --help # smoke test +ldd Release-build/bin/wpa.exe # list dependent DLLs (MSYS2) +``` diff --git a/docs/windows-port/testing-windows.md b/docs/windows-port/testing-windows.md new file mode 100644 index 0000000000..cb854f4292 --- /dev/null +++ b/docs/windows-port/testing-windows.md @@ -0,0 +1,174 @@ +--- +title: "SVF — Testing Guide on Windows" +tags: + - svf + - documentation + - ide + - setup + - build + - llvm + - testing + - windows + - api +--- + +# SVF — Testing Guide on Windows + +This file describes how to verify that changes in the `windows-port` branch compile and run correctly on Windows. + +--- + +## Approach A — MSYS2 + Clang (via POSIX shell) + +### Prerequisites (one-time) + +1. Install MSYS2 from https://www.msys2.org — use the path `C:\msys64` +2. Open the **MSYS2 CLANG64** terminal (not MINGW64, not UCRT64) +3. Install dependencies: + +```bash +pacman -Syu +pacman -S \ + mingw-w64-clang-x86_64-toolchain \ + mingw-w64-clang-x86_64-cmake \ + mingw-w64-clang-x86_64-ninja \ + unzip curl tar xz +``` + +### Build + +```bash +# In MSYS2 CLANG64, from the repository root: +cd /c/Users/CAD3TN/Desktop/SVF +./build.sh sta_lib nortti +``` + +### Verification + +```bash +source ./setup.sh Release + +wpa --help + +cat > /tmp/test.c << 'EOF' +#include +void foo(void) { printf("foo\n"); } +int main(void) { + void (*fp)(void) = foo; + fp(); + return 0; +} +EOF + +clang -emit-llvm -c -g /tmp/test.c -o /tmp/test.bc +wpa -ander -print-fp -stat=false /tmp/test.bc +``` + +Expected output: prints the call target `foo` for the function pointer. + +--- + +## Approach B — PowerShell + llvm-mingw (recommended, without MSYS2) + +Uses **llvm-mingw** as the toolchain: Clang + lld + libc++ + UCRT, distributed as a single zip archive. Does not require Visual Studio or MSYS2. + +Advantages over the previous approach (clang-cl + VS Build Tools): +- No dependency on VS Build Tools (~5 GB) +- LLVM compiled with RTTI → `BUILD_SHARED_LIBS=ON` works +- Uniform ABI: compiler, LLVM, and Z3 all use MinGW/UCRT +- Z3 compiled from source with the same toolchain (~5 min) + +### Prerequisites (one-time) + +Only **CMake** and **Ninja** — automatically installable by the script: + +```powershell +# Enable script execution (one-time): +Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned + +# Complete setup (downloads everything, compiles, and configures): +.\setup-windows.ps1 +``` + +Alternatively, if CMake and Ninja are already in the PATH: + +```powershell +.\setup-windows.ps1 -SkipTools +``` + +### Manual build (if you prefer to control each step) + +```powershell +# build.ps1 downloads llvm-mingw, compiles Z3 from source, and compiles SVF: +.\build.ps1 + +# With static libraries: +.\build.ps1 -BuildSharedLibs OFF + +# Debug build: +.\build.ps1 -BuildType Debug +``` + +### Verification + +```powershell +# Dot-sourcing is required to update the PATH in the current session: +. .\setup.ps1 + +# Smoke test: +wpa --help + +# Test with bitcode: +clang -emit-llvm -c -g test.c -o test.bc +wpa -ander -print-fp -stat=false test.bc +``` + +--- + +## Pre-merge Checklist + +- [ ] `build.sh sta_lib nortti` completes without errors in MSYS2 CLANG64 +- [ ] `wpa.exe` responds to `--help` (MSYS2) +- [ ] `extapi.bc` present in `Release-build/lib/` (MSYS2) +- [ ] `.\build.ps1` completes without errors in PowerShell (llvm-mingw) +- [ ] `wpa.exe` responds to `--help` (llvm-mingw) +- [ ] `extapi.bc` present in `Release-build/lib/` (llvm-mingw) +- [ ] Linux build has no regressions (CI) +- [ ] macOS build has no regressions (CI) + +--- + +## Common issues + +### `clang not found` in MSYS2 +Verify you are in the **CLANG64** terminal: +```bash +echo $MSYSTEM # must print CLANG64 +``` + +### Missing DLLs at `wpa` startup (MSYS2) +```bash +source ./setup.sh Release +ldd Release-build/bin/wpa.exe | grep "not found" +``` + +### Missing DLLs at `wpa` startup (PowerShell) +```powershell +. .\setup.ps1 +# setup.ps1 adds llvm-mingw\bin to the PATH where MinGW DLLs reside +``` + +### PowerShell blocks the script +```powershell +Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned +``` + +### `extapi.bc` not found at runtime +SVF searches for `extapi.bc` in the following order: +1. The `-extapi=path/to/extapi.bc` option +2. `SVF_BUILD_DIR/lib/extapi.bc` (injected at compile-time by CMake) +3. `$SVF_DIR/-build/lib/extapi.bc` +4. Output of `npm root` +5. Loaded DLL directory (not available on Windows — no `dladdr`) + +Ensure that `SVF_DIR` is set (handled by `setup.ps1`/`setup.sh`). diff --git a/setup-windows.ps1 b/setup-windows.ps1 new file mode 100644 index 0000000000..7fd79fa86a --- /dev/null +++ b/setup-windows.ps1 @@ -0,0 +1,181 @@ +<# +.SYNOPSIS + Complete SVF setup on Windows — installs dependencies and runs the build. + +.DESCRIPTION + All-in-one script based on llvm-mingw (Clang + MinGW/UCRT). + Does not require Visual Studio or MSYS2. + + Steps performed: + 1. Verify winget + 2. Install CMake (if missing) + 3. Install Ninja (if missing) + 4. Run build.ps1 to download llvm-mingw, compile Z3, and build SVF + + Estimated first run time: 15-30 minutes + - llvm-mingw download: ~300 MB + - Z3 compilation from source: ~5 minutes + - SVF compilation: ~5-10 minutes + +.PARAMETER BuildType + Release (default) or Debug. + +.PARAMETER BuildSharedLibs + ON (default) for DLL with RTTI, OFF for static libraries. + llvm-mingw compiles LLVM with RTTI enabled, so ON works. + +.PARAMETER SkipTools + Skip CMake and Ninja installation (if already in PATH). + +.EXAMPLE + .\setup-windows.ps1 + .\setup-windows.ps1 -BuildType Debug + .\setup-windows.ps1 -BuildSharedLibs OFF + .\setup-windows.ps1 -SkipTools +#> + +param( + [ValidateSet("Release", "Debug")] + [string]$BuildType = "Release", + + [ValidateSet("ON", "OFF")] + [string]$BuildSharedLibs = "OFF", + + [string]$LLVMDir = "", + + [ValidateSet("mingw", "msvc")] + [string]$Compiler = "mingw", + + [switch]$SkipTools +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +function Write-Step { + param([string]$Msg) + Write-Host "" + Write-Host "==> $Msg" -ForegroundColor Cyan +} + +# --------------------------------------------------------------------------- +# 1. Verify winget +# --------------------------------------------------------------------------- + +Write-Step "Verifying system prerequisites" + +if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { + throw "winget not found. Update Windows or install 'App Installer' from the Microsoft Store." +} +Write-Host " winget: OK" + +# --------------------------------------------------------------------------- +# 2. Execution policy +# --------------------------------------------------------------------------- + +Write-Step "Verifying execution policy" +$policy = Get-ExecutionPolicy -Scope CurrentUser +if ($policy -eq "Restricted" -or $policy -eq "Undefined") { + Write-Host " Setting RemoteSigned execution policy for current user..." + try { + Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force -ErrorAction SilentlyContinue + Write-Host " Execution policy updated." -ForegroundColor Green + } catch { + Write-Host " Failed to update execution policy for current user, but execution continues." -ForegroundColor Yellow + } +} else { + Write-Host " Execution policy: $policy - OK" +} + +# --------------------------------------------------------------------------- +# 3. CMake and Ninja +# --------------------------------------------------------------------------- + +if (-not $SkipTools) { + Write-Step "Checking CMake" + + if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { + Write-Host " CMake not found. Installing with winget..." + winget install --id Kitware.CMake --exact --silent ` + --accept-package-agreements --accept-source-agreements + # Reload PATH in session + $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("PATH", "User") + if (Get-Command cmake -ErrorAction SilentlyContinue) { + Write-Host " CMake installed: OK" -ForegroundColor Green + } else { + Write-Host " CMake installed but not yet in PATH." -ForegroundColor Yellow + Write-Host " Restart PowerShell and rerun the script if the build fails." -ForegroundColor Yellow + } + } else { + $v = cmake --version | Select-Object -First 1 + Write-Host " CMake already present: $v" + } + + Write-Step "Checking Ninja" + + if (-not (Get-Command ninja -ErrorAction SilentlyContinue)) { + Write-Host " Ninja not found. Installing with winget..." + winget install --id Ninja-build.Ninja --exact --silent ` + --accept-package-agreements --accept-source-agreements + $env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("PATH", "User") + if (Get-Command ninja -ErrorAction SilentlyContinue) { + Write-Host " Ninja installed: OK" -ForegroundColor Green + } else { + Write-Host " Ninja installed but not yet in PATH." -ForegroundColor Yellow + Write-Host " Restart PowerShell and rerun the script if the build fails." -ForegroundColor Yellow + } + } else { + $v = ninja --version + Write-Host " Ninja already present: $v" + } +} else { + Write-Host " [SkipTools] Skipping CMake/Ninja check." +} + +# --------------------------------------------------------------------------- +# 4. Build SVF (Local LLVM + Clang SDK + Z3 from source + SVF) +# --------------------------------------------------------------------------- + +Write-Step "Starting SVF build" +Write-Host " BuildType: $BuildType" +Write-Host " BuildSharedLibs: $BuildSharedLibs" +Write-Host " Toolchain: Local LLVM + Clang SDK (clang++, no VS Build Tools, no local MSYS2 install)" +Write-Host "" + +$buildScript = Join-Path $ScriptDir "build.ps1" +if (-not (Test-Path $buildScript)) { + throw "build.ps1 not found in $ScriptDir." +} + +$buildArgs = @{ + BuildType = $BuildType + BuildSharedLibs = $BuildSharedLibs + Compiler = $Compiler +} +if ($LLVMDir) { + $buildArgs["LLVMDir"] = $LLVMDir +} +& $buildScript @buildArgs + +# --------------------------------------------------------------------------- +# 5. Final summary +# --------------------------------------------------------------------------- + +Write-Host "" +Write-Host "============================================================" -ForegroundColor Green +Write-Host " Setup completed." -ForegroundColor Green +Write-Host "" +Write-Host " To use SVF in the current session:" -ForegroundColor White +Write-Host " . .\setup.ps1" -ForegroundColor Yellow +Write-Host "" +Write-Host " Smoke test:" -ForegroundColor White +Write-Host " wpa --help" -ForegroundColor Yellow +Write-Host "" +Write-Host " Test with bitcode:" -ForegroundColor White +Write-Host " clang -emit-llvm -c test.c -o test.bc" -ForegroundColor Yellow +Write-Host " wpa -ander -stat=false test.bc" -ForegroundColor Yellow +Write-Host "============================================================" -ForegroundColor Green diff --git a/setup.ps1 b/setup.ps1 new file mode 100644 index 0000000000..9f3785569b --- /dev/null +++ b/setup.ps1 @@ -0,0 +1,59 @@ +<# +.SYNOPSIS + Configures the PATH to use SVF compiled on Windows with llvm-mingw. + +.PARAMETER BuildType + Release (default) or Debug. + +.EXAMPLE + . .\setup.ps1 # dot-source required to modify the PATH + . .\setup.ps1 Debug + +.NOTES + Always use dot-sourcing (. .\setup.ps1), otherwise environment variables + will be set in a sub-process and then lost. +#> + +param( + [ValidateSet("Release", "Debug")] + [string]$BuildType = "Release" +) + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$BuildDir = Join-Path $ScriptDir "$BuildType-build" + +if (-not (Test-Path $BuildDir)) { + Write-Error "Build directory not found: $BuildDir. Run build.ps1 first." + return +} + +# Resolve LLVM_DIR and Z3_DIR — same logic as build.ps1 +$LLVMSdk = Join-Path $ScriptDir "llvm-sdk.obj\clang64" +$Z3Home = Join-Path $ScriptDir "z3.obj" + +if (Test-Path $LLVMSdk) { + $env:LLVM_DIR = $LLVMSdk +} +if (-not $env:Z3_DIR) { + if (Test-Path $Z3Home) { $env:Z3_DIR = $Z3Home } +} + +# On Windows, DLLs must be in the PATH (not LD_LIBRARY_PATH). +$additions = @() +if ($env:LLVM_DIR) { $additions += "$env:LLVM_DIR\bin" } +if ($env:Z3_DIR) { $additions += "$env:Z3_DIR\bin"; $additions += "$env:Z3_DIR\lib" } +$additions += "$BuildDir\bin" +$additions += "$BuildDir\lib" + +foreach ($p in $additions) { + if ((Test-Path $p) -and ($env:PATH -notlike "*$p*")) { + $env:PATH = "$p;$env:PATH" + } +} + +$env:SVF_DIR = $ScriptDir + +Write-Host "SVF_DIR = $env:SVF_DIR" +Write-Host "LLVM_DIR = $env:LLVM_DIR" +Write-Host "Z3_DIR = $env:Z3_DIR" +Write-Host "PATH updated. Now you can use: wpa, dvf, saber, ae, ..." diff --git a/setup.sh b/setup.sh index cc02486eaa..2518682cb4 100755 --- a/setup.sh +++ b/setup.sh @@ -64,15 +64,20 @@ fi Build="${PTAOBJTY}-build" -# Add LLVM & Z3 to $PATH and $LD_LIBRARY_PATH (prepend so that selected instances will be used first) -export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$PATH -export LD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$LD_LIBRARY_PATH -export DYLD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$DYLD_LIBRARY_PATH +if [[ "$(uname -s)" == MINGW* || "$(uname -s)" == MSYS* ]]; then + # On Windows, DLLs must be in the PATH (LD_LIBRARY_PATH is ignored) + export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$SVF_DIR/$Build/bin:$PATH +else + # Add LLVM & Z3 to $PATH and $LD_LIBRARY_PATH (prepend so that selected instances will be used first) + export PATH=$LLVM_DIR/bin:$Z3_DIR/bin:$PATH + export LD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$LD_LIBRARY_PATH + export DYLD_LIBRARY_PATH=$LLVM_DIR/lib:$Z3_DIR/bin:$DYLD_LIBRARY_PATH -# Add compiled SVF binaries dir to $PATH -export PATH=$SVF_DIR/$Build/bin:$PATH + # Add compiled SVF binaries dir to $PATH + export PATH=$SVF_DIR/$Build/bin:$PATH -# Add compiled library directories to $LD_LIBRARY_PATH -export LD_LIBRARY_PATH=$SVF_DIR/$Build/svf:$SVF_DIR/$Build/svf-llvm:$LD_LIBRARY_PATH + # Add compiled library directories to $LD_LIBRARY_PATH + export LD_LIBRARY_PATH=$SVF_DIR/$Build/svf:$SVF_DIR/$Build/svf-llvm:$LD_LIBRARY_PATH +fi echo "Added SVF, LLVM, and Z3 to each of \$PATH, \$LD_LIBRARY_PATH, and \$DYLD_LIBRARY_PATH." diff --git a/svf-llvm/CMakeLists.txt b/svf-llvm/CMakeLists.txt index 65ec966564..f871648dd7 100644 --- a/svf-llvm/CMakeLists.txt +++ b/svf-llvm/CMakeLists.txt @@ -4,11 +4,16 @@ # Find the LLVM instance to build & link SvfLLVM against (prioritise $LLVM_DIR) find_package(LLVM CONFIG REQUIRED HINTS ${LLVM_HOME} $ENV{LLVM_HOME} ${LLVM_DIR} $ENV{LLVM_DIR}) +add_compile_definitions(LLVM_BUILD_STATIC) # Import certain utilities (e.g. to make add_llvm_library() available) list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") include(AddLLVM) +macro(add_llvm_executable target) + add_executable(${target} ${ARGN}) +endmacro() + # If exceptions are disabled, verify the LLVM instance could never raise them if(LLVM_ENABLE_EH AND NOT SVF_ENABLE_EXCEPTIONS) message(WARNING "LLVM could throw exceptions but SVF configured to disable exception handling; " @@ -45,6 +50,9 @@ include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) add_definitions(${_LLVM_DEFINITIONS}) +# Force dynamic dylib link checking to OFF so that llvm_map_components_to_libnames returns the individual component libraries. +set(LLVM_LINK_LLVM_DYLIB OFF) + # Use all components as link targets (picks dynamic/static libs); store in $LLVM_LIBRARIES if(LLVM_LINK_LLVM_DYLIB) set(LLVM_LIBRARIES LLVM) @@ -72,6 +80,23 @@ else() list(FILTER LLVM_LIBRARIES EXCLUDE REGEX "^LLVMSvf(Core|LLVM)$|^LLVMSVFAnalysis$") endif() +if(MINGW) + # Glob all static library files matching libLLVM*.a from the LLVM library directory + file(GLOB LLVM_STATIC_LIBS "${LLVM_LIBRARY_DIRS}/libLLVM*.a") + # Exclude import libraries (.dll.a) to avoid dynamic linking + list(FILTER LLVM_STATIC_LIBS EXCLUDE REGEX "\\.dll\\.a$") + # Also append static system libraries required by LLVM support and XML/compression features + list(APPEND LLVM_STATIC_LIBS + "${LLVM_LIBRARY_DIRS}/libzstd.a" + "${LLVM_LIBRARY_DIRS}/libxml2.a" + "${LLVM_LIBRARY_DIRS}/libz.a" + "${LLVM_LIBRARY_DIRS}/libffi.a" + bcrypt + ntdll + ) + set(LLVM_LIBRARIES ${LLVM_STATIC_LIBS}) +endif() + # Search in the executables dir for this LLVM's clang instance find_program(LLVM_CLANG clang ${LLVM_BINARY_DIR} ${LLVM_TOOLS_BINARY_DIR}) if(NOT LLVM_CLANG) @@ -111,9 +136,15 @@ else() endif() # Add a custom command to compile the extapi.bc bitcode file from extapi.c +if(WIN32) + set(EXTAPI_PIC_FLAG "") +else() + set(EXTAPI_PIC_FLAG "-fPIC") +endif() + add_custom_command( OUTPUT ${SVF_BUILD_EXTAPI_BC} - COMMAND ${LLVM_CLANG} -w -S -c -fPIC -std=gnu11 -emit-llvm -o ${SVF_BUILD_EXTAPI_BC} ${EXTAPI_SRC} + COMMAND ${LLVM_CLANG} -w -S -c ${EXTAPI_PIC_FLAG} -std=gnu11 -emit-llvm -o ${SVF_BUILD_EXTAPI_BC} ${EXTAPI_SRC} COMMENT "Generating extapi.bc LLVM bitcode file..." MAIN_DEPENDENCY ${EXTAPI_SRC} DEPENDS ${EXTAPI_SRC} diff --git a/svf-llvm/include/SVF-LLVM/CppUtil.h b/svf-llvm/include/SVF-LLVM/CppUtil.h index b0a5c06b26..a6250bfb18 100644 --- a/svf-llvm/include/SVF-LLVM/CppUtil.h +++ b/svf-llvm/include/SVF-LLVM/CppUtil.h @@ -51,8 +51,45 @@ struct DemangledName bool isThunkFunc; }; -struct DemangledName demangle(const std::string& name); +class CXXABI +{ +public: + virtual ~CXXABI() = default; + virtual bool isVtable(const std::string& name) = 0; + virtual bool isTypeInfo(const std::string& name) = 0; + virtual bool isConstructor(const std::string& name) = 0; + virtual bool isDestructor(const std::string& name) = 0; + virtual std::string extractClassName(const std::string& name) = 0; + virtual DemangledName demangle(const std::string& name) = 0; +}; + +class ItaniumABI : public CXXABI +{ +public: + bool isVtable(const std::string& name) override; + bool isTypeInfo(const std::string& name) override; + bool isConstructor(const std::string& name) override; + bool isDestructor(const std::string& name) override; + std::string extractClassName(const std::string& name) override; + DemangledName demangle(const std::string& name) override; +}; +class MSVCABI : public CXXABI +{ +public: + bool isVtable(const std::string& name) override; + bool isTypeInfo(const std::string& name) override; + bool isConstructor(const std::string& name) override; + bool isDestructor(const std::string& name) override; + std::string extractClassName(const std::string& name) override; + DemangledName demangle(const std::string& name) override; +}; + +CXXABI* getCXXABI(); +CXXABI* getCXXABI(const Module* M); +CXXABI* getCXXABI(const Value* val); + +struct DemangledName demangle(const std::string& name); Set getClsNamesInBrackets(const std::string& name); @@ -80,7 +117,7 @@ std::string getClassNameFromVtblObj(const std::string& vtblName); * * See https://github.com/SVF-tools/SVF/issues/1114 for more. */ -const ConstantStruct *getVtblStruct(const GlobalValue *vtbl); +const ConstantStruct* getVtblStruct(const GlobalValue* vtbl); bool isValVtbl(const Value* val); bool isVirtualCallSite(const CallBase* cs); @@ -133,28 +170,29 @@ bool isSameThisPtrInConstructor(const Argument* thisPtr1, const Value* thisPtr2); /// extract class name from the c++ function name, e.g., constructor/destructors -Set extractClsNamesFromFunc(const Function *foo); +Set extractClsNamesFromFunc(const Function* foo); /// extract class names from template functions -Set extractClsNamesFromTemplate(const std::string &oname); +Set extractClsNamesFromTemplate(const std::string& oname); /// class sources can be heap allocation -/// or functions where we can extract the class name (constructors/destructors or template functions) -bool isClsNameSource(const Value *val); +/// or functions where we can extract the class name (constructors/destructors +/// or template functions) +bool isClsNameSource(const Value* val); /// whether foo matches the mangler label -bool matchesLabel(const std::string &foo, const std::string &label); +bool matchesLabel(const std::string& foo, const std::string& label); /// whether foo is a cpp template function -bool isTemplateFunc(const Function *foo); +bool isTemplateFunc(const Function* foo); /// whether foo is a cpp dyncast function -bool isDynCast(const Function *foo); +bool isDynCast(const Function* foo); /// extract class name from cpp dyncast function std::string extractClsNameFromDynCast(const CallBase* callBase); -const Type *cppClsNameToType(const std::string &className); +const Type* cppClsNameToType(const std::string& className); } // End namespace cppUtil } // End namespace SVF diff --git a/svf-llvm/include/SVF-LLVM/GEPTypeBridgeIterator.h b/svf-llvm/include/SVF-LLVM/GEPTypeBridgeIterator.h index 0997bf219b..cce105b24f 100644 --- a/svf-llvm/include/SVF-LLVM/GEPTypeBridgeIterator.h +++ b/svf-llvm/include/SVF-LLVM/GEPTypeBridgeIterator.h @@ -4,23 +4,24 @@ #ifndef SVF_GEPTYPEBRIDGEITERATOR_H #define SVF_GEPTYPEBRIDGEITERATOR_H +#include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/Operator.h" #include "llvm/IR/User.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/IR/GetElementPtrTypeIterator.h" namespace llvm { -template +template class generic_bridge_gep_type_iterator { ItTy OpIt; - PointerIntPair CurTy; + PointerIntPair CurTy; unsigned AddrSpace; generic_bridge_gep_type_iterator() {} + public: using iterator_category = std::forward_iterator_tag; using value_type = Type*; @@ -37,7 +38,7 @@ class generic_bridge_gep_type_iterator } static generic_bridge_gep_type_iterator begin(Type* Ty, unsigned AddrSpace, - ItTy It) + ItTy It) { generic_bridge_gep_type_iterator I; I.CurTy.setPointer(Ty); @@ -66,7 +67,7 @@ class generic_bridge_gep_type_iterator Type* operator*() const { - if ( CurTy.getInt() ) + if (CurTy.getInt()) return PointerType::get(CurTy.getPointer()->getContext(), AddrSpace); return CurTy.getPointer(); } @@ -74,10 +75,10 @@ class generic_bridge_gep_type_iterator Type* getIndexedType() const { assert(false && "needs to be refactored"); - if ( CurTy.getInt() ) + if (CurTy.getInt()) return CurTy.getPointer(); #if LLVM_VERSION_MAJOR >= 11 - Type* CT = CurTy.getPointer(); + Type* CT = CurTy.getPointer(); if (auto ST = dyn_cast(CT)) return ST->getTypeAtIndex(getOperand()); else if (auto Array = dyn_cast(CT)) @@ -87,7 +88,7 @@ class generic_bridge_gep_type_iterator else return CT; #else - CompositeType *CT = llvm::cast( CurTy.getPointer() ); + CompositeType* CT = llvm::cast(CurTy.getPointer()); return CT->getTypeAtIndex(getOperand()); #endif } @@ -104,15 +105,14 @@ class generic_bridge_gep_type_iterator return const_cast(&**OpIt); } - generic_bridge_gep_type_iterator& operator++() { - if ( CurTy.getInt() ) + if (CurTy.getInt()) { CurTy.setInt(false); } #if LLVM_VERSION_MAJOR >= 11 - else if ( Type* CT = CurTy.getPointer() ) + else if (Type* CT = CurTy.getPointer()) { if (auto ST = dyn_cast(CT)) CurTy.setPointer(ST->getTypeAtIndex(getOperand())); @@ -124,7 +124,8 @@ class generic_bridge_gep_type_iterator CurTy.setPointer(nullptr); } #else - else if ( CompositeType * CT = dyn_cast(CurTy.getPointer()) ) + else if (CompositeType* CT = + dyn_cast(CurTy.getPointer())) { CurTy.setPointer(CT->getTypeAtIndex(getOperand())); } @@ -137,25 +138,24 @@ class generic_bridge_gep_type_iterator return *this; } - generic_bridge_gep_type_iterator operator++(int) { generic_bridge_gep_type_iterator tmp = *this; ++*this; return tmp; } - }; - typedef generic_bridge_gep_type_iterator<> bridge_gep_iterator; inline bridge_gep_iterator bridge_gep_begin(const User* GEP) { - auto *GEPOp = llvm::cast(GEP); - return bridge_gep_iterator::begin(GEPOp->getSourceElementType(), - llvm::cast(GEPOp->getPointerOperandType()->getScalarType())->getAddressSpace(), - GEP->op_begin() + 1); + auto* GEPOp = llvm::cast(GEP); + return bridge_gep_iterator::begin( + GEPOp->getSourceElementType(), + llvm::cast(GEPOp->getPointerOperandType()->getScalarType()) + ->getAddressSpace(), + GEP->op_begin() + 1); } inline bridge_gep_iterator bridge_gep_end(const User* GEP) @@ -163,21 +163,24 @@ inline bridge_gep_iterator bridge_gep_end(const User* GEP) return bridge_gep_iterator::end(GEP->op_end()); } -inline bridge_gep_iterator bridge_gep_begin(const User &GEP) +inline bridge_gep_iterator bridge_gep_begin(const User& GEP) { - auto &GEPOp = llvm::cast(GEP); - return bridge_gep_iterator::begin( GEPOp.getSourceElementType(), - llvm::cast(GEPOp.getPointerOperandType()->getScalarType())->getAddressSpace(), - GEP.op_begin() + 1); + auto& GEPOp = llvm::cast(GEP); + return bridge_gep_iterator::begin( + GEPOp.getSourceElementType(), + llvm::cast(GEPOp.getPointerOperandType()->getScalarType()) + ->getAddressSpace(), + GEP.op_begin() + 1); } -inline bridge_gep_iterator bridge_gep_end(const User &GEP) +inline bridge_gep_iterator bridge_gep_end(const User& GEP) { return bridge_gep_iterator::end(GEP.op_end()); } -template -inline generic_bridge_gep_type_iterator bridge_gep_end( Type* /*Op0*/, ArrayRef A ) +template +inline generic_bridge_gep_type_iterator bridge_gep_end(Type* /*Op0*/, + ArrayRef A) { return generic_bridge_gep_type_iterator::end(A.end()); } diff --git a/svf-llvm/lib/BreakConstantExpr.cpp b/svf-llvm/lib/BreakConstantExpr.cpp index 76b2a0fe28..65a3c7cf95 100644 --- a/svf-llvm/lib/BreakConstantExpr.cpp +++ b/svf-llvm/lib/BreakConstantExpr.cpp @@ -24,8 +24,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Author: Yulei Sui */ - - //===- BreakConstantGEPs.cpp - Change constant GEPs into GEP instructions - --// // // The SAFECode Compiler @@ -40,14 +38,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // //===----------------------------------------------------------------------===// - #include "llvm/ADT/Statistic.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/IR/InstIterator.h" #include "SVF-LLVM/BasicTypes.h" #include "SVF-LLVM/BreakConstantExpr.h" @@ -67,8 +64,8 @@ char MergeFunctionRets::ID = 0; #define DEBUG_TYPE "break-constgeps" // Statistics -STATISTIC (GEPChanges, "Number of Converted GEP Constant Expressions"); -STATISTIC (TotalChanges, "Number of Converted Constant Expressions"); +STATISTIC(GEPChanges, "Number of Converted GEP Constant Expressions"); +STATISTIC(TotalChanges, "Number of Converted Constant Expressions"); // // Function: hasConstantGEP() @@ -81,14 +78,14 @@ STATISTIC (TotalChanges, "Number of Converted Constant Expressions"); // V - The value to check. // // Return value: -// nullptr - This value is not a constant expression with a constant expression +// nullptr - This value is not a constant expression with a constant +// expression // GEP within it. // ~nullptr - A pointer to the value casted into a ConstantExpr is returned. // -static ConstantExpr * -hasConstantGEP (Value* V) +static ConstantExpr* hasConstantGEP(Value* V) { - if (ConstantExpr * CE = SVFUtil::dyn_cast(V)) + if (ConstantExpr* CE = SVFUtil::dyn_cast(V)) { if (CE->getOpcode() == Instruction::GetElementPtr) { @@ -98,7 +95,7 @@ hasConstantGEP (Value* V) { for (u32_t index = 0; index < CE->getNumOperands(); ++index) { - if (hasConstantGEP (CE->getOperand(index))) + if (hasConstantGEP(CE->getOperand(index))) return CE; } } @@ -110,12 +107,12 @@ hasConstantGEP (Value* V) // Description: // This function determines whether the given value is a constant expression // that has a constant binary or unary operator expression embedded within it. -static ConstantExpr * -hasConstantBinaryOrUnaryOp (Value* V) +static ConstantExpr* hasConstantBinaryOrUnaryOp(Value* V) { - if (ConstantExpr * CE = SVFUtil::dyn_cast(V)) + if (ConstantExpr* CE = SVFUtil::dyn_cast(V)) { - if (Instruction::isBinaryOp(CE->getOpcode()) || Instruction::isUnaryOp(CE->getOpcode())) + if (Instruction::isBinaryOp(CE->getOpcode()) || + Instruction::isUnaryOp(CE->getOpcode())) { return CE; } @@ -123,7 +120,7 @@ hasConstantBinaryOrUnaryOp (Value* V) { for (u32_t index = 0; index < CE->getNumOperands(); ++index) { - if (hasConstantBinaryOrUnaryOp (CE->getOperand(index))) + if (hasConstantBinaryOrUnaryOp(CE->getOperand(index))) return CE; } } @@ -134,14 +131,13 @@ hasConstantBinaryOrUnaryOp (Value* V) // Description: // Return true if this is a constant Gep or binaryOp or UnaryOp expression -static ConstantExpr * -hasConstantExpr (Value* V) +static ConstantExpr* hasConstantExpr(Value* V) { - if (ConstantExpr * gep = hasConstantGEP(V)) + if (ConstantExpr* gep = hasConstantGEP(V)) { return gep; } - else if (ConstantExpr * buop = hasConstantBinaryOrUnaryOp(V)) + else if (ConstantExpr* buop = hasConstantBinaryOrUnaryOp(V)) { return buop; } @@ -151,7 +147,6 @@ hasConstantExpr (Value* V) } } - // // Function: convertExpression() // @@ -160,8 +155,7 @@ hasConstantExpr (Value* V) // perform any recursion, so the resulting instruction may have constant // expression operands. // -static Instruction* -convertExpression (ConstantExpr * CE, Instruction* InsertPt) +static Instruction* convertExpression(ConstantExpr* CE, Instruction* InsertPt) { // // Convert this constant expression into a regular instruction. @@ -184,33 +178,33 @@ convertExpression (ConstantExpr * CE, Instruction* InsertPt) // true - The function was modified. // false - The function was not modified. // -bool -BreakConstantGEPs::runOnModule (Module & module) +bool BreakConstantGEPs::runOnModule(Module& module) { bool modified = false; for (Module::iterator F = module.begin(), E = module.end(); F != E; ++F) { // Worklist of values to check for constant GEP expressions - std::vector Worklist; + std::vector Worklist; // - // Initialize the worklist by finding all instructions that have one or more - // operands containing a constant GEP expression. + // Initialize the worklist by finding all instructions that have one or + // more operands containing a constant GEP expression. // for (Function::iterator BB = (*F).begin(); BB != (*F).end(); ++BB) { for (BasicBlock::iterator i = BB->begin(); i != BB->end(); ++i) { // - // Scan through the operands of this instruction. If it is a constant - // expression GEP, insert an instruction GEP before the instruction. + // Scan through the operands of this instruction. If it is a + // constant expression GEP, insert an instruction GEP before the + // instruction. // - Instruction* I = &(*i); + Instruction* I = &(*i); for (u32_t index = 0; index < I->getNumOperands(); ++index) { if (hasConstantExpr(I->getOperand(index))) { - Worklist.push_back (I); + Worklist.push_back(I); } } } @@ -219,7 +213,8 @@ BreakConstantGEPs::runOnModule (Module & module) // // Determine whether we will modify anything. // - if (Worklist.size()) modified = true; + if (Worklist.size()) + modified = true; // // While the worklist is not empty, take an item from it, convert the @@ -228,37 +223,44 @@ BreakConstantGEPs::runOnModule (Module & module) // while (Worklist.size()) { - Instruction* I = Worklist.back(); + Instruction* I = Worklist.back(); Worklist.pop_back(); // - // Scan through the operands of this instruction and convert each into an - // instruction. Note that this works a little differently for phi - // instructions because the new instruction must be added to the - // appropriate predecessor block. + // Scan through the operands of this instruction and convert each + // into an instruction. Note that this works a little differently + // for phi instructions because the new instruction must be added to + // the appropriate predecessor block. // - if (PHINode * PHI = SVFUtil::dyn_cast(I)) + if (PHINode* PHI = SVFUtil::dyn_cast(I)) { - for (u32_t index = 0; index < PHI->getNumIncomingValues(); ++index) + for (u32_t index = 0; index < PHI->getNumIncomingValues(); + ++index) { // - // For PHI Nodes, if an operand is a constant expression with a GEP, we - // want to insert the new instructions in the predecessor basic block. + // For PHI Nodes, if an operand is a constant expression + // with a GEP, we want to insert the new instructions in the + // predecessor basic block. // - // Note: It seems that it's possible for a phi to have the same - // incoming basic block listed multiple times; this seems okay as long - // the same value is listed for the incoming block. + // Note: It seems that it's possible for a phi to have the + // same incoming basic block listed multiple times; this + // seems okay as long the same value is listed for the + // incoming block. // - Instruction* InsertPt = PHI->getIncomingBlock(index)->getTerminator(); - if (ConstantExpr * CE = hasConstantExpr(PHI->getIncomingValue(index))) + Instruction* InsertPt = + PHI->getIncomingBlock(index)->getTerminator(); + if (ConstantExpr* CE = + hasConstantExpr(PHI->getIncomingValue(index))) { - Instruction* NewInst = convertExpression (CE, InsertPt); - for (u32_t i2 = index; i2 < PHI->getNumIncomingValues(); ++i2) + Instruction* NewInst = convertExpression(CE, InsertPt); + for (u32_t i2 = index; i2 < PHI->getNumIncomingValues(); + ++i2) { - if ((PHI->getIncomingBlock (i2)) == PHI->getIncomingBlock (index)) - PHI->setIncomingValue (i2, NewInst); + if ((PHI->getIncomingBlock(i2)) == + PHI->getIncomingBlock(index)) + PHI->setIncomingValue(i2, NewInst); } - Worklist.push_back (NewInst); + Worklist.push_back(NewInst); } } } @@ -267,24 +269,20 @@ BreakConstantGEPs::runOnModule (Module & module) for (u32_t index = 0; index < I->getNumOperands(); ++index) { // - // For other instructions, we want to insert instructions replacing - // constant expressions immediately before the instruction using the - // constant expression. + // For other instructions, we want to insert instructions + // replacing constant expressions immediately before the + // instruction using the constant expression. // - if (ConstantExpr * CE = hasConstantExpr(I->getOperand(index))) + if (ConstantExpr* CE = + hasConstantExpr(I->getOperand(index))) { - Instruction* NewInst = convertExpression (CE, I); - I->replaceUsesOfWith (CE, NewInst); - Worklist.push_back (NewInst); + Instruction* NewInst = convertExpression(CE, I); + I->replaceUsesOfWith(CE, NewInst); + Worklist.push_back(NewInst); } } } } - } return modified; } - - - - diff --git a/svf-llvm/lib/CHGBuilder.cpp b/svf-llvm/lib/CHGBuilder.cpp index 50d7cb0524..0aaf6f190f 100644 --- a/svf-llvm/lib/CHGBuilder.cpp +++ b/svf-llvm/lib/CHGBuilder.cpp @@ -54,8 +54,6 @@ using namespace std; const string pureVirtualFunName = "__cxa_pure_virtual"; -const string ztiLabel = "_ZTI"; - LLVMModuleSet* CHGBuilder::llvmModuleSet() { return LLVMModuleSet::getLLVMModuleSet(); @@ -411,11 +409,11 @@ void CHGBuilder::analyzeVTables(const Module &M) { if (i > 0 && !SVFUtil::isa(vtbl->getOperand(i-1))) { - auto foo = [&is_virtual, &null_ptr_num, &vtbl, &i](const Value* val) - { - if (val->getName().str().compare(0, ztiLabel.size(), ztiLabel) == 0) - { - is_virtual = true; + auto foo = [&is_virtual, &null_ptr_num, &vtbl, &i](const Value* val) + { + if (getCXXABI(val)->isTypeInfo(val->getName().str())) + { + is_virtual = true; null_ptr_num = 1; while (i+null_ptr_num < vtbl->getNumOperands()) { @@ -497,10 +495,9 @@ void CHGBuilder::analyzeVTables(const Module &M) pure_abstract &= false; } - else if (operand->getName().str().compare(0, ztiLabel.size(), - ztiLabel) == 0) - { - } + else if (getCXXABI(operand)->isTypeInfo(operand->getName().str())) + { + } else { assert("what else can be in bitcast of a vtable?"); diff --git a/svf-llvm/lib/CppUtil.cpp b/svf-llvm/lib/CppUtil.cpp index 2234a943de..deef5e0578 100644 --- a/svf-llvm/lib/CppUtil.cpp +++ b/svf-llvm/lib/CppUtil.cpp @@ -29,13 +29,37 @@ #include "SVF-LLVM/CppUtil.h" #include "SVF-LLVM/BasicTypes.h" +#include "SVF-LLVM/LLVMModule.h" #include "SVF-LLVM/LLVMUtil.h" +#include "SVF-LLVM/ObjTypeInference.h" #include "Util/Casting.h" #include "Util/SVFUtil.h" -#include "SVF-LLVM/LLVMModule.h" -#include "SVF-LLVM/ObjTypeInference.h" -#include // for demangling +#if defined(_WIN32) +# include "llvm/Demangle/Demangle.h" +# include +# include +namespace abi +{ +static char* __cxa_demangle(const char* name, char*, size_t*, int* status) +{ + std::string d = llvm::demangle(name); + if (d == name) + { + if (status) + *status = -2; + return nullptr; + } + if (status) + *status = 0; + char* r = static_cast(std::malloc(d.size() + 1)); + std::memcpy(r, d.c_str(), d.size() + 1); + return r; +} +} // namespace abi +#else +# include // for demangling +#endif using namespace SVF; @@ -59,28 +83,45 @@ const std::string vtableType = "(...)**"; const std::string znwm = "_Znwm"; const std::string zn1Label = "_ZN1"; // c++ constructor const std::string znstLabel = "_ZNSt"; -const std::string znst5Label = "_ZNSt5"; // _ZNSt5dequeIPK1ASaIS2_EE5frontEv -> std::deque >::front() -const std::string znst12Label = "_ZNSt12"; // _ZNSt12forward_listIPK1ASaIS2_EEC2Ev -> std::forward_list >::forward_list() -const std::string znst6Label = "_ZNSt6"; // _ZNSt6vectorIP1ASaIS1_EEC2Ev -> std::vector >::vector() -const std::string znst7Label = "_ZNSt7"; // _ZNSt7__cxx114listIPK1ASaIS3_EEC2Ev -> std::__cxx11::list >::list() -const std::string znst14Label = "_ZNSt14"; // _ZNSt14_Fwd_list_baseI1ASaIS0_EEC2Ev -> std::_Fwd_list_base >::_Fwd_list_base() - +const std::string znst5Label = + "_ZNSt5"; // _ZNSt5dequeIPK1ASaIS2_EE5frontEv -> std::deque >::front() +const std::string znst12Label = + "_ZNSt12"; // _ZNSt12forward_listIPK1ASaIS2_EEC2Ev -> std::forward_list >::forward_list() +const std::string znst6Label = + "_ZNSt6"; // _ZNSt6vectorIP1ASaIS1_EEC2Ev -> std::vector >::vector() +const std::string znst7Label = + "_ZNSt7"; // _ZNSt7__cxx114listIPK1ASaIS3_EEC2Ev -> std::__cxx11::list >::list() +const std::string znst14Label = + "_ZNSt14"; // _ZNSt14_Fwd_list_baseI1ASaIS0_EEC2Ev -> std::_Fwd_list_base >::_Fwd_list_base() const std::string znkstLabel = "_ZNKSt"; -const std::string znkst5Label = "_ZNKSt15_"; // _ZNKSt15_Deque_iteratorIPK1ARS2_PS2_EdeEv -> std::_Deque_iterator::operator*() const -const std::string znkst20Label = "_ZNKSt20_"; // _ZNKSt20_List_const_iteratorIPK1AEdeEv -> std::_List_const_iterator::operator*() const - -const std::string znkst23Label = "_ZNKSt23_"; // _ZNKSt23_Rb_tree_const_iteratorISt4pairIKi1AEEptEv -> std::_List_const_iterator::operator*() const - +const std::string znkst5Label = + "_ZNKSt15_"; // _ZNKSt15_Deque_iteratorIPK1ARS2_PS2_EdeEv -> + // std::_Deque_iterator::operator*() const +const std::string znkst20Label = + "_ZNKSt20_"; // _ZNKSt20_List_const_iteratorIPK1AEdeEv -> + // std::_List_const_iterator::operator*() const + +const std::string znkst23Label = + "_ZNKSt23_"; // _ZNKSt23_Rb_tree_const_iteratorISt4pairIKi1AEEptEv -> + // std::_List_const_iterator::operator*() const const std::string znkLabel = "_ZNK"; -const std::string znk9Label = "_ZNK9"; // _ZNK9__gnu_cxx17__normal_iteratorIPK1ASt6vectorIS1_SaIS1_EEEdeEv -> __gnu_cxx::__normal_iterator > >::operator*() const +const std::string znk9Label = + "_ZNK9"; // _ZNK9__gnu_cxx17__normal_iteratorIPK1ASt6vectorIS1_SaIS1_EEEdeEv + // -> __gnu_cxx::__normal_iterator > >::operator*() const const std::string ztilabel = "_ZTI"; const std::string ztiprefix = "typeinfo for "; const std::string dyncast = "__dynamic_cast"; - static bool isOperOverload(const std::string& name) { u32_t leftnum = 0, rightnum = 0; @@ -156,13 +197,12 @@ static void handleThunkFunction(cppUtil::DemangledName& dname) // to get the real class name static std::vector thunkPrefixes = {VThunkFuncLabel, - NVThunkFunLabel - }; + NVThunkFunLabel}; for (unsigned i = 0; i < thunkPrefixes.size(); i++) { auto prefix = thunkPrefixes[i]; if (dname.className.size() > prefix.size() && - dname.className.compare(0, prefix.size(), prefix) == 0) + dname.className.compare(0, prefix.size(), prefix) == 0) { dname.className = dname.className.substr(prefix.size()); dname.isThunkFunc = true; @@ -194,57 +234,16 @@ static void handleThunkFunction(cppUtil::DemangledName& dname) struct cppUtil::DemangledName cppUtil::demangle(const std::string& name) { - struct cppUtil::DemangledName dname; - dname.isThunkFunc = false; - - s32_t status; - char* realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); - if (realname == nullptr) - { - dname.className = ""; - dname.funcName = ""; - } - else - { - std::string realnameStr = std::string(realname); - std::string beforeParenthesis = getBeforeParenthesis(realnameStr); - if (beforeParenthesis.find("::") == std::string::npos || - isOperOverload(beforeParenthesis)) - { - dname.className = ""; - dname.funcName = ""; - } - else - { - std::string beforeBracket = getBeforeBrackets(beforeParenthesis); - size_t colon = beforeBracket.rfind("::"); - if (colon == std::string::npos) - { - dname.className = ""; - dname.funcName = ""; - } - else - { - dname.className = beforeParenthesis.substr(0, colon); - dname.funcName = beforeParenthesis.substr(colon + 2); - } - } - std::free(realname); - } - - handleThunkFunction(dname); - - return dname; + return getCXXABI()->demangle(name); } // Extract class name in parameters -// e.g., given "WithSemaphore::WithSemaphore(AP_HAL::Semaphore&)", return "AP_HAL::Semaphore" +// e.g., given "WithSemaphore::WithSemaphore(AP_HAL::Semaphore&)", return +// "AP_HAL::Semaphore" Set cppUtil::getClsNamesInBrackets(const std::string& name) { Set res; - // Lambda to trim whitespace from both ends of a string - auto trim = [](std::string& s) - { + auto trim = [](std::string& s) { size_t first = s.find_first_not_of(' '); size_t last = s.find_last_not_of(' '); if (first != std::string::npos && last != std::string::npos) @@ -257,37 +256,41 @@ Set cppUtil::getClsNamesInBrackets(const std::string& name) } }; - // Lambda to remove trailing '*' and '&' characters - auto removePointerAndReference = [](std::string& s) - { + auto removePointerAndReference = [](std::string& s) { while (!s.empty() && (s.back() == '*' || s.back() == '&')) { s.pop_back(); } }; - s32_t status; - char* realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); - if (realname == nullptr) + std::string realnameStr = ""; + if (getCXXABI()->isConstructor(name) || getCXXABI()->isDestructor(name) || + name.find("?") == 0) { - // do nothing + realnameStr = llvm::demangle(name); } else { - std::string realnameStr = std::string(realname); + s32_t status; + char* realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); + if (realname != nullptr) + { + realnameStr = std::string(realname); + std::free(realname); + } + } - // Find the start and end of the parameter list + if (!realnameStr.empty()) + { size_t start = realnameStr.find('('); size_t end = realnameStr.find(')'); - if (start == std::string::npos || end == std::string::npos || start >= end) + if (start == std::string::npos || end == std::string::npos || + start >= end) { - return res; // Return empty set if the format is incorrect + return res; } - // Extract the parameter list std::string paramList = realnameStr.substr(start + 1, end - start - 1); - - // Split the parameter list by commas std::istringstream ss(paramList); std::string param; while (std::getline(ss, param, ',')) @@ -296,38 +299,24 @@ Set cppUtil::getClsNamesInBrackets(const std::string& name) removePointerAndReference(param); res.insert(param); } - std::free(realname); } return res; } std::string cppUtil::getClassNameFromVtblObj(const std::string& vtblName) { - std::string className = ""; - - s32_t status; - char* realname = abi::__cxa_demangle(vtblName.c_str(), 0, 0, &status); - if (realname != nullptr) - { - std::string realnameStr = std::string(realname); - if (realnameStr.compare(0, vtblLabelAfterDemangle.size(), - vtblLabelAfterDemangle) == 0) - { - className = realnameStr.substr(vtblLabelAfterDemangle.size()); - } - std::free(realname); - } - return className; + return getCXXABI()->extractClassName(vtblName); } -const ConstantStruct *cppUtil::getVtblStruct(const GlobalValue *vtbl) +const ConstantStruct* cppUtil::getVtblStruct(const GlobalValue* vtbl) { - const ConstantStruct *vtblStruct = SVFUtil::dyn_cast(vtbl->getOperand(0)); + const ConstantStruct* vtblStruct = + SVFUtil::dyn_cast(vtbl->getOperand(0)); assert(vtblStruct && "Initializer of a vtable not a struct?"); if (vtblStruct->getNumOperands() == 2 && - SVFUtil::isa(vtblStruct->getOperand(0)) && - vtblStruct->getOperand(1)->getType()->isArrayTy()) + SVFUtil::isa(vtblStruct->getOperand(0)) && + vtblStruct->getOperand(1)->getType()->isArrayTy()) return SVFUtil::cast(vtblStruct->getOperand(0)); return vtblStruct; @@ -338,8 +327,7 @@ bool cppUtil::isValVtbl(const Value* val) if (!SVFUtil::isa(val)) return false; std::string valName = val->getName().str(); - return valName.compare(0, vtblLabelBeforeDemangle.size(), - vtblLabelBeforeDemangle) == 0; + return getCXXABI(val)->isVtable(valName); } /* @@ -366,7 +354,7 @@ bool cppUtil::isVirtualCallSite(const CallBase* cs) { const Value* vfuncptr = vfuncloadinst->getPointerOperand(); if (const GetElementPtrInst* vfuncptrgepinst = - SVFUtil::dyn_cast(vfuncptr)) + SVFUtil::dyn_cast(vfuncptr)) { if (vfuncptrgepinst->getNumIndices() != 1) return false; @@ -431,14 +419,15 @@ static bool isDerivedFromThisPtr(const Argument* thisPtr, const Value* V) if (const LoadInst* load = SVFUtil::dyn_cast(V)) { if (const AllocaInst* alloca = - SVFUtil::dyn_cast(load->getPointerOperand())) + SVFUtil::dyn_cast(load->getPointerOperand())) { for (const User* U : alloca->users()) { if (const StoreInst* store = SVFUtil::dyn_cast(U)) { if (store->getPointerOperand() == alloca && - store->getValueOperand()->stripPointerCasts() == thisPtr) + store->getValueOperand()->stripPointerCasts() == + thisPtr) return true; } } @@ -482,7 +471,7 @@ static bool isDerivedFromThisPtr(const Argument* thisPtr, const Value* V) * → struct GEP from this, return false */ bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1, - const Value* thisPtr2) + const Value* thisPtr2) { if (thisPtr1 == thisPtr2) return true; @@ -496,7 +485,8 @@ bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1, return true; // === Opaque pointer: GEP check (Case 3 & 4) === - if (const GetElementPtrInst* GEP = SVFUtil::dyn_cast(stripped)) + if (const GetElementPtrInst* GEP = + SVFUtil::dyn_cast(stripped)) { if (!isDerivedFromThisPtr(thisPtr1, GEP->getPointerOperand())) return false; @@ -515,7 +505,7 @@ bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1, if (const LoadInst* load = SVFUtil::dyn_cast(storeU)) { if (load->getNextNode() && - SVFUtil::isa(load->getNextNode())) + SVFUtil::isa(load->getNextNode())) return SVFUtil::cast(load->getNextNode()) == (thisPtr2->stripPointerCasts()); } @@ -527,15 +517,16 @@ bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1, const Argument* cppUtil::getConstructorThisPtr(const Function* fun) { - assert((isConstructor(fun) || isDestructor(fun)) && - "not a constructor?"); + assert((isConstructor(fun) || isDestructor(fun)) && "not a constructor?"); // We always need at least one argument to return something meaningful. assert(fun->arg_size() >= 1 && "expected at least one argument"); // If param 0 is sret, 'this' is typically param 1, but be defensive. - const bool isStructRet = fun->hasParamAttribute(0, llvm::Attribute::StructRet); + const bool isStructRet = + fun->hasParamAttribute(0, llvm::Attribute::StructRet); - // Prefer arg1 when sret is present and available; otherwise fall back to arg0. + // Prefer arg1 when sret is present and available; otherwise fall back to + // arg0. const u32_t thisIdx = (isStructRet && fun->arg_size() >= 2) ? 1 : 0; const Argument* thisPtr = fun->getArg(thisIdx); @@ -543,7 +534,8 @@ const Argument* cppUtil::getConstructorThisPtr(const Function* fun) } /// strip off brackets and namespace from classname -/// e.g., for `namespace::A<...::...>::f', we get `A' by stripping off namespace and <> +/// e.g., for `namespace::A<...::...>::f', we get `A' by stripping off namespace +/// and <> void stripBracketsAndNamespace(cppUtil::DemangledName& dname) { dname.funcName = cppUtil::getBeforeBrackets(dname.funcName); @@ -566,19 +558,7 @@ bool cppUtil::isConstructor(const Function* F) if (F->isDeclaration()) return false; std::string funcName = F->getName().str(); - if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0) - { - return false; - } - struct cppUtil::DemangledName dname = cppUtil::demangle(funcName.c_str()); - if (dname.className.size() == 0) - { - return false; - } - stripBracketsAndNamespace(dname); - /// TODO: on mac os function name is an empty string after demangling - return dname.className.size() > 0 && - dname.className.compare(dname.funcName) == 0; + return getCXXABI(F)->isConstructor(funcName); } bool cppUtil::isDestructor(const Function* F) @@ -586,20 +566,7 @@ bool cppUtil::isDestructor(const Function* F) if (F->isDeclaration()) return false; std::string funcName = F->getName().str(); - if (funcName.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0) - { - return false; - } - struct cppUtil::DemangledName dname = cppUtil::demangle(funcName.c_str()); - if (dname.className.size() == 0) - { - return false; - } - stripBracketsAndNamespace(dname); - return (dname.className.size() > 0 && dname.funcName.size() > 0 && - dname.className.size() + 1 == dname.funcName.size() && - dname.funcName.compare(0, 1, "~") == 0 && - dname.className.compare(dname.funcName.substr(1)) == 0); + return getCXXABI(F)->isDestructor(funcName); } /* @@ -629,11 +596,12 @@ bool cppUtil::VCallInCtorOrDtor(const CallBase* cs) { Set classNameOfThisPtrs = cppUtil::getClassNameOfThisPtr(cs); const Function* func = cs->getCaller(); - for (const auto &classNameOfThisPtr: classNameOfThisPtrs) + for (const auto& classNameOfThisPtr : classNameOfThisPtrs) { if (cppUtil::isConstructor(func) || cppUtil::isDestructor(func)) { - cppUtil::DemangledName dname = cppUtil::demangle(func->getName().str()); + cppUtil::DemangledName dname = + cppUtil::demangle(func->getName().str()); if (classNameOfThisPtr.compare(dname.className) == 0) return true; } @@ -643,9 +611,9 @@ bool cppUtil::VCallInCtorOrDtor(const CallBase* cs) bool cppUtil::classTyHasVTable(const StructType* ty) { - if(getClassNameFromType(ty).empty()==false) + if (getClassNameFromType(ty).empty() == false) { - for(auto it = ty->element_begin(); it!=ty->element_end(); it++) + for (auto it = ty->element_begin(); it != ty->element_end(); it++) { const std::string& str = LLVMUtil::dumpType(*it); if (str.find(vtableType) != std::string::npos) @@ -685,25 +653,28 @@ Set cppUtil::getClassNameOfThisPtr(const CallBase* inst) if (thisPtrClassName.size() == 0) { const Value* thisPtr = getVCallThisPtr(inst); - Set& names = LLVMModuleSet::getLLVMModuleSet()->getTypeInference()->inferThisPtrClsName(thisPtr); + Set& names = LLVMModuleSet::getLLVMModuleSet() + ->getTypeInference() + ->inferThisPtrClsName(thisPtr); thisPtrNames.insert(names.begin(), names.end()); } Set ans; - std::transform(thisPtrNames.begin(), thisPtrNames.end(), std::inserter(ans, ans.begin()), - [](const std::string &thisPtrName) -> std::string - { - size_t found = thisPtrName.find_last_not_of("0123456789"); - if (found != std::string::npos) - { - if (found != thisPtrName.size() - 1 && - thisPtrName[found] == '.') - { - return thisPtrName.substr(0, found); - } - } - return thisPtrName; - }); + std::transform(thisPtrNames.begin(), thisPtrNames.end(), + std::inserter(ans, ans.begin()), + [](const std::string& thisPtrName) -> std::string { + size_t found = + thisPtrName.find_last_not_of("0123456789"); + if (found != std::string::npos) + { + if (found != thisPtrName.size() - 1 && + thisPtrName[found] == '.') + { + return thisPtrName.substr(0, found); + } + } + return thisPtrName; + }); return ans; } @@ -756,12 +727,19 @@ bool LLVMUtil::isConstantObjSym(const Value* val) } else { - StInfo *stInfo = LLVMModuleSet::getLLVMModuleSet()->getSVFType(v->getInitializer()->getType())->getTypeInfo(); - const std::vector &fields = stInfo->getFlattenFieldTypes(); - for (std::vector::const_iterator it = fields.begin(), eit = fields.end(); it != eit; ++it) + StInfo* stInfo = LLVMModuleSet::getLLVMModuleSet() + ->getSVFType(v->getInitializer()->getType()) + ->getTypeInfo(); + const std::vector& fields = + stInfo->getFlattenFieldTypes(); + for (std::vector::const_iterator + it = fields.begin(), + eit = fields.end(); + it != eit; ++it) { const SVFType* elemTy = *it; - assert(!SVFUtil::isa(elemTy) && "Initializer of a global is a function?"); + assert(!SVFUtil::isa(elemTy) && + "Initializer of a global is a function?"); if (SVFUtil::isa(elemTy)) return false; } @@ -778,9 +756,9 @@ bool LLVMUtil::isConstantObjSym(const Value* val) * @param foo * @return */ -Set cppUtil::extractClsNamesFromFunc(const Function *foo) +Set cppUtil::extractClsNamesFromFunc(const Function* foo) { - const std::string &name = foo->getName().str(); + const std::string& name = foo->getName().str(); if (isConstructor(foo) || isDestructor(foo)) { // c++ constructor or destructor @@ -802,11 +780,12 @@ Set cppUtil::extractClsNamesFromFunc(const Function *foo) /*! * find the innermost brackets, - * e.g., return "int const, A" for "__gnu_cxx::__aligned_membuf >::_M_ptr() const" + * e.g., return "int const, A" for "__gnu_cxx::__aligned_membuf >::_M_ptr() const" * @param input * @return */ -std::vector findInnermostBrackets(const std::string &input) +std::vector findInnermostBrackets(const std::string& input) { typedef std::pair StEdIdxPair; std::stack stack; @@ -839,16 +818,17 @@ std::vector findInnermostBrackets(const std::string &input) if (isInnermost) { innerMostPairs.emplace_back(openIndex, i); - used[openIndex] = used[i] = true; // Mark these indices as used + used[openIndex] = used[i] = + true; // Mark these indices as used } } } } std::vector ans(innerMostPairs.size()); - std::transform(innerMostPairs.begin(), innerMostPairs.end(), ans.begin(), [&input](StEdIdxPair &p) -> std::string - { - return input.substr(p.first + 1, p.second - p.first - 1); - }); + std::transform(innerMostPairs.begin(), innerMostPairs.end(), ans.begin(), + [&input](StEdIdxPair& p) -> std::string { + return input.substr(p.first + 1, p.second - p.first - 1); + }); return ans; } @@ -857,21 +837,19 @@ std::vector findInnermostBrackets(const std::string &input) * @param str * @return */ -std::string stripWhitespaces(const std::string &str) +std::string stripWhitespaces(const std::string& str) { - auto start = std::find_if(str.begin(), str.end(), [](unsigned char ch) - { + auto start = std::find_if(str.begin(), str.end(), [](unsigned char ch) { return !std::isspace(ch); }); - auto end = std::find_if(str.rbegin(), str.rend(), [](unsigned char ch) - { - return !std::isspace(ch); - }).base(); + auto end = std::find_if(str.rbegin(), str.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(); return (start < end) ? std::string(start, end) : std::string(); } -std::vector splitAndStrip(const std::string &input, char delimiter) +std::vector splitAndStrip(const std::string& input, char delimiter) { std::vector tokens; size_t start = 0, end = 0; @@ -892,18 +870,19 @@ std::vector splitAndStrip(const std::string &input, char delimiter) * @param oname * @return */ -Set cppUtil::extractClsNamesFromTemplate(const std::string &oname) +Set cppUtil::extractClsNamesFromTemplate(const std::string& oname) { // "std::array" -> A // "std::queue > >" -> A - // __gnu_cxx::__aligned_membuf >::_M_ptr() const -> A + // __gnu_cxx::__aligned_membuf >::_M_ptr() const -> + // A Set ans; std::string demangleName = llvm::demangle(oname); std::vector innermosts = findInnermostBrackets(demangleName); - for (const auto &innermost: innermosts) + for (const auto& innermost : innermosts) { - const std::vector &allstrs = splitAndStrip(innermost, ','); - for (const auto &str: allstrs) + const std::vector& allstrs = splitAndStrip(innermost, ','); + for (const auto& str : allstrs) { size_t spacePos = str.find(' '); if (spacePos != std::string::npos) @@ -925,25 +904,28 @@ Set cppUtil::extractClsNamesFromTemplate(const std::string &oname) return ans; } - /*! * class sources are functions - * where we can extract the class name (constructors/destructors or template functions) + * where we can extract the class name (constructors/destructors or template + * functions) * @param val * @return */ -bool cppUtil::isClsNameSource(const Value *val) +bool cppUtil::isClsNameSource(const Value* val) { - if (const auto *callBase = SVFUtil::dyn_cast(val)) + if (const auto* callBase = SVFUtil::dyn_cast(val)) { - const Function *foo = callBase->getCalledFunction(); + const Function* foo = callBase->getCalledFunction(); // indirect call - if(!foo) return false; - return isConstructor(foo) || isDestructor(foo) || isTemplateFunc(foo) || isDynCast(foo); + if (!foo) + return false; + return isConstructor(foo) || isDestructor(foo) || isTemplateFunc(foo) || + isDynCast(foo); } - else if (const auto *func = SVFUtil::dyn_cast(val)) + else if (const auto* func = SVFUtil::dyn_cast(val)) { - return isConstructor(func) || isDestructor(func) || isTemplateFunc(func); + return isConstructor(func) || isDestructor(func) || + isTemplateFunc(func); } return false; } @@ -954,25 +936,28 @@ bool cppUtil::isClsNameSource(const Value *val) * @param label * @return */ -bool cppUtil::matchesLabel(const std::string &foo, const std::string &label) +bool cppUtil::matchesLabel(const std::string& foo, const std::string& label) { return foo.compare(0, label.size(), label) == 0; } /*! * whether foo is a cpp template function - * TODO: we only consider limited label for now (see the very beginning of CppUtil.cpp) + * TODO: we only consider limited label for now (see the very beginning of + * CppUtil.cpp) * @param foo * @return */ -bool cppUtil::isTemplateFunc(const Function *foo) +bool cppUtil::isTemplateFunc(const Function* foo) { - const std::string &name = foo->getName().str(); - bool matchedLabel = matchesLabel(name, znstLabel) || matchesLabel(name, znkstLabel) || + const std::string& name = foo->getName().str(); + bool matchedLabel = matchesLabel(name, znstLabel) || + matchesLabel(name, znkstLabel) || matchesLabel(name, znkLabel); // we exclude "_ZNK6cArray3dupEv" -> cArray::dup() const - const std::string &demangledName = llvm::demangle(name); - return matchedLabel && demangledName.find('<') != std::string::npos && demangledName.find('>') != std::string::npos; + const std::string& demangledName = llvm::demangle(name); + return matchedLabel && demangledName.find('<') != std::string::npos && + demangledName.find('>') != std::string::npos; } /*! @@ -980,7 +965,7 @@ bool cppUtil::isTemplateFunc(const Function *foo) * @param foo * @return */ -bool cppUtil::isDynCast(const Function *foo) +bool cppUtil::isDynCast(const Function* foo) { return foo->getName().str() == dyncast; } @@ -992,23 +977,311 @@ bool cppUtil::isDynCast(const Function *foo) */ std::string cppUtil::extractClsNameFromDynCast(const CallBase* callBase) { - Value *tgtCast = callBase->getArgOperand(2); - const std::string &valueStr = LLVMUtil::dumpValue(tgtCast); + Value* tgtCast = callBase->getArgOperand(2); + const std::string& valueStr = LLVMUtil::dumpValue(tgtCast); u32_t leftPos = valueStr.find(ztilabel); - assert(leftPos != (u32_t) std::string::npos && "does not find ZTI for dyncast?"); + assert(leftPos != (u32_t)std::string::npos && + "does not find ZTI for dyncast?"); u32_t rightPos = leftPos; - while (rightPos < valueStr.size() && valueStr[rightPos] != ' ') rightPos++; - const std::string &substr = valueStr.substr(leftPos, rightPos - leftPos); + while (rightPos < valueStr.size() && valueStr[rightPos] != ' ') + rightPos++; + const std::string& substr = valueStr.substr(leftPos, rightPos - leftPos); std::string demangleName = llvm::demangle(substr); - const std::string &realName = demangleName.substr(ztiprefix.size(), - demangleName.size() - ztiprefix.size()); + const std::string& realName = demangleName.substr( + ztiprefix.size(), demangleName.size() - ztiprefix.size()); assert(realName != "" && "real name for dyncast empty?"); return realName; } -const Type *cppUtil::cppClsNameToType(const std::string &className) +const Type* cppUtil::cppClsNameToType(const std::string& className) +{ + StructType* classTy = StructType::getTypeByName( + LLVMModuleSet::getLLVMModuleSet()->getContext(), clsName + className); + return classTy ? classTy + : LLVMModuleSet::getLLVMModuleSet() + ->getTypeInference() + ->ptrType(); +} + +namespace SVF +{ +namespace cppUtil +{ + +CXXABI* getCXXABI(const Module* M) +{ + if (M) + { + llvm::Triple triple(M->getTargetTriple()); + std::string tripleStr = triple.str(); + if (tripleStr.find("msvc") != std::string::npos || + tripleStr.find("MSVC") != std::string::npos) + { + static MSVCABI msvcabi; + return &msvcabi; + } + } + static ItaniumABI itaniumabi; + return &itaniumabi; +} + +CXXABI* getCXXABI(const Value* val) +{ + if (val) + { + if (const GlobalValue* GV = SVFUtil::dyn_cast(val)) + { + return getCXXABI(GV->getParent()); + } + if (const Instruction* I = SVFUtil::dyn_cast(val)) + { + return getCXXABI(I->getFunction()->getParent()); + } + if (const Argument* Arg = SVFUtil::dyn_cast(val)) + { + return getCXXABI(Arg->getParent()->getParent()); + } + } + return getCXXABI(); +} + +CXXABI* getCXXABI() +{ + if (LLVMModuleSet::getLLVMModuleSet() && + !LLVMModuleSet::getLLVMModuleSet()->empty()) + { + return getCXXABI( + LLVMModuleSet::getLLVMModuleSet()->getMainLLVMModule()); + } + static ItaniumABI itaniumabi; + return &itaniumabi; +} + +bool ItaniumABI::isVtable(const std::string& name) +{ + return name.compare(0, vtblLabelBeforeDemangle.size(), + vtblLabelBeforeDemangle) == 0; +} + +bool ItaniumABI::isTypeInfo(const std::string& name) +{ + return name.compare(0, ztilabel.size(), ztilabel) == 0; +} + +bool ItaniumABI::isConstructor(const std::string& name) +{ + if (name.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0) + { + return false; + } + cppUtil::DemangledName dname = demangle(name); + if (dname.className.size() == 0) + { + return false; + } + stripBracketsAndNamespace(dname); + return dname.className.size() > 0 && dname.className == dname.funcName; +} + +bool ItaniumABI::isDestructor(const std::string& name) +{ + if (name.compare(0, vfunPreLabel.size(), vfunPreLabel) != 0) + { + return false; + } + cppUtil::DemangledName dname = demangle(name); + if (dname.className.size() == 0) + { + return false; + } + stripBracketsAndNamespace(dname); + return (dname.className.size() > 0 && dname.funcName.size() > 0 && + dname.className.size() + 1 == dname.funcName.size() && + dname.funcName.compare(0, 1, "~") == 0 && + dname.className.compare(dname.funcName.substr(1)) == 0); +} + +std::string ItaniumABI::extractClassName(const std::string& name) +{ + std::string className = ""; + s32_t status; + char* realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); + if (realname != nullptr) + { + std::string realnameStr = std::string(realname); + if (realnameStr.compare(0, vtblLabelAfterDemangle.size(), + vtblLabelAfterDemangle) == 0) + { + className = realnameStr.substr(vtblLabelAfterDemangle.size()); + } + std::free(realname); + } + return className; +} + +DemangledName ItaniumABI::demangle(const std::string& name) +{ + struct cppUtil::DemangledName dname; + dname.isThunkFunc = false; + + s32_t status; + char* realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status); + if (realname == nullptr) + { + dname.className = ""; + dname.funcName = ""; + } + else + { + std::string realnameStr = std::string(realname); + std::string beforeParenthesis = getBeforeParenthesis(realnameStr); + if (beforeParenthesis.find("::") == std::string::npos || + isOperOverload(beforeParenthesis)) + { + dname.className = ""; + dname.funcName = ""; + } + else + { + std::string beforeBracket = getBeforeBrackets(beforeParenthesis); + size_t colon = beforeBracket.rfind("::"); + if (colon == std::string::npos) + { + dname.className = ""; + dname.funcName = ""; + } + else + { + dname.className = beforeParenthesis.substr(0, colon); + dname.funcName = beforeParenthesis.substr(colon + 2); + } + } + std::free(realname); + } + + handleThunkFunction(dname); + + return dname; +} + +bool MSVCABI::isVtable(const std::string& name) +{ + return name.compare(0, 4, "??_7") == 0 || name.compare(0, 4, "??_8") == 0; +} + +bool MSVCABI::isTypeInfo(const std::string& name) +{ + return name.compare(0, 4, "??_R") == 0; +} + +bool MSVCABI::isConstructor(const std::string& name) +{ + return name.compare(0, 3, "??0") == 0; +} + +bool MSVCABI::isDestructor(const std::string& name) +{ + return name.compare(0, 3, "??1") == 0; +} + +std::string MSVCABI::extractClassName(const std::string& name) { - StructType *classTy = StructType::getTypeByName(LLVMModuleSet::getLLVMModuleSet()->getContext(), - clsName + className); - return classTy ? classTy : LLVMModuleSet::getLLVMModuleSet()->getTypeInference()->ptrType(); + std::string className = ""; + std::string realnameStr = llvm::demangle(name); + size_t pos = realnameStr.rfind("::`vftable'"); + if (pos == std::string::npos) + { + pos = realnameStr.rfind("::`vbtable'"); + } + if (pos != std::string::npos) + { + className = realnameStr.substr(0, pos); + if (className.compare(0, 6, "const ") == 0) + { + className = className.substr(6); + } + } + return className; } + +DemangledName MSVCABI::demangle(const std::string& name) +{ + struct DemangledName dname; + dname.isThunkFunc = false; + + std::string realnameStr = llvm::demangle(name); + if (realnameStr == name) + { + dname.className = ""; + dname.funcName = ""; + return dname; + } + + if (realnameStr.find("[thunk]") != std::string::npos || + realnameStr.find("`vcall'") != std::string::npos || + realnameStr.find("`adjustor'") != std::string::npos) + { + dname.isThunkFunc = true; + } + + std::string beforeParenthesis = getBeforeParenthesis(realnameStr); + if (beforeParenthesis.find("::") == std::string::npos || + isOperOverload(beforeParenthesis)) + { + dname.className = ""; + dname.funcName = ""; + } + else + { + std::string beforeBracket = getBeforeBrackets(beforeParenthesis); + size_t colon = beforeBracket.rfind("::"); + if (colon == std::string::npos) + { + dname.className = ""; + dname.funcName = ""; + } + else + { + std::string classNamePart = beforeParenthesis.substr(0, colon); + dname.funcName = beforeParenthesis.substr(colon + 2); + + int i = classNamePart.size() - 1; + int bracketDepth = 0; + while (i >= 0) + { + char c = classNamePart[i]; + if (c == '>') + { + bracketDepth++; + } + else if (c == '<') + { + bracketDepth--; + } + + if (bracketDepth > 0) + { + i--; + } + else + { + if (std::isalnum(c) || c == '_' || c == ':' || c == '<' || + c == '>') + { + i--; + } + else + { + break; + } + } + } + dname.className = classNamePart.substr(i + 1); + } + } + + return dname; +} + +} // namespace cppUtil +} // namespace SVF diff --git a/svf-llvm/lib/LLVMUtil.cpp b/svf-llvm/lib/LLVMUtil.cpp index d12a7b9735..d12473ebbb 100644 --- a/svf-llvm/lib/LLVMUtil.cpp +++ b/svf-llvm/lib/LLVMUtil.cpp @@ -28,13 +28,12 @@ */ #include "SVF-LLVM/LLVMUtil.h" +#include "SVF-LLVM/LLVMModule.h" #include "SVFIR/ObjTypeInfo.h" #include "SVFIR/SVFType.h" -#include #include #include -#include "SVF-LLVM/LLVMModule.h" - +#include using namespace SVF; @@ -58,9 +57,10 @@ const Function* LLVMUtil::getProgFunction(const std::string& funName) * 3) stack * 4) heap */ -bool LLVMUtil::isObject(const Value* ref) +bool LLVMUtil::isObject(const Value* ref) { - if (SVFUtil::isa(ref) && isHeapAllocExtCallViaRet(SVFUtil::cast(ref))) + if (SVFUtil::isa(ref) && + isHeapAllocExtCallViaRet(SVFUtil::cast(ref))) return true; if (SVFUtil::isa(ref)) return true; @@ -73,28 +73,31 @@ bool LLVMUtil::isObject(const Value* ref) /*! * Return reachable bbs from function entry */ -void LLVMUtil::getFunReachableBBs (const Function* fun, std::vector &reachableBBs) +void LLVMUtil::getFunReachableBBs( + const Function* fun, std::vector& reachableBBs) { - assert(!LLVMUtil::isExtCall(fun) && "The calling function cannot be an external function."); - //initial DominatorTree + assert(!LLVMUtil::isExtCall(fun) && + "The calling function cannot be an external function."); + // initial DominatorTree DominatorTree& dt = LLVMModuleSet::getLLVMModuleSet()->getDomTree(fun); Set visited; std::vector bbVec; bbVec.push_back(&fun->getEntryBlock()); - while(!bbVec.empty()) + while (!bbVec.empty()) { const BasicBlock* bb = bbVec.back(); bbVec.pop_back(); - const SVFBasicBlock* svfbb = LLVMModuleSet::getLLVMModuleSet()->getSVFBasicBlock(bb); + const SVFBasicBlock* svfbb = + LLVMModuleSet::getLLVMModuleSet()->getSVFBasicBlock(bb); reachableBBs.push_back(svfbb); - if(DomTreeNode *dtNode = dt.getNode(const_cast(bb))) + if (DomTreeNode* dtNode = dt.getNode(const_cast(bb))) { for (DomTreeNode::iterator DI = dtNode->begin(), DE = dtNode->end(); - DI != DE; ++DI) + DI != DE; ++DI) { const BasicBlock* succbb = (*DI)->getBlock(); - if(visited.find(succbb)==visited.end()) + if (visited.find(succbb) == visited.end()) visited.insert(succbb); else continue; @@ -110,18 +113,19 @@ void LLVMUtil::getFunReachableBBs (const Function* fun, std::vectorbegin(), eit = bb->end(); - it != eit; ++it) + it != eit; ++it) { - if(SVFUtil::isa(*it)) + if (SVFUtil::isa(*it)) return true; } return false; } /*! - * Return true if the function has a return instruction reachable from function entry + * Return true if the function has a return instruction reachable from function + * entry */ -bool LLVMUtil::functionDoesNotRet(const Function* fun) +bool LLVMUtil::functionDoesNotRet(const Function* fun) { if (LLVMUtil::isExtCall(fun)) { @@ -130,7 +134,7 @@ bool LLVMUtil::functionDoesNotRet(const Function* fun) std::vector bbVec; Set visited; bbVec.push_back(&fun->getEntryBlock()); - while(!bbVec.empty()) + while (!bbVec.empty()) { const BasicBlock* bb = bbVec.back(); bbVec.pop_back(); @@ -140,10 +144,10 @@ bool LLVMUtil::functionDoesNotRet(const Function* fun) } for (succ_const_iterator sit = succ_begin(bb), esit = succ_end(bb); - sit != esit; ++sit) + sit != esit; ++sit) { const BasicBlock* succbb = (*sit); - if(visited.find(succbb)==visited.end()) + if (visited.find(succbb) == visited.end()) visited.insert(succbb); else continue; @@ -156,13 +160,14 @@ bool LLVMUtil::functionDoesNotRet(const Function* fun) /*! * Return true if this is a function without any possible caller */ -bool LLVMUtil::isUncalledFunction (const Function* fun) +bool LLVMUtil::isUncalledFunction(const Function* fun) { - if(fun->hasAddressTaken()) + if (fun->hasAddressTaken()) return false; if (LLVMUtil::isProgEntryFunction(fun)) return false; - for (Value::const_user_iterator i = fun->user_begin(), e = fun->user_end(); i != e; ++i) + for (Value::const_user_iterator i = fun->user_begin(), e = fun->user_end(); + i != e; ++i) { if (LLVMUtil::isCallSite(*i)) return false; @@ -171,18 +176,19 @@ bool LLVMUtil::isUncalledFunction (const Function* fun) } /*! - * Return true if this is a value in a dead function (function without any caller) + * Return true if this is a value in a dead function (function without any + * caller) */ -bool LLVMUtil::isPtrInUncalledFunction (const Value* value) +bool LLVMUtil::isPtrInUncalledFunction(const Value* value) { - if(const Instruction* inst = SVFUtil::dyn_cast(value)) + if (const Instruction* inst = SVFUtil::dyn_cast(value)) { - if(isUncalledFunction(inst->getParent()->getParent())) + if (isUncalledFunction(inst->getParent()->getParent())) return true; } - else if(const Argument* arg = SVFUtil::dyn_cast(value)) + else if (const Argument* arg = SVFUtil::dyn_cast(value)) { - if(isUncalledFunction(arg->getParent())) + if (isUncalledFunction(arg->getParent())) return true; } return false; @@ -221,7 +227,7 @@ const Value* LLVMUtil::stripConstantCasts(const Value* val) { if (SVFUtil::isa(val) || isInt2PtrConstantExpr(val)) return val; - else if (const ConstantExpr *CE = SVFUtil::dyn_cast(val)) + else if (const ConstantExpr* CE = SVFUtil::dyn_cast(val)) { if (Instruction::isCast(CE->getOpcode())) return stripConstantCasts(CE->getOperand(0)); @@ -248,17 +254,17 @@ void LLVMUtil::viewCFGOnly(const Function* fun) /*! * Strip all casts */ -const Value* LLVMUtil::stripAllCasts(const Value* val) +const Value* LLVMUtil::stripAllCasts(const Value* val) { while (true) { - if (const CastInst *ci = SVFUtil::dyn_cast(val)) + if (const CastInst* ci = SVFUtil::dyn_cast(val)) { val = ci->getOperand(0); } - else if (const ConstantExpr *ce = SVFUtil::dyn_cast(val)) + else if (const ConstantExpr* ce = SVFUtil::dyn_cast(val)) { - if(ce->isCast()) + if (ce->isCast()) val = ce->getOperand(0); else return val; @@ -272,16 +278,19 @@ const Value* LLVMUtil::stripAllCasts(const Value* val) } /* - * Get the first dominated cast instruction for heap allocations since they typically come from void* (i8*) - * for example, %4 = call align 16 i8* @malloc(i64 10); %5 = bitcast i8* %4 to i32* - * return %5 whose type is i32* but not %4 whose type is i8* + * Get the first dominated cast instruction for heap allocations since they + * typically come from void* (i8*) for example, %4 = call align 16 i8* + * @malloc(i64 10); %5 = bitcast i8* %4 to i32* return %5 whose type is i32* but + * not %4 whose type is i8* */ const Value* LLVMUtil::getFirstUseViaCastInst(const Value* val) { - assert(SVFUtil::isa(val->getType()) && "this value should be a pointer type!"); - /// If type is void* (i8*) and val is immediately used at a bitcast instruction - const Value *latestUse = nullptr; - for (const auto &it : val->uses()) + assert(SVFUtil::isa(val->getType()) && + "this value should be a pointer type!"); + /// If type is void* (i8*) and val is immediately used at a bitcast + /// instruction + const Value* latestUse = nullptr; + for (const auto& it : val->uses()) { if (SVFUtil::isa(it.getUser())) latestUse = it.getUser(); @@ -300,10 +309,16 @@ u32_t LLVMUtil::getNumOfElements(const Type* ety) u32_t numOfFields = 1; if (SVFUtil::isa(ety)) { - if(Options::ModelArrays()) - return LLVMModuleSet::getLLVMModuleSet()->getSVFType(ety)->getTypeInfo()->getNumOfFlattenElements(); + if (Options::ModelArrays()) + return LLVMModuleSet::getLLVMModuleSet() + ->getSVFType(ety) + ->getTypeInfo() + ->getNumOfFlattenElements(); else - return LLVMModuleSet::getLLVMModuleSet()->getSVFType(ety)->getTypeInfo()->getNumOfFlattenFields(); + return LLVMModuleSet::getLLVMModuleSet() + ->getSVFType(ety) + ->getTypeInfo() + ->getNumOfFlattenFields(); } return numOfFields; } @@ -313,13 +328,14 @@ u32_t LLVMUtil::getNumOfElements(const Type* ety) * llvm::parseIRFile (lib/IRReader/IRReader.cpp) * llvm::parseIR (lib/IRReader/IRReader.cpp) */ -bool LLVMUtil::isIRFile(const std::string &filename) +bool LLVMUtil::isIRFile(const std::string& filename) { llvm::LLVMContext context; llvm::SMDiagnostic err; // Parse the input LLVM IR file into a module - std::unique_ptr module = llvm::parseIRFile(filename, err, context); + std::unique_ptr module = + llvm::parseIRFile(filename, err, context); // Check if the parsing succeeded if (!module) @@ -331,11 +347,11 @@ bool LLVMUtil::isIRFile(const std::string &filename) return true; // It is an LLVM IR file } - /// Get the names of all modules into a vector /// And process arguments -void LLVMUtil::processArguments(int argc, char **argv, int &arg_num, char **arg_value, - std::vector &moduleNameVec) +void LLVMUtil::processArguments(int argc, char** argv, int& arg_num, + char** arg_value, + std::vector& moduleNameVec) { bool first_ir_file = true; for (int i = 0; i < argc; ++i) @@ -343,8 +359,8 @@ void LLVMUtil::processArguments(int argc, char **argv, int &arg_num, char **arg_ std::string argument(argv[i]); if (LLVMUtil::isIRFile(argument)) { - if (find(moduleNameVec.begin(), moduleNameVec.end(), argument) - == moduleNameVec.end()) + if (find(moduleNameVec.begin(), moduleNameVec.end(), argument) == + moduleNameVec.end()) moduleNameVec.push_back(argument); if (first_ir_file) { @@ -362,54 +378,55 @@ void LLVMUtil::processArguments(int argc, char **argv, int &arg_num, char **arg_ } /// Get all called funcions in a parent function -std::vector LLVMUtil::getCalledFunctions(const Function *F) +std::vector LLVMUtil::getCalledFunctions(const Function* F) { - std::vector calledFunctions; - for (const Instruction &I : instructions(F)) + std::vector calledFunctions; + for (const Instruction& I : instructions(F)) { - if (const CallBase *callInst = SVFUtil::dyn_cast(&I)) + if (const CallBase* callInst = SVFUtil::dyn_cast(&I)) { - Function *calledFunction = callInst->getCalledFunction(); + Function* calledFunction = callInst->getCalledFunction(); if (calledFunction) { calledFunctions.push_back(calledFunction); - std::vector nestedCalledFunctions = getCalledFunctions(calledFunction); - calledFunctions.insert(calledFunctions.end(), nestedCalledFunctions.begin(), nestedCalledFunctions.end()); + std::vector nestedCalledFunctions = + getCalledFunctions(calledFunction); + calledFunctions.insert(calledFunctions.end(), + nestedCalledFunctions.begin(), + nestedCalledFunctions.end()); } } } return calledFunctions; } - bool LLVMUtil::isExtCall(const Function* fun) { return fun && LLVMModuleSet::getLLVMModuleSet()->is_ext(fun); } -bool LLVMUtil::isMemcpyExtFun(const Function *fun) +bool LLVMUtil::isMemcpyExtFun(const Function* fun) { return fun && LLVMModuleSet::getLLVMModuleSet()->is_memcpy(fun); } - bool LLVMUtil::isMemsetExtFun(const Function* fun) { return fun && LLVMModuleSet::getLLVMModuleSet()->is_memset(fun); } - u32_t LLVMUtil::getHeapAllocHoldingArgPosition(const Function* fun) { return LLVMModuleSet::getLLVMModuleSet()->get_alloc_arg_pos(fun); } - std::string LLVMUtil::restoreFuncName(std::string funcName) { assert(!funcName.empty() && "Empty function name"); - // Some function names change due to mangling, such as "fopen" to "\01_fopen" on macOS. - // Since C function names cannot include '.', change the function name from llvm.memcpy.p0i8.p0i8.i64 to llvm_memcpy_p0i8_p0i8_i64." + // Some function names change due to mangling, such as "fopen" to + // "\01_fopen" on macOS. Since C function names cannot include '.', change + // the function name from llvm.memcpy.p0i8.p0i8.i64 to + // llvm_memcpy_p0i8_p0i8_i64." bool hasSpecialPrefix = funcName[0] == '\01'; bool hasDot = funcName.find('.') != std::string::npos; @@ -433,7 +450,6 @@ std::string LLVMUtil::restoreFuncName(std::string funcName) return funcName; } - const FunObjVar* LLVMUtil::getFunObjVar(const std::string& name) { return LLVMModuleSet::getLLVMModuleSet()->getFunObjVar(name); @@ -451,9 +467,10 @@ const Value* LLVMUtil::getGlobalRep(const Value* val) /*! * Get the meta data (line number and file name) info of a LLVM value */ -const std::string LLVMUtil::getSourceLoc(const Value* val ) +const std::string LLVMUtil::getSourceLoc(const Value* val) { - if(val==nullptr) return "{ empty val }"; + if (val == nullptr) + return "{ empty val }"; std::string str; std::stringstream rawstr(str); @@ -464,79 +481,102 @@ const std::string LLVMUtil::getSourceLoc(const Value* val ) if (SVFUtil::isa(inst)) { #if LLVM_VERSION_MAJOR >= 20 - for (llvm::DbgVariableRecord *DVR : llvm::findDVRDeclares(const_cast(inst))) + for (llvm::DbgVariableRecord* DVR : + llvm::findDVRDeclares(const_cast(inst))) { - llvm::DIVariable *DIVar = DVR->getVariable(); - rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" << DIVar->getFilename().str() << "\""; + llvm::DIVariable* DIVar = DVR->getVariable(); + rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" + << DIVar->getFilename().str() << "\""; break; } +#elif LLVM_VERSION_MAJOR > 16 + for (llvm::DbgInfoIntrinsic* DII : + llvm::findDbgDeclares(const_cast(inst))) + { + if (llvm::DbgDeclareInst* DDI = + SVFUtil::dyn_cast(DII)) + { + llvm::DIVariable* DIVar = + SVFUtil::cast(DDI->getVariable()); + rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" + << DIVar->getFilename().str() << "\""; + break; + } + } #else -#if LLVM_VERSION_MAJOR > 16 - for (llvm::DbgInfoIntrinsic *DII : llvm::findDbgDeclares(const_cast(inst))) -#else - for (llvm::DbgInfoIntrinsic *DII : FindDbgDeclareUses(const_cast(inst))) -#endif + for (llvm::DbgInfoIntrinsic* DII : + FindDbgDeclareUses(const_cast(inst))) { - if (llvm::DbgDeclareInst *DDI = SVFUtil::dyn_cast(DII)) + if (llvm::DbgDeclareInst* DDI = + SVFUtil::dyn_cast(DII)) { - llvm::DIVariable *DIVar = SVFUtil::cast(DDI->getVariable()); - rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" << DIVar->getFilename().str() << "\""; + llvm::DIVariable* DIVar = + SVFUtil::cast(DDI->getVariable()); + rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" + << DIVar->getFilename().str() << "\""; break; } } #endif } - else if (MDNode *N = inst->getMetadata("dbg")) // Here I is an LLVM instruction + else if (MDNode* N = + inst->getMetadata("dbg")) // Here I is an LLVM instruction { - llvm::DILocation* Loc = SVFUtil::cast(N); // DILocation is in DebugInfo.h + llvm::DILocation* Loc = SVFUtil::cast( + N); // DILocation is in DebugInfo.h unsigned Line = Loc->getLine(); unsigned Column = Loc->getColumn(); std::string File = Loc->getFilename().str(); - //StringRef Dir = Loc.getDirectory(); - if(File.empty() || Line == 0) + // StringRef Dir = Loc.getDirectory(); + if (File.empty() || Line == 0) { auto inlineLoc = Loc->getInlinedAt(); - if(inlineLoc) + if (inlineLoc) { Line = inlineLoc->getLine(); Column = inlineLoc->getColumn(); File = inlineLoc->getFilename().str(); } } - rawstr << "\"ln\": " << Line << ", \"cl\": " << Column << ", \"fl\": \"" << File << "\""; + rawstr << "\"ln\": " << Line << ", \"cl\": " << Column + << ", \"fl\": \"" << File << "\""; } } else if (const Argument* argument = SVFUtil::dyn_cast(val)) { - if (argument->getArgNo()%10 == 1) + if (argument->getArgNo() % 10 == 1) rawstr << argument->getArgNo() << "st"; - else if (argument->getArgNo()%10 == 2) + else if (argument->getArgNo() % 10 == 2) rawstr << argument->getArgNo() << "nd"; - else if (argument->getArgNo()%10 == 3) + else if (argument->getArgNo() % 10 == 3) rawstr << argument->getArgNo() << "rd"; else rawstr << argument->getArgNo() << "th"; rawstr << " arg " << argument->getParent()->getName().str() << " " << getSourceLocOfFunction(argument->getParent()); } - else if (const GlobalVariable* gvar = SVFUtil::dyn_cast(val)) + else if (const GlobalVariable* gvar = + SVFUtil::dyn_cast(val)) { rawstr << "Glob "; - NamedMDNode* CU_Nodes = gvar->getParent()->getNamedMetadata("llvm.dbg.cu"); - if(CU_Nodes) + NamedMDNode* CU_Nodes = + gvar->getParent()->getNamedMetadata("llvm.dbg.cu"); + if (CU_Nodes) { for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { - llvm::DICompileUnit *CUNode = SVFUtil::cast(CU_Nodes->getOperand(i)); - for (llvm::DIGlobalVariableExpression *GV : CUNode->getGlobalVariables()) + llvm::DICompileUnit* CUNode = + SVFUtil::cast(CU_Nodes->getOperand(i)); + for (llvm::DIGlobalVariableExpression* GV : + CUNode->getGlobalVariables()) { - llvm::DIGlobalVariable * DGV = GV->getVariable(); + llvm::DIGlobalVariable* DGV = GV->getVariable(); - if(DGV->getName() == gvar->getName()) + if (DGV->getName() == gvar->getName()) { - rawstr << "\"ln\": " << DGV->getLine() << ", \"fl\": \"" << DGV->getFilename().str() << "\""; + rawstr << "\"ln\": " << DGV->getLine() << ", \"fl\": \"" + << DGV->getFilename().str() << "\""; } - } } } @@ -550,7 +590,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val ) auto nonPhiIt = bb->getFirstNonPHIIt(); rawstr << "\"basic block\": " << bb->getName().str() << ", \"location\": " << getSourceLoc(nonPhiIt != bb->end() ? &*nonPhiIt : nullptr); } - else if(LLVMUtil::isConstDataOrAggData(val)) + else if (LLVMUtil::isConstDataOrAggData(val)) { rawstr << "constant data"; } @@ -560,12 +600,11 @@ const std::string LLVMUtil::getSourceLoc(const Value* val ) } rawstr << " }"; - if(rawstr.str()=="{ }") + if (rawstr.str() == "{ }") return ""; return rawstr.str(); } - /*! * Get source code line number of a function according to debug info */ @@ -577,16 +616,18 @@ const std::string LLVMUtil::getSourceLocOfFunction(const Function* F) * https://reviews.llvm.org/D18074?id=50385 * looks like the relevant */ - if (llvm::DISubprogram *SP = F->getSubprogram()) + if (llvm::DISubprogram* SP = F->getSubprogram()) { if (SP->describes(F)) - rawstr << "\"ln\": " << SP->getLine() << ", \"file\": \"" << SP->getFilename().str() << "\""; + rawstr << "\"ln\": " << SP->getLine() << ", \"file\": \"" + << SP->getFilename().str() << "\""; } return rawstr.str(); } /// Get the next instructions following control flow -void LLVMUtil::getNextInsts(const Instruction* curInst, std::vector& instList) +void LLVMUtil::getNextInsts(const Instruction* curInst, + std::vector& instList) { if (!curInst->isTerminator()) { @@ -598,9 +639,10 @@ void LLVMUtil::getNextInsts(const Instruction* curInst, std::vectorgetParent(); + const BasicBlock* BB = curInst->getParent(); // Visit all successors of BB in the CFG - for (succ_const_iterator it = succ_begin(BB), ie = succ_end(BB); it != ie; ++it) + for (succ_const_iterator it = succ_begin(BB), ie = succ_end(BB); + it != ie; ++it) { const Instruction* nextInst = &((*it)->front()); if (LLVMUtil::isIntrinsicInst(nextInst)) @@ -611,8 +653,6 @@ void LLVMUtil::getNextInsts(const Instruction* curInst, std::vector(inst)) { const Function* fun = call->getCalledFunction(); - return fun && isPtrTy && - (pSet->is_alloc(fun) || - pSet->is_realloc(fun)); + return fun && isPtrTy && (pSet->is_alloc(fun) || pSet->is_realloc(fun)); } else return false; @@ -666,8 +704,7 @@ bool LLVMUtil::isHeapAllocExtCallViaArg(const Instruction* inst) if (const CallBase* call = SVFUtil::dyn_cast(inst)) { const Function* fun = call->getCalledFunction(); - return fun && - LLVMModuleSet::getLLVMModuleSet()->is_arg_alloc(fun); + return fun && LLVMModuleSet::getLLVMModuleSet()->is_arg_alloc(fun); } else { @@ -675,15 +712,14 @@ bool LLVMUtil::isHeapAllocExtCallViaArg(const Instruction* inst) } } -bool LLVMUtil::isStackAllocExtCallViaRet(const Instruction *inst) +bool LLVMUtil::isStackAllocExtCallViaRet(const Instruction* inst) { LLVMModuleSet* pSet = LLVMModuleSet::getLLVMModuleSet(); bool isPtrTy = inst->getType()->isPointerTy(); if (const CallBase* call = SVFUtil::dyn_cast(inst)) { const Function* fun = call->getCalledFunction(); - return fun && isPtrTy && - pSet->is_alloc_stack_ret(fun); + return fun && isPtrTy && pSet->is_alloc_stack_ret(fun); } else return false; @@ -700,10 +736,12 @@ bool LLVMUtil::isHeapObj(const Value* val) // Check if the value is an argument in the program entry function if (ArgInProgEntryFunction(val)) { - // Return true if the value does not have a first use via cast instruction + // Return true if the value does not have a first use via cast + // instruction return !getFirstUseViaCastInst(val); } - // Check if the value is an instruction and if it is a heap allocation external call + // Check if the value is an instruction and if it is a heap allocation + // external call else if (SVFUtil::isa(val) && LLVMUtil::isHeapAllocExtCall(SVFUtil::cast(val))) { @@ -723,7 +761,8 @@ bool LLVMUtil::isStackObj(const Value* val) { return true; } - // Check if the value is an instruction and if it is a stack allocation external call + // Check if the value is an instruction and if it is a stack allocation + // external call else if (SVFUtil::isa(val) && LLVMUtil::isStackAllocExtCall(SVFUtil::cast(val))) { @@ -737,7 +776,7 @@ bool LLVMUtil::isNonInstricCallSite(const Instruction* inst) { bool res = false; - if(isIntrinsicInst(inst)) + if (isIntrinsicInst(inst)) res = false; else res = isCallSite(inst); @@ -747,18 +786,16 @@ bool LLVMUtil::isNonInstricCallSite(const Instruction* inst) namespace SVF { - const std::string SVFValue::valueOnlyToString() const { std::string str; llvm::raw_string_ostream rawstr(str); - assert( - !SVFUtil::isa(this) && !SVFUtil::isa(this) && - !SVFUtil::isa(this) &&!SVFUtil::isa(this) && - !SVFUtil::isa(this) && - "invalid value, refer to their toString method"); - auto llvmVal = - LLVMModuleSet::getLLVMModuleSet()->getLLVMValue(this); + assert(!SVFUtil::isa(this) && !SVFUtil::isa(this) && + !SVFUtil::isa(this) && + !SVFUtil::isa(this) && + !SVFUtil::isa(this) && + "invalid value, refer to their toString method"); + auto llvmVal = LLVMModuleSet::getLLVMModuleSet()->getLLVMValue(this); if (llvmVal) rawstr << " " << *llvmVal << " "; else @@ -770,6 +807,5 @@ const std::string SVFValue::valueOnlyToString() const const bool SVFValue::hasLLVMValue() const { return LLVMModuleSet::getLLVMModuleSet()->hasLLVMValue(this); - } -}// namespace SVF +} // namespace SVF diff --git a/svf-llvm/lib/extapi.c b/svf-llvm/lib/extapi.c index cf0f39bd56..31fcd1b986 100644 --- a/svf-llvm/lib/extapi.c +++ b/svf-llvm/lib/extapi.c @@ -26,6 +26,48 @@ void *malloc(unsigned long size) return NULL; } +__attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:Arg2"))) +void *HeapAlloc(void *hHeap, unsigned int dwFlags, unsigned long dwBytes) +{ + return NULL; +} + +__attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:Arg1"))) +void *LocalAlloc(unsigned int uFlags, unsigned long uBytes) +{ + return NULL; +} + +__attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:Arg1"))) +void *GlobalAlloc(unsigned int uFlags, unsigned long uBytes) +{ + return NULL; +} + +__attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:Arg0"))) +void *_malloc_dbg(unsigned long size, int blockType, const char *filename, int linenumber) +{ + return NULL; +} + +__attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:Arg0"))) +void *_aligned_malloc(unsigned long size, unsigned long alignment) +{ + return NULL; +} + +__attribute__((annotate("REALLOC_HEAP_RET"), annotate("AllocSize:Arg3"))) +void *HeapReAlloc(void *hHeap, unsigned int dwFlags, void *lpMem, unsigned long dwBytes) +{ + return NULL; +} + +__attribute__((annotate("REALLOC_HEAP_RET"), annotate("AllocSize:Arg1"))) +void *LocalReAlloc(void *hMem, unsigned long uBytes, unsigned int uFlags) +{ + return NULL; +} + __attribute__((annotate("ALLOC_HEAP_RET"), annotate("AllocSize:UNKNOWN"))) void *fopen(const char *voidname, const char *mode) { @@ -1153,7 +1195,7 @@ void _ZNSt8__detail15_List_node_base7_M_hookEPS0_(void *arg0, void **arg1) *arg1 = arg0; } -void* __dynamic_cast(void* source, const void* sourceTypeInfo, const void* targetTypeInfo, unsigned long castType) +void* __dynamic_cast(void* source, const void* sourceTypeInfo, const void* targetTypeInfo, ptrdiff_t castType) { return source; } diff --git a/svf-llvm/tools/AE/ae.cpp b/svf-llvm/tools/AE/ae.cpp index 06220eafdd..7aa9077f7c 100644 --- a/svf-llvm/tools/AE/ae.cpp +++ b/svf-llvm/tools/AE/ae.cpp @@ -26,30 +26,23 @@ // Author: Jiawei Wang, Xiao Cheng, Jiawei Yang, Jiawei Ren, Yulei Sui */ #include "SVF-LLVM/SVFIRBuilder.h" -#include "WPA/WPAPass.h" #include "Util/CommandLine.h" #include "Util/Options.h" #include "WPA/Andersen.h" +#include "WPA/WPAPass.h" #include "AE/Core/RelExeState.h" #include "AE/Core/RelationSolver.h" #include "AE/Svfexe/AbstractInterpretation.h" +#include using namespace SVF; using namespace SVFUtil; +static Option SYMABS("symabs", "symbolic abstraction test", false); -static Option SYMABS( - "symabs", - "symbolic abstraction test", - false -); - -static Option AETEST( - "aetest", - "abstract execution basic function test", - false -); +static Option AETEST("aetest", "abstract execution basic function test", + false); class SymblicAbstractionTest { @@ -75,7 +68,7 @@ class SymblicAbstractionTest AbstractState resRSY = rs.RSY(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( - end_time - start_time); + end_time - start_time); outs() << "running time of RSY : " << duration.count() << " microseconds\n"; return resRSY; @@ -87,7 +80,7 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( - end_time - start_time); + end_time - start_time); outs() << "running time of Bilateral: " << duration.count() << " microseconds\n"; return resBilateral; @@ -99,7 +92,7 @@ class SymblicAbstractionTest AbstractState resBS = rs.BS(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( - end_time - start_time); + end_time - start_time); outs() << "running time of BS : " << duration.count() << " microseconds\n"; return resBS; @@ -130,13 +123,16 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[0,1] 1:[1,2] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(1, 2)}}; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, + {1, IntervalValue(1, 2)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState1_2() @@ -165,13 +161,16 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[0,1] 1:[0,2] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(0, 2)}}; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, + {1, IntervalValue(0, 2)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState2_1() @@ -203,17 +202,18 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[0,10] 1:[0,10] 2:[0,0] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, - {1, IntervalValue(0, 10)}, - {2, IntervalValue(0, 0)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {1, IntervalValue(0, 10)}, + {2, IntervalValue(0, 0)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState2_2() @@ -246,17 +246,18 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[0,100] 1:[0,100] 2:[0,0] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100)}, - {1, IntervalValue(0, 100)}, - {2, IntervalValue(0, 0)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {1, IntervalValue(0, 100)}, + {2, IntervalValue(0, 0)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState2_3() @@ -289,17 +290,19 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[0,1000] 1:[0,1000] 2:[0,0] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(0, 1000)}, {1, IntervalValue(0, 1000)}, - {2, IntervalValue(0, 0)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {2, IntervalValue(0, 0)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState2_4() @@ -332,17 +335,19 @@ class SymblicAbstractionTest AbstractState resBilateral = Bilateral_time(inv, phi, rs); AbstractState resBS = BS_time(inv, phi, rs); // 0:[0,10000] 1:[0,10000] 2:[0,0] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(0, 10000)}, {1, IntervalValue(0, 10000)}, - {2, IntervalValue(0, 0)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {2, IntervalValue(0, 0)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState2_5() @@ -375,17 +380,19 @@ class SymblicAbstractionTest AbstractState resBilateral = Bilateral_time(inv, phi, rs); AbstractState resBS = BS_time(inv, phi, rs); // 0:[0,100000] 1:[0,100000] 2:[0,0] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(0, 100000)}, {1, IntervalValue(0, 100000)}, - {2, IntervalValue(0, 0)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {2, IntervalValue(0, 0)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState3_1() @@ -417,17 +424,18 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[1,10] 1:[1,10] 2:[1,1] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10)}, - {1, IntervalValue(1, 10)}, - {2, IntervalValue(1, 1)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {1, IntervalValue(1, 10)}, + {2, IntervalValue(1, 1)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState3_2() @@ -459,17 +467,19 @@ class SymblicAbstractionTest AbstractState resBilateral = rs.bilateral(inv, phi); AbstractState resBS = rs.BS(inv, phi); // 0:[1,1000] 1:[1,1000] 2:[1,1] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 1000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(1, 1000)}, {1, IntervalValue(1, 1000)}, - {2, IntervalValue(1, 1)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {2, IntervalValue(1, 1)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState3_3() @@ -501,16 +511,17 @@ class SymblicAbstractionTest AbstractState resBilateral = Bilateral_time(inv, phi, rs); AbstractState resBS = BS_time(inv, phi, rs); // 0:[1,10000] 1:[1,10000] 2:[1,1] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(1, 10000)}, {1, IntervalValue(1, 10000)}, - {2, IntervalValue(1, 1)} - }; + {2, IntervalValue(1, 1)}}; } void testRelExeState3_4() @@ -542,17 +553,19 @@ class SymblicAbstractionTest AbstractState resBilateral = Bilateral_time(inv, phi, rs); AbstractState resBS = BS_time(inv, phi, rs); // 0:[1,100000] 1:[1,100000] 2:[1,1] - assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); + assert(resRSY == resBS && resBS == resBilateral && + "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 100000)}, + AbstractState::VarToAbsValMap intendedRes = { + {0, IntervalValue(1, 100000)}, {1, IntervalValue(1, 100000)}, - {2, IntervalValue(1, 1)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {2, IntervalValue(1, 1)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testRelExeState4_1() @@ -594,10 +607,10 @@ class SymblicAbstractionTest } // ground truth AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, - {1, IntervalValue(0, 10)}, - {2, IntervalValue(0, 10)} - }; - assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + {1, IntervalValue(0, 10)}, + {2, IntervalValue(0, 10)}}; + assert(resBS.eqVarToValMap(resBS.getVarToVal(), intendedRes) && + "inconsistency occurs"); } void testsValidation() @@ -632,197 +645,417 @@ class AETest void testBinaryOpStmt() { // test division / - assert((IntervalValue(4) / IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() / IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() / IntervalValue(0)).equals(IntervalValue::bottom())); + assert((IntervalValue(4) / IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() / IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() / IntervalValue(0)) + .equals(IntervalValue::bottom())); assert((IntervalValue(4) / IntervalValue(2)).equals(IntervalValue(2))); - assert((IntervalValue(3) / IntervalValue(2)).equals(IntervalValue(1))); // - assert((IntervalValue(-3) / IntervalValue(2)).equals(IntervalValue(-1))); // - assert((IntervalValue(1, 3) / IntervalValue(2)).equals(IntervalValue(0, 1))); // - assert((IntervalValue(2, 7) / IntervalValue(2)).equals(IntervalValue(1, 3))); // - assert((IntervalValue(-3, 3) / IntervalValue(2)).equals(IntervalValue(-1, 1))); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) / IntervalValue(2)).equals(IntervalValue(-1, IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) / IntervalValue(2)).equals(IntervalValue(IntervalValue::minus_infinity(), 1))); - assert((IntervalValue(1, 3) / IntervalValue(1, 2)).equals(IntervalValue(0, 3)));// - assert((IntervalValue(-3, 3) / IntervalValue(1, 2)).equals(IntervalValue(-3, 3))); - assert((IntervalValue(2, 7) / IntervalValue(-2, 3)).equals(IntervalValue(-7, 7))); // - assert((IntervalValue(-2, 7) / IntervalValue(-2, 3)).equals(IntervalValue(-7, 7))); // - assert((IntervalValue(IntervalValue::minus_infinity(), 7) / IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) / IntervalValue(-2, 3)).equals(IntervalValue::top())); - - assert((IntervalValue(-2, 7) / IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue(-7, 7))); - assert((IntervalValue(-2, 7) / IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue(-7, 7))); - assert((IntervalValue(-6, -3) / IntervalValue(3, 9)).equals(IntervalValue(-2, 0))); - assert((IntervalValue(-6, 6) / IntervalValue(3, 9)).equals(IntervalValue(-2, 2))); + assert( + (IntervalValue(3) / IntervalValue(2)).equals(IntervalValue(1))); // + assert((IntervalValue(-3) / IntervalValue(2)) + .equals(IntervalValue(-1))); // + assert((IntervalValue(1, 3) / IntervalValue(2)) + .equals(IntervalValue(0, 1))); // + assert((IntervalValue(2, 7) / IntervalValue(2)) + .equals(IntervalValue(1, 3))); // + assert((IntervalValue(-3, 3) / IntervalValue(2)) + .equals(IntervalValue(-1, 1))); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) / + IntervalValue(2)) + .equals(IntervalValue(-1, IntervalValue::plus_infinity()))); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) / + IntervalValue(2)) + .equals(IntervalValue(IntervalValue::minus_infinity(), 1))); + assert((IntervalValue(1, 3) / IntervalValue(1, 2)) + .equals(IntervalValue(0, 3))); // + assert((IntervalValue(-3, 3) / IntervalValue(1, 2)) + .equals(IntervalValue(-3, 3))); + assert((IntervalValue(2, 7) / IntervalValue(-2, 3)) + .equals(IntervalValue(-7, 7))); // + assert((IntervalValue(-2, 7) / IntervalValue(-2, 3)) + .equals(IntervalValue(-7, 7))); // + assert((IntervalValue(IntervalValue::minus_infinity(), 7) / + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) / + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + + assert((IntervalValue(-2, 7) / + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue(-7, 7))); + assert((IntervalValue(-2, 7) / + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue(-7, 7))); + assert((IntervalValue(-6, -3) / IntervalValue(3, 9)) + .equals(IntervalValue(-2, 0))); + assert((IntervalValue(-6, 6) / IntervalValue(3, 9)) + .equals(IntervalValue(-2, 2))); // test remainder % - assert((IntervalValue(4) % IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() % IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() % IntervalValue(0)).equals(IntervalValue::top())); + assert((IntervalValue(4) % IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() % IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() % IntervalValue(0)) + .equals(IntervalValue::top())); assert((IntervalValue(4) % IntervalValue(2)).equals(IntervalValue(0))); assert((IntervalValue(3) % IntervalValue(2)).equals(IntervalValue(1))); - assert((IntervalValue(-3) % IntervalValue(2)).equals(IntervalValue(-1))); - assert((IntervalValue(1, 3) % IntervalValue(2)).equals(IntervalValue(0, 1))); - assert((IntervalValue(2, 7) % IntervalValue(2)).equals(IntervalValue(0, 1))); - assert((IntervalValue(-3, 3) % IntervalValue(2)).equals(IntervalValue(-1, 1))); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) % IntervalValue(2)).equals(IntervalValue(-1, 1))); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) % IntervalValue(2)).equals(IntervalValue(-1, 1))); - assert((IntervalValue(1, 3) % IntervalValue(1, 2)).equals(IntervalValue(0, 1))); - assert((IntervalValue(-3, 3) % IntervalValue(1, 2)).equals(IntervalValue(-1, 1))); - assert((IntervalValue(2, 7) % IntervalValue(-2, 3)).equals(IntervalValue::top())); // - assert((IntervalValue(-2, 7) % IntervalValue(-2, 3)).equals(IntervalValue::top())); // - assert((IntervalValue(IntervalValue::minus_infinity(), 7) % IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) % IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) % IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) % IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue::top())); - assert((IntervalValue(-6, -3) % IntervalValue(3, 9)).equals(IntervalValue(-6, 0))); - assert((IntervalValue(-6, 6) % IntervalValue(3, 9)).equals(IntervalValue(-6, 6))); + assert( + (IntervalValue(-3) % IntervalValue(2)).equals(IntervalValue(-1))); + assert((IntervalValue(1, 3) % IntervalValue(2)) + .equals(IntervalValue(0, 1))); + assert((IntervalValue(2, 7) % IntervalValue(2)) + .equals(IntervalValue(0, 1))); + assert((IntervalValue(-3, 3) % IntervalValue(2)) + .equals(IntervalValue(-1, 1))); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) % + IntervalValue(2)) + .equals(IntervalValue(-1, 1))); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) % + IntervalValue(2)) + .equals(IntervalValue(-1, 1))); + assert((IntervalValue(1, 3) % IntervalValue(1, 2)) + .equals(IntervalValue(0, 1))); + assert((IntervalValue(-3, 3) % IntervalValue(1, 2)) + .equals(IntervalValue(-1, 1))); + assert((IntervalValue(2, 7) % IntervalValue(-2, 3)) + .equals(IntervalValue::top())); // + assert((IntervalValue(-2, 7) % IntervalValue(-2, 3)) + .equals(IntervalValue::top())); // + assert((IntervalValue(IntervalValue::minus_infinity(), 7) % + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) % + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) % + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) % + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, -3) % IntervalValue(3, 9)) + .equals(IntervalValue(-6, 0))); + assert((IntervalValue(-6, 6) % IntervalValue(3, 9)) + .equals(IntervalValue(-6, 6))); // shl << - assert((IntervalValue(IntervalValue::plus_infinity()) << IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::top()))); - assert((IntervalValue(IntervalValue::plus_infinity()) << IntervalValue(2, 2)).equals(IntervalValue(IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity()) << IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::top()))); - assert((IntervalValue(IntervalValue::minus_infinity()) << IntervalValue(2, 2)).equals(IntervalValue(IntervalValue::minus_infinity()))); - assert((IntervalValue(2, 2) << IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::top()))); - assert((IntervalValue(0, 0) << IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(0, 0))); - assert((IntervalValue(-2, -2) << IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::top()))); - assert((IntervalValue(0, 0) << IntervalValue(2, 2)).equals(IntervalValue(0, 0))); - assert((IntervalValue(2, 2) << IntervalValue(3, 3)).equals(IntervalValue(16, 16))); - assert((IntervalValue(-2, -2) << IntervalValue(3, 3)).equals(IntervalValue(-16, -16))); - - assert((IntervalValue(4) << IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() << IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() << IntervalValue(0)).equals(IntervalValue::top())); - assert((IntervalValue(4) << IntervalValue(2)).equals(IntervalValue(16))); - assert((IntervalValue(3) << IntervalValue(2)).equals(IntervalValue(12))); - assert((IntervalValue(-3) << IntervalValue(2)).equals(IntervalValue(-12))); - assert((IntervalValue(4) << IntervalValue(-2)).equals(IntervalValue::bottom())); - assert((IntervalValue(1, 3) << IntervalValue(2)).equals(IntervalValue(4, 12))); - assert((IntervalValue(2, 7) << IntervalValue(2)).equals(IntervalValue(8, 28))); - assert((IntervalValue(-3, 3) << IntervalValue(2)).equals(IntervalValue(-12, 12))); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) << IntervalValue(2)).equals(IntervalValue(-12, IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) << IntervalValue(2)).equals(IntervalValue(IntervalValue::minus_infinity(), 12))); - assert((IntervalValue(1, 3) << IntervalValue(1, 2)).equals(IntervalValue(2, 12))); - assert((IntervalValue(-3, 3) << IntervalValue(1, 2)).equals(IntervalValue(-12, 12))); - assert((IntervalValue(2, 7) << IntervalValue(-2, 3)).equals(IntervalValue(2, 56))); - assert((IntervalValue(-2, 7) << IntervalValue(-2, 3)).equals(IntervalValue(-16, 56))); - assert((IntervalValue(IntervalValue::minus_infinity(), 7) << IntervalValue(-2, 3)).equals(IntervalValue(IntervalValue::minus_infinity(), 56))); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) << IntervalValue(-2, 3)).equals(IntervalValue(-16, IntervalValue::plus_infinity()))); - assert((IntervalValue(-2, 7) << IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue(-16, 56))); - assert((IntervalValue(-2, 7) << IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue::top())); - assert((IntervalValue(-6, -3) << IntervalValue(3, 9)).equals(IntervalValue(-3072, -24))); - assert((IntervalValue(-6, 6) << IntervalValue(3, 9)).equals(IntervalValue(-3072, 3072))); - assert((IntervalValue(-2, 7) << IntervalValue(IntervalValue::minus_infinity(), -1)).equals(IntervalValue::bottom())); - assert((IntervalValue(0) << IntervalValue::top()).equals(IntervalValue(0))); + assert((IntervalValue(IntervalValue::plus_infinity()) + << IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::top()))); + assert((IntervalValue(IntervalValue::plus_infinity()) + << IntervalValue(2, 2)) + .equals(IntervalValue(IntervalValue::plus_infinity()))); + assert((IntervalValue(IntervalValue::minus_infinity()) + << IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::top()))); + assert((IntervalValue(IntervalValue::minus_infinity()) + << IntervalValue(2, 2)) + .equals(IntervalValue(IntervalValue::minus_infinity()))); + assert((IntervalValue(2, 2) + << IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::top()))); + assert((IntervalValue(0, 0) + << IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(0, 0))); + assert((IntervalValue(-2, -2) + << IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::top()))); + assert((IntervalValue(0, 0) << IntervalValue(2, 2)) + .equals(IntervalValue(0, 0))); + assert((IntervalValue(2, 2) << IntervalValue(3, 3)) + .equals(IntervalValue(16, 16))); + assert((IntervalValue(-2, -2) << IntervalValue(3, 3)) + .equals(IntervalValue(-16, -16))); + assert((IntervalValue(4) << IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() << IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() << IntervalValue(0)) + .equals(IntervalValue::top())); + assert( + (IntervalValue(4) << IntervalValue(2)).equals(IntervalValue(16))); + assert( + (IntervalValue(3) << IntervalValue(2)).equals(IntervalValue(12))); + assert( + (IntervalValue(-3) << IntervalValue(2)).equals(IntervalValue(-12))); + assert((IntervalValue(4) << IntervalValue(-2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue(1, 3) << IntervalValue(2)) + .equals(IntervalValue(4, 12))); + assert((IntervalValue(2, 7) << IntervalValue(2)) + .equals(IntervalValue(8, 28))); + assert((IntervalValue(-3, 3) << IntervalValue(2)) + .equals(IntervalValue(-12, 12))); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) + << IntervalValue(2)) + .equals(IntervalValue(-12, IntervalValue::plus_infinity()))); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) + << IntervalValue(2)) + .equals(IntervalValue(IntervalValue::minus_infinity(), 12))); + assert((IntervalValue(1, 3) << IntervalValue(1, 2)) + .equals(IntervalValue(2, 12))); + assert((IntervalValue(-3, 3) << IntervalValue(1, 2)) + .equals(IntervalValue(-12, 12))); + assert((IntervalValue(2, 7) << IntervalValue(-2, 3)) + .equals(IntervalValue(2, 56))); + assert((IntervalValue(-2, 7) << IntervalValue(-2, 3)) + .equals(IntervalValue(-16, 56))); + assert((IntervalValue(IntervalValue::minus_infinity(), 7) + << IntervalValue(-2, 3)) + .equals(IntervalValue(IntervalValue::minus_infinity(), 56))); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) + << IntervalValue(-2, 3)) + .equals(IntervalValue(-16, IntervalValue::plus_infinity()))); + assert((IntervalValue(-2, 7) + << IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue(-16, 56))); + assert((IntervalValue(-2, 7) + << IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, -3) << IntervalValue(3, 9)) + .equals(IntervalValue(-3072, -24))); + assert((IntervalValue(-6, 6) << IntervalValue(3, 9)) + .equals(IntervalValue(-3072, 3072))); + assert((IntervalValue(-2, 7) + << IntervalValue(IntervalValue::minus_infinity(), -1)) + .equals(IntervalValue::bottom())); + assert((IntervalValue(0) << IntervalValue::top()) + .equals(IntervalValue(0))); // shr >> - assert((IntervalValue(IntervalValue::plus_infinity()) >> IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::plus_infinity()) >> IntervalValue(2)).equals(IntervalValue(IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity()) >> IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(IntervalValue::minus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity()) >> IntervalValue(2)).equals(IntervalValue(IntervalValue::minus_infinity()))); - assert((IntervalValue(2) >> IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(0))); - assert((IntervalValue(0) >> IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(0))); - assert((IntervalValue(-2) >> IntervalValue(IntervalValue::plus_infinity())).equals(IntervalValue(-1))); + assert((IntervalValue(IntervalValue::plus_infinity()) >> + IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::plus_infinity()))); + assert( + (IntervalValue(IntervalValue::plus_infinity()) >> IntervalValue(2)) + .equals(IntervalValue(IntervalValue::plus_infinity()))); + assert((IntervalValue(IntervalValue::minus_infinity()) >> + IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(IntervalValue::minus_infinity()))); + assert( + (IntervalValue(IntervalValue::minus_infinity()) >> IntervalValue(2)) + .equals(IntervalValue(IntervalValue::minus_infinity()))); + assert( + (IntervalValue(2) >> IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(0))); + assert( + (IntervalValue(0) >> IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(0))); + assert( + (IntervalValue(-2) >> IntervalValue(IntervalValue::plus_infinity())) + .equals(IntervalValue(-1))); assert((IntervalValue(0) >> IntervalValue(2)).equals(IntervalValue(0))); - assert((IntervalValue(15) >> IntervalValue(2)).equals(IntervalValue(3))); - assert((IntervalValue(-15) >> IntervalValue(2)).equals(IntervalValue(-4))); + assert( + (IntervalValue(15) >> IntervalValue(2)).equals(IntervalValue(3))); + assert( + (IntervalValue(-15) >> IntervalValue(2)).equals(IntervalValue(-4))); - assert((IntervalValue(4) >> IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() >> IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() >> IntervalValue(0)).equals(IntervalValue::top())); - assert((IntervalValue(15) >> IntervalValue(2)).equals(IntervalValue(3))); + assert((IntervalValue(4) >> IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() >> IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() >> IntervalValue(0)) + .equals(IntervalValue::top())); + assert( + (IntervalValue(15) >> IntervalValue(2)).equals(IntervalValue(3))); assert((IntervalValue(1) >> IntervalValue(2)).equals(IntervalValue(0))); - assert((IntervalValue(-15) >> IntervalValue(2)).equals(IntervalValue(-4))); - assert((IntervalValue(4) >> IntervalValue(-2)).equals(IntervalValue::bottom())); - assert((IntervalValue(1, 3) >> IntervalValue(2)).equals(IntervalValue(0))); - assert((IntervalValue(2, 7) >> IntervalValue(2)).equals(IntervalValue(0, 1))); - assert((IntervalValue(-15, 15) >> IntervalValue(2)).equals(IntervalValue(-4, 3))); - assert((IntervalValue(-15, IntervalValue::plus_infinity()) >> IntervalValue(2)).equals(IntervalValue(-4, IntervalValue::plus_infinity()))); - assert((IntervalValue(IntervalValue::minus_infinity(), 15) >> IntervalValue(2)).equals(IntervalValue(IntervalValue::minus_infinity(), 3))); - assert((IntervalValue(0, 15) >> IntervalValue(1, 2)).equals(IntervalValue(0, 7))); - assert((IntervalValue(-17, 15) >> IntervalValue(1, 2)).equals(IntervalValue(-9, 7))); - assert((IntervalValue(2, 7) >> IntervalValue(-2, 3)).equals(IntervalValue(0, 7))); - assert((IntervalValue(-2, 7) >> IntervalValue(-2, 3)).equals(IntervalValue(-2, 7))); - assert((IntervalValue(IntervalValue::minus_infinity(), 7) >> IntervalValue(-2, 3)).equals(IntervalValue(IntervalValue::minus_infinity(), 7))); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) >> IntervalValue(-2, 3)).equals(IntervalValue(-2, IntervalValue::plus_infinity()))); - assert((IntervalValue(-2, 7) >> IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue(-2, 7))); - assert((IntervalValue(-2, 7) >> IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue(-2, 7))); - assert((IntervalValue(-6, -3) >> IntervalValue(2, 3)).equals(IntervalValue(-2, -1))); - assert((IntervalValue(-6, 6) >> IntervalValue(2, 3)).equals(IntervalValue(-2, 1))); - assert((IntervalValue(-2, 7) >> IntervalValue(IntervalValue::minus_infinity(), -1)).equals(IntervalValue::bottom())); - assert((IntervalValue(0) >> IntervalValue::top()).equals(IntervalValue(0))); + assert( + (IntervalValue(-15) >> IntervalValue(2)).equals(IntervalValue(-4))); + assert((IntervalValue(4) >> IntervalValue(-2)) + .equals(IntervalValue::bottom())); + assert( + (IntervalValue(1, 3) >> IntervalValue(2)).equals(IntervalValue(0))); + assert((IntervalValue(2, 7) >> IntervalValue(2)) + .equals(IntervalValue(0, 1))); + assert((IntervalValue(-15, 15) >> IntervalValue(2)) + .equals(IntervalValue(-4, 3))); + assert((IntervalValue(-15, IntervalValue::plus_infinity()) >> + IntervalValue(2)) + .equals(IntervalValue(-4, IntervalValue::plus_infinity()))); + assert((IntervalValue(IntervalValue::minus_infinity(), 15) >> + IntervalValue(2)) + .equals(IntervalValue(IntervalValue::minus_infinity(), 3))); + assert((IntervalValue(0, 15) >> IntervalValue(1, 2)) + .equals(IntervalValue(0, 7))); + assert((IntervalValue(-17, 15) >> IntervalValue(1, 2)) + .equals(IntervalValue(-9, 7))); + assert((IntervalValue(2, 7) >> IntervalValue(-2, 3)) + .equals(IntervalValue(0, 7))); + assert((IntervalValue(-2, 7) >> IntervalValue(-2, 3)) + .equals(IntervalValue(-2, 7))); + assert((IntervalValue(IntervalValue::minus_infinity(), 7) >> + IntervalValue(-2, 3)) + .equals(IntervalValue(IntervalValue::minus_infinity(), 7))); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) >> + IntervalValue(-2, 3)) + .equals(IntervalValue(-2, IntervalValue::plus_infinity()))); + assert((IntervalValue(-2, 7) >> + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue(-2, 7))); + assert((IntervalValue(-2, 7) >> + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue(-2, 7))); + assert((IntervalValue(-6, -3) >> IntervalValue(2, 3)) + .equals(IntervalValue(-2, -1))); + assert((IntervalValue(-6, 6) >> IntervalValue(2, 3)) + .equals(IntervalValue(-2, 1))); + assert((IntervalValue(-2, 7) >> + IntervalValue(IntervalValue::minus_infinity(), -1)) + .equals(IntervalValue::bottom())); + assert((IntervalValue(0) >> IntervalValue::top()) + .equals(IntervalValue(0))); // and & - assert((IntervalValue(4) & IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() & IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() & IntervalValue(0)).equals(IntervalValue(0))); + assert((IntervalValue(4) & IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() & IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert( + (IntervalValue::top() & IntervalValue(0)).equals(IntervalValue(0))); assert((IntervalValue(4) & IntervalValue(2)).equals(IntervalValue(0))); assert((IntervalValue(3) & IntervalValue(2)).equals(IntervalValue(2))); assert((IntervalValue(-3) & IntervalValue(2)).equals(IntervalValue(0))); - assert((IntervalValue(1, 3) & IntervalValue(2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(2, 7) & IntervalValue(2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(-3, 3) & IntervalValue(2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) & IntervalValue(2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) & IntervalValue(2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(1, 3) & IntervalValue(1, 2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(-3, 3) & IntervalValue(1, 2)).equals(IntervalValue(0, 2))); - assert((IntervalValue(2, 7) & IntervalValue(-2, 3)).equals(IntervalValue(0, 7))); - assert((IntervalValue(-2, 7) & IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(IntervalValue::minus_infinity(), 7) & IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) & IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) & IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) & IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue::top())); - assert((IntervalValue(-6, -3) & IntervalValue(3, 9)).equals(IntervalValue(0, 9))); - assert((IntervalValue(-6, 6) & IntervalValue(3, 9)).equals(IntervalValue(0, 9))); + assert((IntervalValue(1, 3) & IntervalValue(2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(2, 7) & IntervalValue(2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(-3, 3) & IntervalValue(2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) & + IntervalValue(2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) & + IntervalValue(2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(1, 3) & IntervalValue(1, 2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(-3, 3) & IntervalValue(1, 2)) + .equals(IntervalValue(0, 2))); + assert((IntervalValue(2, 7) & IntervalValue(-2, 3)) + .equals(IntervalValue(0, 7))); + assert((IntervalValue(-2, 7) & IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(IntervalValue::minus_infinity(), 7) & + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) & + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) & + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) & + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, -3) & IntervalValue(3, 9)) + .equals(IntervalValue(0, 9))); + assert((IntervalValue(-6, 6) & IntervalValue(3, 9)) + .equals(IntervalValue(0, 9))); // Or | - assert((IntervalValue(4) | IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() | IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() | IntervalValue(-1)).equals(IntervalValue::top()));// - assert((IntervalValue(-1) | IntervalValue::top()).equals(IntervalValue::top()));// + assert((IntervalValue(4) | IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() | IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() | IntervalValue(-1)) + .equals(IntervalValue::top())); // + assert((IntervalValue(-1) | IntervalValue::top()) + .equals(IntervalValue::top())); // assert((IntervalValue(4) | IntervalValue(2)).equals(IntervalValue(6))); assert((IntervalValue(3) | IntervalValue(2)).equals(IntervalValue(3))); - assert((IntervalValue(-3) | IntervalValue(2)).equals(IntervalValue(-1))); - assert((IntervalValue(1, 3) | IntervalValue(2)).equals(IntervalValue(0, 3))); - assert((IntervalValue(2, 7) | IntervalValue(2)).equals(IntervalValue(0, 7))); - assert((IntervalValue(-3, 3) | IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) | IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) | IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(1, 3) | IntervalValue(1, 2)).equals(IntervalValue(0, 3))); - assert((IntervalValue(-3, 3) | IntervalValue(1, 2)).equals(IntervalValue::top())); - assert((IntervalValue(2, 7) | IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) | IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(IntervalValue::minus_infinity(), 7) | IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) | IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) | IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) | IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue::top())); - assert((IntervalValue(-6, -3) | IntervalValue(3, 9)).equals(IntervalValue::top())); - assert((IntervalValue(-6, 6) | IntervalValue(3, 9)).equals(IntervalValue::top())); + assert( + (IntervalValue(-3) | IntervalValue(2)).equals(IntervalValue(-1))); + assert((IntervalValue(1, 3) | IntervalValue(2)) + .equals(IntervalValue(0, 3))); + assert((IntervalValue(2, 7) | IntervalValue(2)) + .equals(IntervalValue(0, 7))); + assert((IntervalValue(-3, 3) | IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) | + IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) | + IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(1, 3) | IntervalValue(1, 2)) + .equals(IntervalValue(0, 3))); + assert((IntervalValue(-3, 3) | IntervalValue(1, 2)) + .equals(IntervalValue::top())); + assert((IntervalValue(2, 7) | IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) | IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(IntervalValue::minus_infinity(), 7) | + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) | + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) | + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) | + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, -3) | IntervalValue(3, 9)) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, 6) | IntervalValue(3, 9)) + .equals(IntervalValue::top())); // Xor ^ - assert((IntervalValue(4) ^ IntervalValue::bottom()).equals(IntervalValue::bottom())); - assert((IntervalValue::bottom() ^ IntervalValue(2)).equals(IntervalValue::bottom())); - assert((IntervalValue::top() ^ IntervalValue(-1)).equals(IntervalValue::top())); - assert((IntervalValue(-1) ^ IntervalValue::top()).equals(IntervalValue::top())); + assert((IntervalValue(4) ^ IntervalValue::bottom()) + .equals(IntervalValue::bottom())); + assert((IntervalValue::bottom() ^ IntervalValue(2)) + .equals(IntervalValue::bottom())); + assert((IntervalValue::top() ^ IntervalValue(-1)) + .equals(IntervalValue::top())); + assert((IntervalValue(-1) ^ IntervalValue::top()) + .equals(IntervalValue::top())); assert((IntervalValue(4) ^ IntervalValue(2)).equals(IntervalValue(6))); assert((IntervalValue(3) ^ IntervalValue(2)).equals(IntervalValue(1))); - assert((IntervalValue(-3) ^ IntervalValue(2)).equals(IntervalValue(-1))); - assert((IntervalValue(1, 3) ^ IntervalValue(2)).equals(IntervalValue(0, 3))); - assert((IntervalValue(2, 7) ^ IntervalValue(2)).equals(IntervalValue(0, 7))); - assert((IntervalValue(-3, 3) ^ IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(-3, IntervalValue::plus_infinity()) ^ IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(IntervalValue::minus_infinity(), 3) ^ IntervalValue(2)).equals(IntervalValue::top())); - assert((IntervalValue(1, 3) ^ IntervalValue(1, 2)).equals(IntervalValue(0, 3))); - assert((IntervalValue(-3, 3) ^ IntervalValue(1, 2)).equals(IntervalValue::top())); - assert((IntervalValue(2, 7) ^ IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) ^ IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(IntervalValue::minus_infinity(), 7) ^ IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, IntervalValue::plus_infinity()) ^ IntervalValue(-2, 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) ^ IntervalValue(IntervalValue::minus_infinity(), 3)).equals(IntervalValue::top())); - assert((IntervalValue(-2, 7) ^ IntervalValue(-2, IntervalValue::plus_infinity())).equals(IntervalValue::top())); - assert((IntervalValue(-6, -3) ^ IntervalValue(3, 9)).equals(IntervalValue::top())); - assert((IntervalValue(-6, 6) ^ IntervalValue(3, 9)).equals(IntervalValue::top())); + assert( + (IntervalValue(-3) ^ IntervalValue(2)).equals(IntervalValue(-1))); + assert((IntervalValue(1, 3) ^ IntervalValue(2)) + .equals(IntervalValue(0, 3))); + assert((IntervalValue(2, 7) ^ IntervalValue(2)) + .equals(IntervalValue(0, 7))); + assert((IntervalValue(-3, 3) ^ IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(-3, IntervalValue::plus_infinity()) ^ + IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(IntervalValue::minus_infinity(), 3) ^ + IntervalValue(2)) + .equals(IntervalValue::top())); + assert((IntervalValue(1, 3) ^ IntervalValue(1, 2)) + .equals(IntervalValue(0, 3))); + assert((IntervalValue(-3, 3) ^ IntervalValue(1, 2)) + .equals(IntervalValue::top())); + assert((IntervalValue(2, 7) ^ IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) ^ IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(IntervalValue::minus_infinity(), 7) ^ + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, IntervalValue::plus_infinity()) ^ + IntervalValue(-2, 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) ^ + IntervalValue(IntervalValue::minus_infinity(), 3)) + .equals(IntervalValue::top())); + assert((IntervalValue(-2, 7) ^ + IntervalValue(-2, IntervalValue::plus_infinity())) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, -3) ^ IntervalValue(3, 9)) + .equals(IntervalValue::top())); + assert((IntervalValue(-6, 6) ^ IntervalValue(3, 9)) + .equals(IntervalValue::top())); } void testAbsState() @@ -833,37 +1066,41 @@ class AETest as[3] = AddressValue(0x7f000007); as[4] = AddressValue(0x7f000008); // store: *as[3] = as[1], *as[4] = as[2] - for (auto addr : as[3].getAddrs()) as.store(addr, as[1]); - for (auto addr : as[4].getAddrs()) as.store(addr, as[2]); + for (auto addr : as[3].getAddrs()) + as.store(addr, as[1]); + for (auto addr : as[4].getAddrs()) + as.store(addr, as[2]); as.printAbstractState(); // load: verify *as[3] == as[1] && *as[4] == as[2] AbstractValue v3, v4; - for (auto addr : as[3].getAddrs()) v3.join_with(as.load(addr)); - for (auto addr : as[4].getAddrs()) v4.join_with(as.load(addr)); + for (auto addr : as[3].getAddrs()) + v3.join_with(as.load(addr)); + for (auto addr : as[4].getAddrs()) + v4.join_with(as.load(addr)); assert(v3.equals(as[1]) && v4.equals(as[2])); } }; - int main(int argc, char** argv) { int arg_num = 0; int extraArgc = 3; - char **arg_value = new char *[argc + extraArgc]; + char** arg_value = new char*[argc + extraArgc]; for (; arg_num < argc; ++arg_num) { arg_value[arg_num] = argv[arg_num]; } // add extra options - arg_value[arg_num++] = (char*) "-model-consts=true"; - arg_value[arg_num++] = (char*) "-model-arrays=true"; - arg_value[arg_num++] = (char*) "-pre-field-sensitive=false"; - assert(arg_num == (argc + extraArgc) && "more extra arguments? Change the value of extraArgc"); + arg_value[arg_num++] = (char*)"-model-consts=true"; + arg_value[arg_num++] = (char*)"-model-arrays=true"; + arg_value[arg_num++] = (char*)"-pre-field-sensitive=false"; + assert(arg_num == (argc + extraArgc) && + "more extra arguments? Change the value of extraArgc"); std::vector moduleNameVec; - moduleNameVec = OptionBase::parseOptions( - arg_num, arg_value, "Static Symbolic Execution", "[options] " - ); + moduleNameVec = OptionBase::parseOptions(arg_num, arg_value, + "Static Symbolic Execution", + "[options] "); delete[] arg_value; if (SYMABS()) { @@ -883,8 +1120,9 @@ int main(int argc, char** argv) LLVMModuleSet::getLLVMModuleSet()->buildSVFModule(moduleNameVec); SVFIRBuilder builder; SVFIR* pag = builder.build(); - // Run Andersen's to resolve indirect calls, then update SVFIR with resolved targets. - // The Andersen singleton will be reused inside AbstractInterpretation::runOnModule(). + // Run Andersen's to resolve indirect calls, then update SVFIR with resolved + // targets. The Andersen singleton will be reused inside + // AbstractInterpretation::runOnModule(). AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(pag); builder.updateCallGraph(ander->getCallGraph()); AbstractInterpretation& ae = AbstractInterpretation::getAEInstance(); diff --git a/svf-llvm/tools/CMakeLists.txt b/svf-llvm/tools/CMakeLists.txt index 8c3ba3530b..b63bdd5898 100644 --- a/svf-llvm/tools/CMakeLists.txt +++ b/svf-llvm/tools/CMakeLists.txt @@ -22,6 +22,23 @@ foreach(_tool IN LISTS ALL_TOOLS) # Link the SvfLLVM library against SVF's core & LLVM libraries target_link_libraries(${_tool} PRIVATE SvfCore SvfLLVM) + # On Windows, increaseStackSize() is a no-op (RLIMIT_STACK not available). + # Set the PE stack reserve to 256 MB at link time to match Linux behaviour. + if(WIN32) + if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") + if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") + # clang++ targeting MSVC ABI + target_link_options(${_tool} PRIVATE -Xlinker /STACK:268435456) + else() + # cl.exe or clang-cl.exe targeting MSVC ABI + target_link_options(${_tool} PRIVATE /STACK:268435456) + endif() + else() + # MinGW (clang++ or g++) uses GNU linker syntax + target_link_options(${_tool} PRIVATE -Wl,--stack,268435456) + endif() + endif() + # Ensure that the build artifacts are placed into lib/bin/include relative to the top of the build directory set_target_properties( ${_tool} diff --git a/svf/include/AE/Core/NumericValue.h b/svf/include/AE/Core/NumericValue.h index d52df3b161..2686f33404 100644 --- a/svf/include/AE/Core/NumericValue.h +++ b/svf/include/AE/Core/NumericValue.h @@ -27,8 +27,9 @@ * */ // The implementation is based on -// Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction. -// 46th International Conference on Software Engineering. (ICSE24) +// Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via +// Cross-Domain Interaction. 46th International Conference on Software +// Engineering. (ICSE24) #ifndef SVF_NUMERICVALUE_H #define SVF_NUMERICVALUE_H @@ -39,9 +40,9 @@ #include "Util/GeneralType.h" -#define epsilon std::numeric_limits::epsilon(); namespace SVF { +constexpr double epsilon = std::numeric_limits::epsilon(); /** * @brief A class representing a bounded 64-bit integer. @@ -283,7 +284,7 @@ class BoundedInt // If one number is positive infinity and the other is negative // infinity, this is an invalid operation, so we assert false. if ((lhs.is_plus_infinity() && rhs.is_minus_infinity()) || - (lhs.is_minus_infinity() && rhs.is_plus_infinity())) + (lhs.is_minus_infinity() && rhs.is_plus_infinity())) { assert(false && "invalid add"); } @@ -305,7 +306,7 @@ class BoundedInt // If both numbers are positive and their sum would exceed the maximum // representable number, the result is positive infinity. if (lhs._iVal > 0 && rhs._iVal > 0 && - (std::numeric_limits::max() - lhs._iVal) < rhs._iVal) + (std::numeric_limits::max() - lhs._iVal) < rhs._iVal) { return plus_infinity(); } @@ -313,7 +314,7 @@ class BoundedInt // If both numbers are negative and their sum would be less than the // most negative representable number, the result is negative infinity. if (lhs._iVal < 0 && rhs._iVal < 0 && - (-std::numeric_limits::max() - lhs._iVal) > rhs._iVal) + (-std::numeric_limits::max() - lhs._iVal) > rhs._iVal) { return minus_infinity(); } @@ -388,7 +389,7 @@ class BoundedInt // If both numbers are positive and their product would exceed the // maximum representable number, the result is positive infinity. if (lhs._iVal > 0 && rhs._iVal > 0 && - (std::numeric_limits::max() / lhs._iVal) < rhs._iVal) + (std::numeric_limits::max() / lhs._iVal) < rhs._iVal) { return plus_infinity(); } @@ -396,7 +397,7 @@ class BoundedInt // If both numbers are negative and their product would exceed the // maximum representable number, the result is positive infinity. if (lhs._iVal < 0 && rhs._iVal < 0 && - (std::numeric_limits::max() / lhs._iVal) > rhs._iVal) + (std::numeric_limits::max() / lhs._iVal) > rhs._iVal) { return plus_infinity(); } @@ -405,9 +406,9 @@ class BoundedInt // would be less than the most negative representable number, the result // is negative infinity. if ((lhs._iVal > 0 && rhs._iVal < 0 && - (-std::numeric_limits::max() / lhs._iVal) > rhs._iVal) || - (lhs._iVal < 0 && rhs._iVal > 0 && - (-std::numeric_limits::max() / rhs._iVal) > lhs._iVal)) + (-std::numeric_limits::max() / lhs._iVal) > rhs._iVal) || + (lhs._iVal < 0 && rhs._iVal > 0 && + (-std::numeric_limits::max() / rhs._iVal) > lhs._iVal)) { return minus_infinity(); } @@ -417,7 +418,6 @@ class BoundedInt return lhs._iVal * rhs._iVal; } - friend BoundedInt operator%(const BoundedInt& lhs, const BoundedInt& rhs) { if (rhs.is_zero()) @@ -568,37 +568,37 @@ class BoundedInt } // Defines a function to find the minimum of two BoundedInt objects. - // This function directly compares the internal integer values of the BoundedInt objects, - // and also checks if either of them represents infinity. + // This function directly compares the internal integer values of the + // BoundedInt objects, and also checks if either of them represents + // infinity. friend BoundedInt min(const BoundedInt& lhs, const BoundedInt& rhs) { if (lhs.is_minus_infinity() || rhs.is_minus_infinity()) return minus_infinity(); - else if(lhs.is_plus_infinity()) + else if (lhs.is_plus_infinity()) return rhs; - else if(rhs.is_plus_infinity()) + else if (rhs.is_plus_infinity()) return lhs; else return BoundedInt(std::min(lhs._iVal, rhs._iVal)); } - // Defines a function to find the maximum of two BoundedInt objects. - // This function directly compares the internal integer values of the BoundedInt objects, - // and also checks if either of them represents infinity. + // This function directly compares the internal integer values of the + // BoundedInt objects, and also checks if either of them represents + // infinity. friend BoundedInt max(const BoundedInt& lhs, const BoundedInt& rhs) { if (lhs.is_plus_infinity() || rhs.is_plus_infinity()) return plus_infinity(); - else if(lhs.is_minus_infinity()) + else if (lhs.is_minus_infinity()) return rhs; - else if(rhs.is_minus_infinity()) + else if (rhs.is_minus_infinity()) return lhs; else return BoundedInt(std::max(lhs._iVal, rhs._iVal)); } - // Defines a function to find the minimum of a vector of BoundedInt objects. // This function iterates over the vector and returns the smallest // BoundedInt object. @@ -864,38 +864,32 @@ class BoundedDouble /// Reload operator //{% - friend bool operator==(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator==(const BoundedDouble& lhs, const BoundedDouble& rhs) { return lhs.equal(rhs); } - friend bool operator!=(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator!=(const BoundedDouble& lhs, const BoundedDouble& rhs) { return !lhs.equal(rhs); } - friend bool operator>(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator>(const BoundedDouble& lhs, const BoundedDouble& rhs) { return !lhs.leq(rhs); } - friend bool operator<(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator<(const BoundedDouble& lhs, const BoundedDouble& rhs) { return !lhs.geq(rhs); } - friend bool operator<=(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator<=(const BoundedDouble& lhs, const BoundedDouble& rhs) { return lhs.leq(rhs); } - friend bool operator>=(const BoundedDouble& lhs, - const BoundedDouble& rhs) + friend bool operator>=(const BoundedDouble& lhs, const BoundedDouble& rhs) { return lhs.geq(rhs); } @@ -912,9 +906,9 @@ class BoundedDouble static double safeAdd(double lhs, double rhs) { if ((lhs == std::numeric_limits::infinity() && - rhs == -std::numeric_limits::infinity()) || - (lhs == -std::numeric_limits::infinity() && - rhs == std::numeric_limits::infinity())) + rhs == -std::numeric_limits::infinity()) || + (lhs == -std::numeric_limits::infinity() && + rhs == std::numeric_limits::infinity())) { assert(false && "invalid add"); } @@ -939,7 +933,7 @@ class BoundedDouble // Check for positive overflow: verify if both operands are positive and // their sum exceeds the maximum double value if (lhs > 0 && rhs > 0 && - (std::numeric_limits::max() - lhs) < rhs) + (std::numeric_limits::max() - lhs) < rhs) { res = std::numeric_limits::infinity(); // Set result to // positive infinity to @@ -950,10 +944,10 @@ class BoundedDouble // Check for an underflow scenario: both numbers are negative and their // sum is more negative than what double can represent if (lhs < 0 && rhs < 0 && - (-std::numeric_limits::max() - lhs) > rhs) + (-std::numeric_limits::max() - lhs) > rhs) { res = -std::numeric_limits< - double>::infinity(); // Set result to negative infinity to + double>::infinity(); // Set result to negative infinity to // clarify extreme negative sum return res; } @@ -1010,24 +1004,24 @@ class BoundedDouble } // Check for overflow scenarios if (lhs > 0 && rhs > 0 && - lhs > std::numeric_limits::max() / rhs) + lhs > std::numeric_limits::max() / rhs) { return std::numeric_limits::infinity(); } if (lhs < 0 && rhs < 0 && - lhs < std::numeric_limits::max() / rhs) + lhs < std::numeric_limits::max() / rhs) { return std::numeric_limits::infinity(); } // Check for "underflow" scenarios (negative overflow) if (lhs > 0 && rhs < 0 && - rhs < std::numeric_limits::lowest() / lhs) + rhs < std::numeric_limits::lowest() / lhs) { return -std::numeric_limits::infinity(); } if (lhs < 0 && rhs > 0 && - lhs < std::numeric_limits::lowest() / rhs) + lhs < std::numeric_limits::lowest() / rhs) { return -std::numeric_limits::infinity(); } @@ -1056,7 +1050,7 @@ class BoundedDouble if (doubleEqual(rhs, 0.0f)) { return (lhs >= 0.0f) ? std::numeric_limits::infinity() - : -std::numeric_limits::infinity(); + : -std::numeric_limits::infinity(); } double res = lhs / rhs; // Check if the result is positive infinity due to overflow @@ -1076,12 +1070,12 @@ class BoundedDouble // Check for overflow when dividing small numbers if (rhs > 0 && rhs < std::numeric_limits::min() && - lhs > std::numeric_limits::max() * rhs) + lhs > std::numeric_limits::max() * rhs) { return std::numeric_limits::infinity(); } if (rhs < 0 && rhs > -std::numeric_limits::min() && - lhs > std::numeric_limits::max() * rhs) + lhs > std::numeric_limits::max() * rhs) { return -std::numeric_limits::infinity(); } diff --git a/svf/include/MemoryModel/PointerAnalysis.h b/svf/include/MemoryModel/PointerAnalysis.h index ac64bf9136..3b4162113f 100644 --- a/svf/include/MemoryModel/PointerAnalysis.h +++ b/svf/include/MemoryModel/PointerAnalysis.h @@ -30,8 +30,10 @@ #ifndef POINTERANALYSIS_H_ #define POINTERANALYSIS_H_ -#include -#include +#ifndef _WIN32 +# include +# include +#endif #include "Graphs/CHG.h" #include "Graphs/CallGraph.h" diff --git a/svf/include/MemoryModel/PointsTo.h b/svf/include/MemoryModel/PointsTo.h index ad240f91bb..a82cef932e 100644 --- a/svf/include/MemoryModel/PointsTo.h +++ b/svf/include/MemoryModel/PointsTo.h @@ -15,9 +15,9 @@ #include #include -#include "Util/GeneralType.h" #include "Util/BitVector.h" #include "Util/CoreBitVector.h" +#include "Util/GeneralType.h" #include "Util/SparseBitVector.h" namespace SVF @@ -46,17 +46,17 @@ class PointsTo /// Construct empty points-to set. PointsTo(); /// Copy constructor. - PointsTo(const PointsTo &pt); + PointsTo(const PointsTo& pt); /// Move constructor. - PointsTo(PointsTo &&pt) noexcept ; + PointsTo(PointsTo&& pt) noexcept; ~PointsTo(); /// Copy assignment. - PointsTo &operator=(const PointsTo &rhs); + PointsTo& operator=(const PointsTo& rhs); /// Move assignment. - PointsTo &operator=(PointsTo &&rhs) noexcept ; + PointsTo& operator=(PointsTo&& rhs) noexcept; /// Returns true if set is empty. bool empty() const; @@ -81,40 +81,41 @@ class PointsTo void reset(u32_t n); /// Returns true if this set is a superset of rhs. - bool contains(const PointsTo &rhs) const; + bool contains(const PointsTo& rhs) const; /// Returns true if this set and rhs share any elements. - bool intersects(const PointsTo &rhs) const; + bool intersects(const PointsTo& rhs) const; /// Returns the first element the set. Returns -1 when the set is empty. /// TODO: should we diverge from LLVM about the int return? int find_first(); /// Returns true if this set and rhs contain exactly the same elements. - bool operator==(const PointsTo &rhs) const; + bool operator==(const PointsTo& rhs) const; /// Returns true if either this set or rhs has an element not in the other. - bool operator!=(const PointsTo &rhs) const; + bool operator!=(const PointsTo& rhs) const; /// Put union of this set and rhs into this set. /// Returns true if this set changed. - bool operator|=(const PointsTo &rhs); - bool operator|=(const NodeBS &rhs); + bool operator|=(const PointsTo& rhs); + bool operator|=(const NodeBS& rhs); /// Put intersection of this set and rhs into this set. /// Returns true if this set changed. - bool operator&=(const PointsTo &rhs); + bool operator&=(const PointsTo& rhs); /// Remove elements in rhs from this set. /// Returns true if this set changed. - bool operator-=(const PointsTo &rhs); + bool operator-=(const PointsTo& rhs); /// Put intersection of this set with complement of rhs into this set. /// Returns true if this set changed. - bool intersectWithComplement(const PointsTo &rhs); + bool intersectWithComplement(const PointsTo& rhs); - /// Put intersection of lhs with complement of rhs into this set (overwrites). - void intersectWithComplement(const PointsTo &lhs, const PointsTo &rhs); + /// Put intersection of lhs with complement of rhs into this set + /// (overwrites). + void intersectWithComplement(const PointsTo& lhs, const PointsTo& rhs); /// Returns this points-to set as a NodeBS. NodeBS toNodeBS() const; @@ -139,8 +140,9 @@ class PointsTo static MappingPtr getCurrentBestNodeMapping(); static MappingPtr getCurrentBestReverseNodeMapping(); - static void setCurrentBestNodeMapping(MappingPtr newCurrentBestNodeMapping, - MappingPtr newCurrentBestReverseNodeMapping); + static void setCurrentBestNodeMapping( + MappingPtr newCurrentBestNodeMapping, + MappingPtr newCurrentBestReverseNodeMapping); private: /// Returns nodeMapping[n], checking for nullptr and size. @@ -149,9 +151,9 @@ class PointsTo /// Returns reverseNodeMapping[n], checking for nullptr and size. NodeID getExternalNode(NodeID n) const; - /// Returns true if this points-to set and pt have the same type, nodeMapping, - /// and reverseNodeMapping - bool metaSame(const PointsTo &pt) const; + /// Returns true if this points-to set and pt have the same type, + /// nodeMapping, and reverseNodeMapping + bool metaSame(const PointsTo& pt) const; private: /// Best node mapping we know of the for the analyses at hand. @@ -161,8 +163,7 @@ class PointsTo /// Holds backing data structure. /// TODO: std::variant when we move to C++17. - union - { + union { /// Sparse bit vector backing. SparseBitVector<> sbv; /// Core bit vector backing. @@ -185,23 +186,24 @@ class PointsTo using iterator_category = std::forward_iterator_tag; using value_type = u32_t; using difference_type = std::ptrdiff_t; - using pointer = u32_t *; - using reference = u32_t &; + using pointer = u32_t*; + using reference = u32_t&; /// Deleted because we don't want iterators with null pt. PointsToIterator() = delete; - PointsToIterator(const PointsToIterator &pt); - PointsToIterator(PointsToIterator &&pt) noexcept ; + PointsToIterator(const PointsToIterator& pt); + PointsToIterator(PointsToIterator&& pt) noexcept; + ~PointsToIterator(); /// Returns an iterator to the beginning of pt if end is false, and to /// the end of pt if end is true. - explicit PointsToIterator(const PointsTo *pt, bool end=false); + explicit PointsToIterator(const PointsTo* pt, bool end = false); - PointsToIterator &operator=(const PointsToIterator &rhs); - PointsToIterator &operator=(PointsToIterator &&rhs) noexcept ; + PointsToIterator& operator=(const PointsToIterator& rhs); + PointsToIterator& operator=(PointsToIterator&& rhs) noexcept; /// Pre-increment: ++it. - const PointsToIterator &operator++(); + const PointsToIterator& operator++(); /// Post-increment: it++. const PointsToIterator operator++(int); @@ -210,21 +212,20 @@ class PointsTo u32_t operator*() const; /// Equality: *this == rhs. - bool operator==(const PointsToIterator &rhs) const; + bool operator==(const PointsToIterator& rhs) const; /// Inequality: *this != rhs. - bool operator!=(const PointsToIterator &rhs) const; + bool operator!=(const PointsToIterator& rhs) const; private: bool atEnd() const; private: /// PointsTo we are iterating over. - const PointsTo *pt; + const PointsTo* pt; /// Iterator into the backing data structure. Discriminated by pt->type. /// TODO: std::variant when we move to C++17. - union - { + union { SparseBitVector<>::iterator sbvIt; CoreBitVector::iterator cbvIt; BitVector::iterator bvIt; @@ -233,24 +234,22 @@ class PointsTo }; /// Returns a new lhs | rhs. -PointsTo operator|(const PointsTo &lhs, const PointsTo &rhs); +PointsTo operator|(const PointsTo& lhs, const PointsTo& rhs); /// Returns a new lhs & rhs. -PointsTo operator&(const PointsTo &lhs, const PointsTo &rhs); +PointsTo operator&(const PointsTo& lhs, const PointsTo& rhs); /// Returns a new lhs - rhs. -PointsTo operator-(const PointsTo &lhs, const PointsTo &rhs); +PointsTo operator-(const PointsTo& lhs, const PointsTo& rhs); } // End namespace SVF -template <> -struct std::hash +template <> struct std::hash { - size_t operator()(const SVF::PointsTo &pt) const + size_t operator()(const SVF::PointsTo& pt) const { return pt.hash(); } }; - -#endif // POINTSTO_H_ +#endif // POINTSTO_H_ diff --git a/svf/include/SVFIR/SVFVariables.h b/svf/include/SVFIR/SVFVariables.h index 8711a7c2c2..2909d51ff2 100644 --- a/svf/include/SVFIR/SVFVariables.h +++ b/svf/include/SVFIR/SVFVariables.h @@ -83,13 +83,11 @@ class SVFVar : public GenericPAGNodeTy return InEdgeKindToSetMap; } - inline const SVFStmt::KindToSVFStmtMapTy& getOutEdgeKindToSetMap() const { return OutEdgeKindToSetMap; } - public: /// Standard constructor with ID, type and kind SVFVar(NodeID i, const SVFType* svfType, PNODEK k); @@ -104,7 +102,8 @@ class SVFVar : public GenericPAGNodeTy return type->isPointerTy(); } - /// Check if this variable represents constant data/metadata but not null pointer + /// Check if this variable represents constant data/metadata but not null + /// pointer virtual bool isConstDataOrAggDataButNotNullPtr() const { return false; @@ -136,7 +135,8 @@ class SVFVar : public GenericPAGNodeTy inline bool hasIncomingEdges(SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = InEdgeKindToSetMap.find(kind); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + InEdgeKindToSetMap.find(kind); if (it != InEdgeKindToSetMap.end()) return (!it->second.empty()); else @@ -145,7 +145,8 @@ class SVFVar : public GenericPAGNodeTy inline bool hasOutgoingEdges(SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = OutEdgeKindToSetMap.find(kind); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + OutEdgeKindToSetMap.find(kind); if (it != OutEdgeKindToSetMap.end()) return (!it->second.empty()); else @@ -153,42 +154,50 @@ class SVFVar : public GenericPAGNodeTy } /// Edge iterators - inline SVFStmt::SVFStmtSetTy::iterator getIncomingEdgesBegin(SVFStmt::PEDGEK kind) const + inline SVFStmt::SVFStmtSetTy::iterator getIncomingEdgesBegin( + SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = InEdgeKindToSetMap.find(kind); - assert(it!=InEdgeKindToSetMap.end() && "Edge kind not found"); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + InEdgeKindToSetMap.find(kind); + assert(it != InEdgeKindToSetMap.end() && "Edge kind not found"); return it->second.begin(); } - inline SVFStmt::SVFStmtSetTy::iterator getIncomingEdgesEnd(SVFStmt::PEDGEK kind) const + inline SVFStmt::SVFStmtSetTy::iterator getIncomingEdgesEnd( + SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = InEdgeKindToSetMap.find(kind); - assert(it!=InEdgeKindToSetMap.end() && "Edge kind not found"); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + InEdgeKindToSetMap.find(kind); + assert(it != InEdgeKindToSetMap.end() && "Edge kind not found"); return it->second.end(); } - inline SVFStmt::SVFStmtSetTy::iterator getOutgoingEdgesBegin(SVFStmt::PEDGEK kind) const + inline SVFStmt::SVFStmtSetTy::iterator getOutgoingEdgesBegin( + SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = OutEdgeKindToSetMap.find(kind); - assert(it!=OutEdgeKindToSetMap.end() && "Edge kind not found"); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + OutEdgeKindToSetMap.find(kind); + assert(it != OutEdgeKindToSetMap.end() && "Edge kind not found"); return it->second.begin(); } - inline SVFStmt::SVFStmtSetTy::iterator getOutgoingEdgesEnd(SVFStmt::PEDGEK kind) const + inline SVFStmt::SVFStmtSetTy::iterator getOutgoingEdgesEnd( + SVFStmt::PEDGEK kind) const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = OutEdgeKindToSetMap.find(kind); - assert(it!=OutEdgeKindToSetMap.end() && "Edge kind not found"); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + OutEdgeKindToSetMap.find(kind); + assert(it != OutEdgeKindToSetMap.end() && "Edge kind not found"); return it->second.end(); } //@} /// Type checking support for LLVM-style RTTI - static inline bool classof(const SVFVar *) + static inline bool classof(const SVFVar*) { return true; } - static inline bool classof(const GenericPAGNodeTy * node) + static inline bool classof(const GenericPAGNodeTy* node) { return isSVFVarKind(node->getNodeKind()); } @@ -207,7 +216,6 @@ class SVFVar : public GenericPAGNodeTy return false; } - private: /// Edge management methods //@{ @@ -228,12 +236,13 @@ class SVFVar : public GenericPAGNodeTy /// Check for incoming variable field GEP edges inline bool hasIncomingVariantGepEdge() const { - SVFStmt::KindToSVFStmtMapTy::const_iterator it = InEdgeKindToSetMap.find(SVFStmt::Gep); + SVFStmt::KindToSVFStmtMapTy::const_iterator it = + InEdgeKindToSetMap.find(SVFStmt::Gep); if (it != InEdgeKindToSetMap.end()) { - for(auto gep : it->second) + for (auto gep : it->second) { - if(SVFUtil::cast(gep)->isVariantFieldGep()) + if (SVFUtil::cast(gep)->isVariantFieldGep()) return true; } } @@ -248,19 +257,17 @@ class SVFVar : public GenericPAGNodeTy void dump() const; /// Stream operator overload for output - friend OutStream& operator<< (OutStream &o, const SVFVar &node) + friend OutStream& operator<<(OutStream& o, const SVFVar& node) { o << node.toString(); return o; } }; - - /* * Value (Pointer) variable */ -class ValVar: public SVFVar +class ValVar : public SVFVar { friend class GraphDBClient; @@ -289,7 +296,8 @@ class ValVar: public SVFVar //@} /// Constructor - ValVar(NodeID i, const SVFType* svfType, const ICFGNode* node, PNODEK ty = ValNode); + ValVar(NodeID i, const SVFType* svfType, const ICFGNode* node, + PNODEK ty = ValNode); /// Return name of a LLVM value inline const std::string getValueName() const { @@ -306,22 +314,22 @@ class ValVar: public SVFVar virtual const std::string toString() const; std::string getValVarNodeFieldsStmt() const; - }; /* * Memory Object variable */ -class ObjVar: public SVFVar +class ObjVar : public SVFVar { friend class GraphDBClient; protected: /// Constructor - ObjVar(NodeID i, const SVFType* svfType, PNODEK ty = ObjNode) : - SVFVar(i, svfType, ty) + ObjVar(NodeID i, const SVFType* svfType, PNODEK ty = ObjNode) + : SVFVar(i, svfType, ty) { } + public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -352,17 +360,15 @@ class ObjVar: public SVFVar virtual const std::string toString() const; std::string getObjVarNodeFieldsStmt() const; - }; - /** * @brief Class representing a function argument variable in the SVFIR * - * This class models function argument in the program analysis. It extends ValVar - * to specifically handle function argument. + * This class models function argument in the program analysis. It extends + * ValVar to specifically handle function argument. */ -class ArgValVar: public ValVar +class ArgValVar : public ValVar { friend class GraphDBClient; @@ -396,8 +402,8 @@ class ArgValVar: public ValVar //@} /// Constructor - ArgValVar(NodeID i, u32_t argNo, const ICFGNode* icn, const FunObjVar* callGraphNode, - const SVFType* svfType); + ArgValVar(NodeID i, u32_t argNo, const ICFGNode* icn, + const FunObjVar* callGraphNode, const SVFType* svfType); /// Return name of a LLVM value inline const std::string getValueName() const @@ -428,39 +434,38 @@ class ArgValVar: public ValVar virtual const std::string toString() const; }; - /* - * Gep Value (Pointer) variable, this variable can be dynamic generated for field sensitive analysis - * e.g. memcpy, temp gep value variable needs to be created - * Each Gep Value variable is connected to base value variable via gep edge + * Gep Value (Pointer) variable, this variable can be dynamic generated for + * field sensitive analysis e.g. memcpy, temp gep value variable needs to be + * created Each Gep Value variable is connected to base value variable via gep + * edge */ -class GepValVar: public ValVar +class GepValVar : public ValVar { friend class GraphDBClient; private: - AccessPath ap; // AccessPath - const ValVar* base; // base node + AccessPath ap; // AccessPath + const ValVar* base; // base node const SVFType* gepValType; NodeID llvmVarID; - public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ - static inline bool classof(const GepValVar *) + static inline bool classof(const GepValVar*) { return true; } - static inline bool classof(const ValVar * node) + static inline bool classof(const ValVar* node) { return node->getNodeKind() == SVFVar::GepValNode; } - static inline bool classof(const SVFVar *node) + static inline bool classof(const SVFVar* node) { return node->getNodeKind() == SVFVar::GepValNode; } - static inline bool classof(const GenericPAGNodeTy *node) + static inline bool classof(const GenericPAGNodeTy* node) { return node->getNodeKind() == SVFVar::GepValNode; } @@ -503,8 +508,7 @@ class GepValVar: public ValVar /// Return name of a LLVM value inline const std::string getValueName() const { - return getName() + "_" + - std::to_string(getConstantFieldIdx()); + return getName() + "_" + std::to_string(getConstantFieldIdx()); } virtual bool isPointer() const @@ -562,7 +566,8 @@ class BaseObjVar : public ObjVar private: ObjTypeInfo* typeInfo; - const ICFGNode* icfgNode; /// ICFGNode related to the creation of this object + const ICFGNode* + icfgNode; /// ICFGNode related to the creation of this object public: /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -590,7 +595,8 @@ class BaseObjVar : public ObjVar //@} /// Constructor - BaseObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node, PNODEK ty = BaseObjNode) + BaseObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node, + PNODEK ty = BaseObjNode) : ObjVar(i, ti->getType(), ty), typeInfo(ti), icfgNode(node) { } @@ -653,7 +659,6 @@ class BaseObjVar : public ObjVar return typeInfo->getMaxFieldOffsetLimit(); } - /// Return true if its field limit is 0 bool isFieldInsensitive() const { @@ -666,7 +671,6 @@ class BaseObjVar : public ObjVar typeInfo->setMaxFieldOffsetLimit(0); } - /// Set the memory object to be field sensitive (up to max field limit) void setFieldSensitive() { @@ -688,7 +692,6 @@ class BaseObjVar : public ObjVar return typeInfo->isConstantByteSize(); } - /// object attributes methods //@{ bool isFunction() const @@ -753,19 +756,16 @@ class BaseObjVar : public ObjVar } virtual const FunObjVar* getFunction() const; - }; - /* * Gep Obj variable, this is dynamic generated for field sensitive analysis * Each gep obj variable is one field of a BaseObjVar (base) */ -class GepObjVar: public ObjVar +class GepObjVar : public ObjVar { friend class GraphDBClient; - private: APOffset apOffset = 0; @@ -797,8 +797,8 @@ class GepObjVar: public ObjVar //@} /// Constructor - GepObjVar(const BaseObjVar* baseObj, NodeID i, - const APOffset& apOffset, PNODEK ty = GepObjNode) + GepObjVar(const BaseObjVar* baseObj, NodeID i, const APOffset& apOffset, + PNODEK ty = GepObjNode) : ObjVar(i, baseObj->getType(), ty), apOffset(apOffset), base(baseObj) { } @@ -821,8 +821,7 @@ class GepObjVar: public ObjVar } /// Return the type of this gep object - inline virtual const SVFType* getType() const; - + virtual const SVFType* getType() const; /// Return name of a LLVM value inline const std::string getValueName() const @@ -858,15 +857,13 @@ class GepObjVar: public ObjVar } }; - - /** * @brief Class representing a heap object variable in the SVFIR * - * This class models heap-allocated objects in the program analysis. It extends BaseObjVar - * to specifically handle heap memory locations. + * This class models heap-allocated objects in the program analysis. It extends + * BaseObjVar to specifically handle heap memory locations. */ -class HeapObjVar: public BaseObjVar +class HeapObjVar : public BaseObjVar { friend class GraphDBClient; @@ -901,8 +898,8 @@ class HeapObjVar: public BaseObjVar //@} /// Constructor - HeapObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node): - BaseObjVar(i, ti, node, HeapObjNode) + HeapObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node) + : BaseObjVar(i, ti, node, HeapObjNode) { } @@ -915,21 +912,20 @@ class HeapObjVar: public BaseObjVar virtual const std::string toString() const; }; - /** - * @brief Represents a stack-allocated object variable in the SVFIR (SVF Intermediate Representation) + * @brief Represents a stack-allocated object variable in the SVFIR (SVF + * Intermediate Representation) * @inherits BaseObjVar * * This class models variables that are allocated on the stack in the program. - * It provides type checking functionality through LLVM-style RTTI (Runtime Type Information) - * methods like classof. + * It provides type checking functionality through LLVM-style RTTI (Runtime Type + * Information) methods like classof. */ -class StackObjVar: public BaseObjVar +class StackObjVar : public BaseObjVar { friend class GraphDBClient; - public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -960,8 +956,8 @@ class StackObjVar: public BaseObjVar //@} /// Constructor - StackObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node): - BaseObjVar(i, ti, node, StackObjNode) + StackObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node) + : BaseObjVar(i, ti, node, StackObjNode) { } @@ -974,7 +970,6 @@ class StackObjVar: public BaseObjVar virtual const std::string toString() const; }; - class CallGraphNode; class FunObjVar : public BaseObjVar @@ -984,13 +979,12 @@ class FunObjVar : public BaseObjVar friend class GraphDBClient; protected: - - inline void updateExitBlock(SVFBasicBlock *bb) + inline void updateExitBlock(SVFBasicBlock* bb) { exitBlock = bb; } - inline void setLoopAndDomInfo(SVFLoopAndDomInfo *ld) + inline void setLoopAndDomInfo(SVFLoopAndDomInfo* ld) { loopAndDom = ld; } @@ -998,7 +992,7 @@ class FunObjVar : public BaseObjVar { return isNotRet; } - inline const std::vector &getArgs() const + inline const std::vector& getArgs() const { return allArgs; } @@ -1010,21 +1004,28 @@ class FunObjVar : public BaseObjVar typedef BasicBlockGraph::IDToNodeMapTy::const_iterator const_bb_iterator; - private: - bool isDecl; /// return true if this function does not have a body - bool intrinsic; /// return true if this function is an intrinsic function (e.g., llvm.dbg), which does not reside in the application code - bool isAddrTaken; /// return true if this function is address-taken (for indirect call purposes) - bool isUncalled; /// return true if this function is never called - bool isNotRet; /// return true if this function never returns - bool supVarArg; /// return true if this function supports variable arguments - const SVFFunctionType* funcType; /// FunctionType, which is different from the type (PointerType) of this SVF Function - SVFLoopAndDomInfo* loopAndDom; /// the loop and dominate information - const FunObjVar * realDefFun; /// the definition of a function across multiple modules + bool isDecl; /// return true if this function does not have a body + bool intrinsic; /// return true if this function is an intrinsic function + /// (e.g., llvm.dbg), which does not reside in the + /// application code + bool isAddrTaken; /// return true if this function is address-taken (for + /// indirect call purposes) + bool isUncalled; /// return true if this function is never called + bool isNotRet; /// return true if this function never returns + bool supVarArg; /// return true if this function supports variable arguments + const SVFFunctionType* + funcType; /// FunctionType, which is different from the type + /// (PointerType) of this SVF Function + SVFLoopAndDomInfo* loopAndDom; /// the loop and dominate information + const FunObjVar* + realDefFun; /// the definition of a function across multiple modules BasicBlockGraph* bbGraph; /// the basic block graph of this function - std::vector allArgs; /// all formal arguments of this function - const SVFBasicBlock *exitBlock; /// a 'single' basic block having no successors and containing return instruction in a function - + std::vector + allArgs; /// all formal arguments of this function + const SVFBasicBlock* + exitBlock; /// a 'single' basic block having no successors and + /// containing return instruction in a function public: /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -1058,25 +1059,27 @@ class FunObjVar : public BaseObjVar /// Constructor FunObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node); - virtual ~FunObjVar() { delete loopAndDom; delete bbGraph; } - void initFunObjVar(bool decl, bool intrinc, bool addr, bool uncalled, bool notret, bool vararg, const SVFFunctionType *ft, - SVFLoopAndDomInfo *ld, const FunObjVar *real, BasicBlockGraph *bbg, - const std::vector &allarg, const SVFBasicBlock *exit); + void initFunObjVar(bool decl, bool intrinc, bool addr, bool uncalled, + bool notret, bool vararg, const SVFFunctionType* ft, + SVFLoopAndDomInfo* ld, const FunObjVar* real, + BasicBlockGraph* bbg, + const std::vector& allarg, + const SVFBasicBlock* exit); - void setRelDefFun(const FunObjVar *real) + void setRelDefFun(const FunObjVar* real) { realDefFun = real; } - virtual const FunObjVar*getFunction() const; + virtual const FunObjVar* getFunction() const; - inline void addArgument(const ArgValVar *arg) + inline void addArgument(const ArgValVar* arg) { allArgs.push_back(arg); } @@ -1107,7 +1110,7 @@ class FunObjVar : public BaseObjVar inline bool hasReturn() const { - return !isNotRet; + return !isNotRet; } /// Returns the FunctionType @@ -1132,9 +1135,10 @@ class FunObjVar : public BaseObjVar return loopAndDom->getReachableBBs(); } - inline void getExitBlocksOfLoop(const SVFBasicBlock* bb, BBList& exitbbs) const + inline void getExitBlocksOfLoop(const SVFBasicBlock* bb, + BBList& exitbbs) const { - return loopAndDom->getExitBlocksOfLoop(bb,exitbbs); + return loopAndDom->getExitBlocksOfLoop(bb, exitbbs); } inline bool hasLoopInfo(const SVFBasicBlock* bb) const @@ -1154,15 +1158,15 @@ class FunObjVar : public BaseObjVar inline bool loopContainsBB(const BBList& lp, const SVFBasicBlock* bb) const { - return loopAndDom->loopContainsBB(lp,bb); + return loopAndDom->loopContainsBB(lp, bb); } - inline const Map& getDomTreeMap() const + inline const Map& getDomTreeMap() const { return loopAndDom->getDomTreeMap(); } - inline const Map& getDomFrontierMap() const + inline const Map& getDomFrontierMap() const { return loopAndDom->getDomFrontierMap(); } @@ -1172,19 +1176,21 @@ class FunObjVar : public BaseObjVar return loopAndDom->isLoopHeader(bb); } - inline bool dominate(const SVFBasicBlock* bbKey, const SVFBasicBlock* bbValue) const + inline bool dominate(const SVFBasicBlock* bbKey, + const SVFBasicBlock* bbValue) const { - return loopAndDom->dominate(bbKey,bbValue); + return loopAndDom->dominate(bbKey, bbValue); } - inline bool postDominate(const SVFBasicBlock* bbKey, const SVFBasicBlock* bbValue) const + inline bool postDominate(const SVFBasicBlock* bbKey, + const SVFBasicBlock* bbValue) const { - return loopAndDom->postDominate(bbKey,bbValue); + return loopAndDom->postDominate(bbKey, bbValue); } inline const FunObjVar* getDefFunForMultipleModule() const { - if(realDefFun==nullptr) + if (realDefFun == nullptr) return this; return realDefFun; } @@ -1211,33 +1217,35 @@ class FunObjVar : public BaseObjVar inline const SVFBasicBlock* getEntryBlock() const { - assert(hasBasicBlock() && "function does not have any Basicblock, external function?"); - assert(bbGraph->begin()->second->getInEdges().size() == 0 && "the first basic block is not entry block"); + assert(hasBasicBlock() && + "function does not have any Basicblock, external function?"); + assert(bbGraph->begin()->second->getInEdges().size() == 0 && + "the first basic block is not entry block"); return bbGraph->begin()->second; } inline const SVFBasicBlock* getExitBB() const { - assert(hasBasicBlock() && "function does not have any Basicblock, external function?"); + assert(hasBasicBlock() && + "function does not have any Basicblock, external function?"); assert(exitBlock && "must have an exitBlock"); return exitBlock; } - inline void setExitBlock(SVFBasicBlock *bb) + inline void setExitBlock(SVFBasicBlock* bb) { assert(!exitBlock && "have already set exit Basicblock!"); exitBlock = bb; } - u32_t inline arg_size() const { return allArgs.size(); } - inline const ArgValVar* getArg(u32_t idx) const + inline const ArgValVar* getArg(u32_t idx) const { - assert (idx < allArgs.size() && "getArg() out of range!"); + assert(idx < allArgs.size() && "getArg() out of range!"); return allArgs[idx]; } inline const SVFBasicBlock* front() const @@ -1247,7 +1255,8 @@ class FunObjVar : public BaseObjVar inline const SVFBasicBlock* back() const { - assert(hasBasicBlock() && "function does not have any Basicblock, external function?"); + assert(hasBasicBlock() && + "function does not have any Basicblock, external function?"); /// Carefully! 'back' is just the last basic block of function, /// but not necessarily a exit basic block /// more refer to: https://github.com/SVF-tools/SVF/pull/1262 @@ -1313,8 +1322,8 @@ class FunValVar : public ValVar } /// Constructor - FunValVar(NodeID i, const ICFGNode* icn, const FunObjVar* cgn, const SVFType* svfType); - + FunValVar(NodeID i, const ICFGNode* icn, const FunObjVar* cgn, + const SVFType* svfType); virtual bool isPointer() const { @@ -1324,13 +1333,10 @@ class FunValVar : public ValVar virtual const std::string toString() const; }; - - class GlobalValVar : public ValVar { friend class GraphDBClient; - public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -1363,7 +1369,6 @@ class GlobalValVar : public ValVar type = svfType; } - virtual const std::string toString() const; }; @@ -1371,7 +1376,6 @@ class ConstDataValVar : public ValVar { friend class GraphDBClient; - public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -1402,7 +1406,6 @@ class ConstDataValVar : public ValVar PNODEK ty = ConstDataValNode) : ValVar(i, svfType, icn, ty) { - } virtual bool isConstDataOrAggData() const @@ -1422,6 +1425,7 @@ class BlackHoleValVar : public ConstDataValVar { friend class GraphDBClient; + public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -1452,10 +1456,10 @@ class BlackHoleValVar : public ConstDataValVar //@} /// Constructor - BlackHoleValVar(NodeID i, const SVFType* svfType, PNODEK ty = BlackHoleValNode) - : ConstDataValVar(i, nullptr, svfType, ty) + BlackHoleValVar(NodeID i, const SVFType* svfType, + PNODEK ty = BlackHoleValNode) + : ConstDataValVar(i, nullptr, svfType, ty) { - } virtual bool isConstDataOrAggDataButNotNullPtr() const @@ -1512,8 +1516,8 @@ class ConstFPValVar : public ConstDataValVar } /// Constructor - ConstFPValVar(NodeID i, double dv, - const ICFGNode* icn, const SVFType* svfType) + ConstFPValVar(NodeID i, double dv, const ICFGNode* icn, + const SVFType* svfType) : ConstDataValVar(i, icn, svfType, ConstFPValNode), dval(dv) { } @@ -1526,7 +1530,6 @@ class ConstIntValVar : public ConstDataValVar friend class GraphDBClient; - private: u64_t zval; s64_t sval; @@ -1565,17 +1568,16 @@ class ConstIntValVar : public ConstDataValVar return sval; } - u64_t getZExtValue() const { return zval; } /// Constructor - ConstIntValVar(NodeID i, s64_t sv, u64_t zv, const ICFGNode* icn, const SVFType* svfType) - : ConstDataValVar(i, icn, svfType, ConstIntValNode), zval(zv), sval(sv) + ConstIntValVar(NodeID i, s64_t sv, u64_t zv, const ICFGNode* icn, + const SVFType* svfType) + : ConstDataValVar(i, icn, svfType, ConstIntValNode), zval(zv), sval(sv) { - } virtual const std::string toString() const; }; @@ -1615,9 +1617,8 @@ class ConstNullPtrValVar : public ConstDataValVar /// Constructor ConstNullPtrValVar(NodeID i, const ICFGNode* icn, const SVFType* svfType) - : ConstDataValVar(i, icn, svfType, ConstNullptrValNode) + : ConstDataValVar(i, icn, svfType, ConstNullptrValNode) { - } virtual bool isConstDataOrAggDataButNotNullPtr() const @@ -1632,7 +1633,6 @@ class GlobalObjVar : public BaseObjVar { friend class GraphDBClient; - public: /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ @@ -1664,12 +1664,11 @@ class GlobalObjVar : public BaseObjVar /// Constructor GlobalObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node, - PNODEK ty = GlobalObjNode): BaseObjVar(i, ti, node, ty) + PNODEK ty = GlobalObjNode) + : BaseObjVar(i, ti, node, ty) { - } - virtual const std::string toString() const; }; @@ -1707,7 +1706,8 @@ class ConstDataObjVar : public BaseObjVar //@} /// Constructor - ConstDataObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node, PNODEK ty = ConstDataObjNode) + ConstDataObjVar(NodeID i, ObjTypeInfo* ti, const ICFGNode* node, + PNODEK ty = ConstDataObjNode) : BaseObjVar(i, ti, node, ty) { } @@ -1730,7 +1730,6 @@ class ConstFPObjVar : public ConstDataObjVar friend class GraphDBClient; - private: float dval; @@ -1781,7 +1780,6 @@ class ConstFPObjVar : public ConstDataObjVar return dval; } - virtual const std::string toString() const; }; @@ -1790,8 +1788,6 @@ class ConstIntObjVar : public ConstDataObjVar friend class GraphDBClient; - - private: u64_t zval; s64_t sval; @@ -1836,7 +1832,6 @@ class ConstIntObjVar : public ConstDataObjVar return sval; } - u64_t getZExtValue() const { return zval; @@ -1844,7 +1839,8 @@ class ConstIntObjVar : public ConstDataObjVar //@} /// Constructor - ConstIntObjVar(NodeID i, s64_t sv, u64_t zv, ObjTypeInfo* ti, const ICFGNode* node) + ConstIntObjVar(NodeID i, s64_t sv, u64_t zv, ObjTypeInfo* ti, + const ICFGNode* node) : ConstDataObjVar(i, ti, node, ConstIntObjNode), zval(zv), sval(sv) { } @@ -1944,9 +1940,9 @@ class RetValPN : public ValVar } //@} - /// Constructor - RetValPN(NodeID i, const FunObjVar* node, const SVFType* svfType, const ICFGNode* icn); + RetValPN(NodeID i, const FunObjVar* node, const SVFType* svfType, + const ICFGNode* icn); inline const FunObjVar* getCallGraphNode() const { @@ -1976,6 +1972,7 @@ class VarArgValPN : public ValVar { callGraphNode = node; } + private: const FunObjVar* callGraphNode; @@ -2004,7 +2001,8 @@ class VarArgValPN : public ValVar //@} /// Constructor - VarArgValPN(NodeID i, const FunObjVar* node, const SVFType* svfType, const ICFGNode* icn) + VarArgValPN(NodeID i, const FunObjVar* node, const SVFType* svfType, + const ICFGNode* icn) : ValVar(i, svfType, icn, VarargValNode), callGraphNode(node) { assert((node->isDeclaration() || icn) && @@ -2026,7 +2024,7 @@ class VarArgValPN : public ValVar /* * Dummy variable without any LLVM value */ -class DummyValVar: public ValVar +class DummyValVar : public ValVar { friend class GraphDBClient; @@ -2055,7 +2053,8 @@ class DummyValVar: public ValVar //@} /// Constructor - DummyValVar(NodeID i, const ICFGNode* node, const SVFType* svfType = SVFType::getSVFPtrType()) + DummyValVar(NodeID i, const ICFGNode* node, + const SVFType* svfType = SVFType::getSVFPtrType()) : ValVar(i, svfType, node, DummyValNode) { } @@ -2078,7 +2077,7 @@ class DummyValVar: public ValVar * Represents an LLVM intrinsic call instruction (e.g. llvm.dbg.declare). * These are collected into valSyms but have no corresponding ICFGNode. */ -class IntrinsicValVar: public ValVar +class IntrinsicValVar : public ValVar { friend class GraphDBClient; @@ -2125,7 +2124,7 @@ class IntrinsicValVar: public ValVar * position-independent code (PIC), or control-flow integrity (CFI). * They have no corresponding ICFGNode. */ -class AsmPCValVar: public ValVar +class AsmPCValVar : public ValVar { friend class GraphDBClient; @@ -2152,7 +2151,9 @@ class AsmPCValVar: public ValVar } AsmPCValVar(NodeID i, const SVFType* svfType) - : ValVar(i, svfType, nullptr, AsmPCValNode) {} + : ValVar(i, svfType, nullptr, AsmPCValNode) + { + } inline const std::string getValueName() const { @@ -2164,12 +2165,11 @@ class AsmPCValVar: public ValVar /* * Dummy object variable */ -class DummyObjVar: public BaseObjVar +class DummyObjVar : public BaseObjVar { friend class GraphDBClient; - public: //@{ Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const DummyObjVar*) diff --git a/svf/include/WPA/Andersen.h b/svf/include/WPA/Andersen.h index 84860fa946..d7c403c2c3 100644 --- a/svf/include/WPA/Andersen.h +++ b/svf/include/WPA/Andersen.h @@ -28,20 +28,21 @@ * * The field-sensitive implementation is improved based on * - * Yuxiang Lei and Yulei Sui. "Fast and Precise Handling of Positive Weight Cycles for Field-sensitive Pointer Analysis". - * 26th International Static Analysis Symposium (SAS'19) + * Yuxiang Lei and Yulei Sui. "Fast and Precise Handling of Positive Weight + * Cycles for Field-sensitive Pointer Analysis". 26th International Static + * Analysis Symposium (SAS'19) */ #ifndef INCLUDE_WPA_ANDERSEN_H_ #define INCLUDE_WPA_ANDERSEN_H_ +#include "Graphs/ConsG.h" #include "MemoryModel/PTATY.h" #include "MemoryModel/PointerAnalysisImpl.h" #include "MemoryModel/PointsTo.h" -#include "WPA/WPASolver.h" -#include "Graphs/ConsG.h" #include "Util/GeneralType.h" #include "Util/Options.h" +#include "WPA/WPASolver.h" namespace SVF { @@ -54,16 +55,16 @@ class SVFIR; */ typedef WPASolver WPAConstraintSolver; -class AndersenBase: public WPAConstraintSolver, public BVDataPTAImpl +class AndersenBase : public WPAConstraintSolver, public BVDataPTAImpl { public: typedef OrderedMap CallSite2DummyValPN; public: - /// Constructor - AndersenBase(SVFIR* _pag, PTATY type = PTATY::Andersen_BASE, bool alias_check = true) - : BVDataPTAImpl(_pag, type, alias_check), consCG(nullptr) + AndersenBase(SVFIR* _pag, PTATY type = PTATY::Andersen_BASE, + bool alias_check = true) + : BVDataPTAImpl(_pag, type, alias_check), consCG(nullptr) { iterationForPrintStat = OnTheFlyIterBudgetForStat; } @@ -90,31 +91,34 @@ class AndersenBase: public WPAConstraintSolver, public BVDataPTAImpl virtual bool updateCallGraph(const CallSiteToFunPtrMap&) override; /// Update thread call graph - virtual bool updateThreadCallGraph(const CallSiteToFunPtrMap&, NodePairSet&); + virtual bool updateThreadCallGraph(const CallSiteToFunPtrMap&, + NodePairSet&); /// Connect formal and actual parameters for indirect forksites - virtual void connectCaller2ForkedFunParams(const CallICFGNode* cs, const FunObjVar* F, - NodePairSet& cpySrcNodes); + virtual void connectCaller2ForkedFunParams(const CallICFGNode* cs, + const FunObjVar* F, + NodePairSet& cpySrcNodes); /// Connect formal and actual parameters for indirect callsites - virtual void connectCaller2CalleeParams(const CallICFGNode* cs, const FunObjVar* F, + virtual void connectCaller2CalleeParams(const CallICFGNode* cs, + const FunObjVar* F, NodePairSet& cpySrcNodes); /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ - static inline bool classof(const AndersenBase *) + static inline bool classof(const AndersenBase*) { return true; } - static inline bool classof(const PointerAnalysis *pta) + static inline bool classof(const PointerAnalysis* pta) { - return ( pta->getAnalysisTy() == PTATY::Andersen_BASE - || pta->getAnalysisTy() == PTATY::Andersen_WPA - || pta->getAnalysisTy() == PTATY::AndersenWaveDiff_WPA - || pta->getAnalysisTy() == PTATY::AndersenSCD_WPA - || pta->getAnalysisTy() == PTATY::AndersenSFR_WPA - || pta->getAnalysisTy() == PTATY::TypeCPP_WPA - || pta->getAnalysisTy() == PTATY::Steensgaard_WPA); + return (pta->getAnalysisTy() == PTATY::Andersen_BASE || + pta->getAnalysisTy() == PTATY::Andersen_WPA || + pta->getAnalysisTy() == PTATY::AndersenWaveDiff_WPA || + pta->getAnalysisTy() == PTATY::AndersenSCD_WPA || + pta->getAnalysisTy() == PTATY::AndersenSFR_WPA || + pta->getAnalysisTy() == PTATY::TypeCPP_WPA || + pta->getAnalysisTy() == PTATY::Steensgaard_WPA); } //@} @@ -154,11 +158,11 @@ class AndersenBase: public WPAConstraintSolver, public BVDataPTAImpl /// Statistics //@{ - static u32_t numOfProcessedAddr; /// Number of processed Addr edge - static u32_t numOfProcessedCopy; /// Number of processed Copy edge - static u32_t numOfProcessedGep; /// Number of processed Gep edge - static u32_t numOfProcessedLoad; /// Number of processed Load edge - static u32_t numOfProcessedStore; /// Number of processed Store edge + static u32_t numOfProcessedAddr; /// Number of processed Addr edge + static u32_t numOfProcessedCopy; /// Number of processed Copy edge + static u32_t numOfProcessedGep; /// Number of processed Gep edge + static u32_t numOfProcessedLoad; /// Number of processed Load edge + static u32_t numOfProcessedStore; /// Number of processed Store edge static u32_t numOfSfrs; static u32_t numOfFieldExpand; @@ -177,33 +181,31 @@ class AndersenBase: public WPAConstraintSolver, public BVDataPTAImpl /// Constraint Graph ConstraintGraph* consCG; CallSite2DummyValPN - callsite2DummyValPN; ///< Map an instruction to a dummy obj which + callsite2DummyValPN; ///< Map an instruction to a dummy obj which ///< created at an indirect callsite, which invokes ///< a heap allocator - void heapAllocatorViaIndCall(const CallICFGNode* cs, NodePairSet& cpySrcNodes); + void heapAllocatorViaIndCall(const CallICFGNode* cs, + NodePairSet& cpySrcNodes); }; /*! * Inclusion-based Pointer Analysis */ -class Andersen: public AndersenBase +class Andersen : public AndersenBase { - public: typedef SCCDetection CGSCC; /// Constructor - Andersen(SVFIR* _pag, PTATY type = PTATY::Andersen_WPA, bool alias_check = true) - : AndersenBase(_pag, type, alias_check) + Andersen(SVFIR* _pag, PTATY type = PTATY::Andersen_WPA, + bool alias_check = true) + : AndersenBase(_pag, type, alias_check) { } /// Destructor - virtual ~Andersen() - { - - } + virtual ~Andersen() {} /// Initialize analysis virtual void initialize(); @@ -222,16 +224,16 @@ class Andersen: public AndersenBase /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ - static inline bool classof(const Andersen *) + static inline bool classof(const Andersen*) { return true; } - static inline bool classof(const PointerAnalysis *pta) + static inline bool classof(const PointerAnalysis* pta) { - return (pta->getAnalysisTy() == PTATY::Andersen_WPA - || pta->getAnalysisTy() == PTATY::AndersenWaveDiff_WPA - || pta->getAnalysisTy() == PTATY::AndersenSCD_WPA - || pta->getAnalysisTy() == PTATY::AndersenSFR_WPA); + return (pta->getAnalysisTy() == PTATY::Andersen_WPA || + pta->getAnalysisTy() == PTATY::AndersenWaveDiff_WPA || + pta->getAnalysisTy() == PTATY::AndersenSCD_WPA || + pta->getAnalysisTy() == PTATY::AndersenSFR_WPA); } //@} @@ -249,10 +251,9 @@ class Andersen: public AndersenBase { id = sccRepNode(id); ptd = sccRepNode(ptd); - return getPTDataTy()->unionPts(id,ptd); + return getPTDataTy()->unionPts(id, ptd); } - void dumpTopLevelPtsTo(); void setDetectPWC(bool flag) @@ -261,8 +262,10 @@ class Andersen: public AndersenBase } protected: - - CallSite2DummyValPN callsite2DummyValPN; ///< Map an instruction to a dummy obj which created at an indirect callsite, which invokes a heap allocator + CallSite2DummyValPN + callsite2DummyValPN; ///< Map an instruction to a dummy obj which + ///< created at an indirect callsite, which invokes + ///< a heap allocator /// Handle diff points-to set. virtual inline void computeDiffPts(NodeID id) @@ -270,7 +273,8 @@ class Andersen: public AndersenBase if (Options::DiffPts()) { NodeID rep = sccRepNode(id); - getDiffPTDataTy()->computeDiffPts(rep, getDiffPTDataTy()->getPts(rep)); + getDiffPTDataTy()->computeDiffPts(rep, + getDiffPTDataTy()->getPts(rep)); } } virtual inline const PointsTo& getDiffPts(NodeID id) @@ -331,9 +335,9 @@ class Andersen: public AndersenBase } /// Merge sub node to its rep - virtual void mergeNodeToRep(NodeID nodeId,NodeID newRepId); + virtual void mergeNodeToRep(NodeID nodeId, NodeID newRepId); - virtual bool mergeSrcToTgt(NodeID srcId,NodeID tgtId); + virtual bool mergeSrcToTgt(NodeID srcId, NodeID tgtId); /// Merge sub node in a SCC cycle to their rep node //@{ @@ -349,31 +353,32 @@ class Andersen: public AndersenBase //@} /// Updates subnodes of its rep, and rep node of its subs - void updateNodeRepAndSubs(NodeID nodeId,NodeID newRepId); + void updateNodeRepAndSubs(NodeID nodeId, NodeID newRepId); /// SCC detection virtual NodeStack& SCCDetect(); - - /// Sanitize pts for field insensitive objects void sanitizePts() { - for(ConstraintGraph::iterator it = consCG->begin(), eit = consCG->end(); it!=eit; ++it) + for (ConstraintGraph::iterator it = consCG->begin(), + eit = consCG->end(); + it != eit; ++it) { const PointsTo& pts = getPts(it->first); NodeBS fldInsenObjs; for (NodeID o : pts) { - if(isFieldInsensitive(o)) + if (isFieldInsensitive(o)) fldInsenObjs.set(o); } for (NodeID o : fldInsenObjs) { - const NodeBS &allFields = consCG->getAllFieldsObjVars(o); - for (NodeID f : allFields) addPts(it->first, f); + const NodeBS& allFields = consCG->getAllFieldsObjVars(o); + for (NodeID f : allFields) + addPts(it->first, f); } } } @@ -389,8 +394,6 @@ class Andersen: public AndersenBase virtual void cluster(void) const; }; - - /** * Wave propagation with diff points-to set. */ @@ -398,18 +401,23 @@ class AndersenWaveDiff : public Andersen { private: - static AndersenWaveDiff* diffWave; // static instance public: - AndersenWaveDiff(SVFIR* _pag, PTATY type = PTATY::AndersenWaveDiff_WPA, bool alias_check = true): Andersen(_pag, type, alias_check) {} + AndersenWaveDiff(SVFIR* _pag, PTATY type = PTATY::AndersenWaveDiff_WPA, + bool alias_check = true) + : Andersen(_pag, type, alias_check) + { + } - /// Create an singleton instance directly instead of invoking llvm pass manager + /// Create an singleton instance directly instead of invoking llvm pass + /// manager static AndersenWaveDiff* createAndersenWaveDiff(SVFIR* _pag) { - if(diffWave==nullptr) + if (diffWave == nullptr) { - diffWave = new AndersenWaveDiff(_pag, PTATY::AndersenWaveDiff_WPA, false); + diffWave = + new AndersenWaveDiff(_pag, PTATY::AndersenWaveDiff_WPA, false); diffWave->analyze(); return diffWave; } @@ -430,6 +438,32 @@ class AndersenWaveDiff : public Andersen virtual bool handleStore(NodeID id, const ConstraintEdge* store); }; +/** + * Detect and collapse PWC nodes produced by processing gep edges, under the + * constraint of field limit. + */ +inline void Andersen::collapsePWCNode(NodeID nodeId) +{ + // If a node is a PWC node, collapse all its points-to target. + // collapseNodePts() may change the points-to set of the nodes which have + // been processed before, in this case, we may need to re-do the analysis. + if (consCG->isPWCNode(nodeId) && collapseNodePts(nodeId)) + reanalyze = true; +} + +inline void Andersen::collapseFields() +{ + while (consCG->hasNodesToBeCollapsed()) + { + NodeID node = consCG->getNextCollapseNode(); + // collapseField() may change the points-to set of the nodes which have + // been processed before, in this case, we may need to re-do the + // analysis. + if (collapseField(node)) + reanalyze = true; + } +} + } // End namespace SVF #endif /* INCLUDE_WPA_ANDERSEN_H_ */ diff --git a/svf/include/WPA/TypeAnalysis.h b/svf/include/WPA/TypeAnalysis.h index f29156b56e..39e61895c8 100644 --- a/svf/include/WPA/TypeAnalysis.h +++ b/svf/include/WPA/TypeAnalysis.h @@ -1,4 +1,5 @@ -//===- TypeAnalysis.h -- Fast type-based analysis without pointer analysis---------// +//===- TypeAnalysis.h -- Fast type-based analysis without pointer +//analysis---------// // // SVF: Static Value-Flow Analysis // @@ -40,20 +41,15 @@ class CallEdgeMap; class CallSiteToFunPtrMap; class SVFIR; -class TypeAnalysis: public AndersenBase +class TypeAnalysis : public AndersenBase { public: /// Constructor - TypeAnalysis(SVFIR* pag) - : AndersenBase(pag, TypeCPP_WPA) - { - } + TypeAnalysis(SVFIR* pag) : AndersenBase(pag, TypeCPP_WPA) {} /// Destructor - virtual ~TypeAnalysis() - { - } + virtual ~TypeAnalysis() {} /// Type analysis void analyze() override; @@ -62,7 +58,7 @@ class TypeAnalysis: public AndersenBase void initialize() override; /// Finalize analysis - virtual inline void finalize() override; + void finalize() override; /// Add copy edge on constraint graph inline bool addCopyEdge(NodeID src, NodeID dst) override @@ -72,18 +68,19 @@ class TypeAnalysis: public AndersenBase } /// Resolve callgraph based on CHA - void callGraphSolveBasedOnCHA(const CallSiteToFunPtrMap& callsites, CallEdgeMap& newEdges); + void callGraphSolveBasedOnCHA(const CallSiteToFunPtrMap& callsites, + CallEdgeMap& newEdges); /// Statistics of CHA and callgraph void dumpCHAStats(); /// Methods for support type inquiry through isa, cast, and dyn_cast: //@{ - static inline bool classof(const TypeAnalysis *) + static inline bool classof(const TypeAnalysis*) { return true; } - static inline bool classof(const PointerAnalysis *pta) + static inline bool classof(const PointerAnalysis* pta) { return (pta->getAnalysisTy() == TypeCPP_WPA); } diff --git a/svf/lib/CFL/GrammarBuilder.cpp b/svf/lib/CFL/GrammarBuilder.cpp index 3a399e60f8..88323640e2 100644 --- a/svf/lib/CFL/GrammarBuilder.cpp +++ b/svf/lib/CFL/GrammarBuilder.cpp @@ -27,10 +27,10 @@ * Author: Pei Xu */ -#include #include -#include #include +#include +#include #include "CFL/CFGrammar.h" #include "CFL/GrammarBuilder.h" @@ -42,7 +42,8 @@ const inline std::string GrammarBuilder::parseProductionsString() const std::ifstream textFile(fileName); if (!textFile.is_open()) { - std::cerr << "Can't open CFL grammar file `" << fileName << "`" << std::endl; + std::cerr << "Can't open CFL grammar file `" << fileName << "`" + << std::endl; abort(); } @@ -85,7 +86,8 @@ const inline std::string GrammarBuilder::parseProductionsString() const size_t productionsPos = lines.find("Productions:"); if (productionsPos != std::string::npos) { - lines = lines.substr(productionsPos + std::string("Productions:").length()); + lines = + lines.substr(productionsPos + std::string("Productions:").length()); } // Parse `symbolString` to insert symbols @@ -107,8 +109,8 @@ const inline std::string GrammarBuilder::parseProductionsString() const return lines; } - -const inline std::vector GrammarBuilder::loadWordProductions() const +const inline std::vector GrammarBuilder::loadWordProductions() + const { size_t pos = 0; std::string lines = parseProductionsString(); @@ -155,14 +157,16 @@ GrammarBase* GrammarBuilder::build() const { // Extract and strip RHS (right-hand side) and LHS (left-hand side) std::string RHS = stripSpace(wordProd.substr(0, pos)); - std::string LHS = stripSpace(wordProd.substr(pos + delimiter1.size())); + std::string LHS = + stripSpace(wordProd.substr(pos + delimiter1.size())); // Insert RHS symbol into grammar GrammarBase::Symbol RHSSymbol = grammar->insertSymbol(RHS); prod.push_back(RHSSymbol); // Ensure RHS symbol exists in raw productions - if (grammar->getRawProductions().find(RHSSymbol) == grammar->getRawProductions().end()) + if (grammar->getRawProductions().find(RHSSymbol) == + grammar->getRawProductions().end()) { grammar->getRawProductions().insert({RHSSymbol, {}}); } @@ -195,5 +199,4 @@ GrammarBase* GrammarBuilder::build() const return grammar; } - -} +} // namespace SVF diff --git a/svf/lib/MemoryModel/PointsTo.cpp b/svf/lib/MemoryModel/PointsTo.cpp index 6170c5d3d8..16b680c03e 100644 --- a/svf/lib/MemoryModel/PointsTo.cpp +++ b/svf/lib/MemoryModel/PointsTo.cpp @@ -12,9 +12,9 @@ #include #include -#include "Util/Options.h" #include "MemoryModel/PointsTo.h" #include "SVFIR/SVFValue.h" +#include "Util/Options.h" namespace SVF { @@ -26,44 +26,60 @@ PointsTo::PointsTo() : type(Options::PtType()), nodeMapping(currentBestNodeMapping), reverseNodeMapping(currentBestReverseNodeMapping) { - if (type == SBV) new (&sbv) SparseBitVector<>(); - else if (type == CBV) new (&cbv) CoreBitVector(); - else if (type == BV) new (&bv) BitVector(); - else assert(false && "PointsTo::PointsTo: unknown type"); + if (type == SBV) + new (&sbv) SparseBitVector<>(); + else if (type == CBV) + new (&cbv) CoreBitVector(); + else if (type == BV) + new (&bv) BitVector(); + else + assert(false && "PointsTo::PointsTo: unknown type"); } -PointsTo::PointsTo(const PointsTo &pt) +PointsTo::PointsTo(const PointsTo& pt) : type(pt.type), nodeMapping(pt.nodeMapping), reverseNodeMapping(pt.reverseNodeMapping) { - if (type == SBV) new (&sbv) SparseBitVector<>(pt.sbv); - else if (type == CBV) new (&cbv) CoreBitVector(pt.cbv); - else if (type == BV) new (&bv) BitVector(pt.bv); - else assert(false && "PointsTo::PointsTo&: unknown type"); + if (type == SBV) + new (&sbv) SparseBitVector<>(pt.sbv); + else if (type == CBV) + new (&cbv) CoreBitVector(pt.cbv); + else if (type == BV) + new (&bv) BitVector(pt.bv); + else + assert(false && "PointsTo::PointsTo&: unknown type"); } -PointsTo::PointsTo(PointsTo &&pt) -noexcept : type(pt.type), nodeMapping(std::move(pt.nodeMapping)), - reverseNodeMapping(std::move(pt.reverseNodeMapping)) +PointsTo::PointsTo(PointsTo&& pt) noexcept + : type(pt.type), nodeMapping(std::move(pt.nodeMapping)), + reverseNodeMapping(std::move(pt.reverseNodeMapping)) { - if (type == SBV) new (&sbv) SparseBitVector<>(std::move(pt.sbv)); - else if (type == CBV) new (&cbv) CoreBitVector(std::move(pt.cbv)); - else if (type == BV) new (&bv) BitVector(std::move(pt.bv)); - else assert(false && "PointsTo::PointsTo&&: unknown type"); + if (type == SBV) + new (&sbv) SparseBitVector<>(std::move(pt.sbv)); + else if (type == CBV) + new (&cbv) CoreBitVector(std::move(pt.cbv)); + else if (type == BV) + new (&bv) BitVector(std::move(pt.bv)); + else + assert(false && "PointsTo::PointsTo&&: unknown type"); } PointsTo::~PointsTo() { - if (type == SBV) sbv.~SparseBitVector<>(); - else if (type == CBV) cbv.~CoreBitVector(); - else if (type == BV) bv.~BitVector(); - else assert(false && "PointsTo::~PointsTo: unknown type"); + if (type == SBV) + sbv.~SparseBitVector<>(); + else if (type == CBV) + cbv.~CoreBitVector(); + else if (type == BV) + bv.~BitVector(); + else + assert(false && "PointsTo::~PointsTo: unknown type"); nodeMapping = nullptr; reverseNodeMapping = nullptr; } -PointsTo &PointsTo::operator=(const PointsTo &rhs) +PointsTo& PointsTo::operator=(const PointsTo& rhs) { if (this == &rhs) return *this; @@ -72,34 +88,44 @@ PointsTo &PointsTo::operator=(const PointsTo &rhs) this->reverseNodeMapping = rhs.reverseNodeMapping; // Placement new because if type has changed, we have // not constructed the new type yet. - if (type == SBV) new (&sbv) SparseBitVector<>(rhs.sbv); - else if (type == CBV) new (&cbv) CoreBitVector(rhs.cbv); - else if (type == BV) new (&bv) BitVector(rhs.bv); - else assert(false && "PointsTo::PointsTo=&: unknown type"); + if (type == SBV) + new (&sbv) SparseBitVector<>(rhs.sbv); + else if (type == CBV) + new (&cbv) CoreBitVector(rhs.cbv); + else if (type == BV) + new (&bv) BitVector(rhs.bv); + else + assert(false && "PointsTo::PointsTo=&: unknown type"); return *this; } -PointsTo &PointsTo::operator=(PointsTo &&rhs) -noexcept +PointsTo& PointsTo::operator=(PointsTo&& rhs) noexcept { this->type = rhs.type; this->nodeMapping = rhs.nodeMapping; this->reverseNodeMapping = rhs.reverseNodeMapping; // See comment in copy assignment. - if (type == SBV) new (&sbv) SparseBitVector<>(std::move(rhs.sbv)); - else if (type == CBV) new (&cbv) CoreBitVector(std::move(rhs.cbv)); - else if (type == BV) new (&bv) BitVector(std::move(rhs.bv)); - else assert(false && "PointsTo::PointsTo=&&: unknown type"); + if (type == SBV) + new (&sbv) SparseBitVector<>(std::move(rhs.sbv)); + else if (type == CBV) + new (&cbv) CoreBitVector(std::move(rhs.cbv)); + else if (type == BV) + new (&bv) BitVector(std::move(rhs.bv)); + else + assert(false && "PointsTo::PointsTo=&&: unknown type"); return *this; } bool PointsTo::empty() const { - if (type == CBV) return cbv.empty(); - else if (type == SBV) return sbv.empty(); - else if (type == BV) return bv.empty(); + if (type == CBV) + return cbv.empty(); + else if (type == SBV) + return sbv.empty(); + else if (type == BV) + return bv.empty(); else { assert(false && "PointsTo::empty: unknown type"); @@ -110,9 +136,12 @@ bool PointsTo::empty() const /// Returns number of elements. u32_t PointsTo::count(void) const { - if (type == CBV) return cbv.count(); - else if (type == SBV) return sbv.count(); - else if (type == BV) return bv.count(); + if (type == CBV) + return cbv.count(); + else if (type == SBV) + return sbv.count(); + else if (type == BV) + return bv.count(); else { assert(false && "PointsTo::count: unknown type"); @@ -122,18 +151,25 @@ u32_t PointsTo::count(void) const void PointsTo::clear() { - if (type == CBV) cbv.clear(); - else if (type == SBV) sbv.clear(); - else if (type == BV) bv.clear(); - else assert(false && "PointsTo::clear: unknown type"); + if (type == CBV) + cbv.clear(); + else if (type == SBV) + sbv.clear(); + else if (type == BV) + bv.clear(); + else + assert(false && "PointsTo::clear: unknown type"); } bool PointsTo::test(u32_t n) const { n = getInternalNode(n); - if (type == CBV) return cbv.test(n); - else if (type == SBV) return sbv.test(n); - else if (type == BV) return bv.test(n); + if (type == CBV) + return cbv.test(n); + else if (type == SBV) + return sbv.test(n); + else if (type == BV) + return bv.test(n); else { assert(false && "PointsTo::test: unknown type"); @@ -144,9 +180,12 @@ bool PointsTo::test(u32_t n) const bool PointsTo::test_and_set(u32_t n) { n = getInternalNode(n); - if (type == CBV) return cbv.test_and_set(n); - else if (type == SBV) return sbv.test_and_set(n); - else if (type == BV) return bv.test_and_set(n); + if (type == CBV) + return cbv.test_and_set(n); + else if (type == SBV) + return sbv.test_and_set(n); + else if (type == BV) + return bv.test_and_set(n); else { assert(false && "PointsTo::test_and_set: unknown type"); @@ -157,28 +196,40 @@ bool PointsTo::test_and_set(u32_t n) void PointsTo::set(u32_t n) { n = getInternalNode(n); - if (type == CBV) cbv.set(n); - else if (type == SBV) sbv.set(n); - else if (type == BV) bv.set(n); - else assert(false && "PointsTo::set: unknown type"); + if (type == CBV) + cbv.set(n); + else if (type == SBV) + sbv.set(n); + else if (type == BV) + bv.set(n); + else + assert(false && "PointsTo::set: unknown type"); } void PointsTo::reset(u32_t n) { n = getInternalNode(n); - if (type == CBV) cbv.reset(n); - else if (type == SBV) sbv.reset(n); - else if (type == BV) bv.reset(n); - else assert(false && "PointsTo::reset: unknown type"); + if (type == CBV) + cbv.reset(n); + else if (type == SBV) + sbv.reset(n); + else if (type == BV) + bv.reset(n); + else + assert(false && "PointsTo::reset: unknown type"); } -bool PointsTo::contains(const PointsTo &rhs) const +bool PointsTo::contains(const PointsTo& rhs) const { - assert(metaSame(rhs) && "PointsTo::contains: mappings of operands do not match!"); + assert(metaSame(rhs) && + "PointsTo::contains: mappings of operands do not match!"); - if (type == CBV) return cbv.contains(rhs.cbv); - else if (type == SBV) return sbv.contains(rhs.sbv); - else if (type == BV) return bv.contains(rhs.bv); + if (type == CBV) + return cbv.contains(rhs.cbv); + else if (type == SBV) + return sbv.contains(rhs.sbv); + else if (type == BV) + return bv.contains(rhs.bv); else { assert(false && "PointsTo::contains: unknown type"); @@ -186,13 +237,17 @@ bool PointsTo::contains(const PointsTo &rhs) const } } -bool PointsTo::intersects(const PointsTo &rhs) const +bool PointsTo::intersects(const PointsTo& rhs) const { - assert(metaSame(rhs) && "PointsTo::intersects: mappings of operands do not match!"); + assert(metaSame(rhs) && + "PointsTo::intersects: mappings of operands do not match!"); - if (type == CBV) return cbv.intersects(rhs.cbv); - else if (type == SBV) return sbv.intersects(rhs.sbv); - else if (type == BV) return bv.intersects(rhs.bv); + if (type == CBV) + return cbv.intersects(rhs.cbv); + else if (type == SBV) + return sbv.intersects(rhs.sbv); + else if (type == BV) + return bv.intersects(rhs.bv); else { assert(false && "PointsTo::intersects: unknown type"); @@ -202,17 +257,21 @@ bool PointsTo::intersects(const PointsTo &rhs) const int PointsTo::find_first() { - if (count() == 0) return -1; + if (count() == 0) + return -1; return *begin(); } -bool PointsTo::operator==(const PointsTo &rhs) const +bool PointsTo::operator==(const PointsTo& rhs) const { assert(metaSame(rhs) && "PointsTo::==: mappings of operands do not match!"); - if (type == CBV) return cbv == rhs.cbv; - else if (type == SBV) return sbv == rhs.sbv; - else if (type == BV) return bv == rhs.bv; + if (type == CBV) + return cbv == rhs.cbv; + else if (type == SBV) + return sbv == rhs.sbv; + else if (type == BV) + return bv == rhs.bv; else { assert(false && "PointsTo::==: unknown type"); @@ -220,7 +279,7 @@ bool PointsTo::operator==(const PointsTo &rhs) const } } -bool PointsTo::operator!=(const PointsTo &rhs) const +bool PointsTo::operator!=(const PointsTo& rhs) const { // TODO: we're asserting and checking twice... should be okay... assert(metaSame(rhs) && "PointsTo::!=: mappings of operands do not match!"); @@ -228,13 +287,16 @@ bool PointsTo::operator!=(const PointsTo &rhs) const return !(*this == rhs); } -bool PointsTo::operator|=(const PointsTo &rhs) +bool PointsTo::operator|=(const PointsTo& rhs) { assert(metaSame(rhs) && "PointsTo::|=: mappings of operands do not match!"); - if (type == CBV) return cbv |= rhs.cbv; - else if (type == SBV) return sbv |= rhs.sbv; - else if (type == BV) return bv |= rhs.bv; + if (type == CBV) + return cbv |= rhs.cbv; + else if (type == SBV) + return sbv |= rhs.sbv; + else if (type == BV) + return bv |= rhs.bv; else { assert(false && "PointsTo::|=: unknown type"); @@ -242,26 +304,31 @@ bool PointsTo::operator|=(const PointsTo &rhs) } } -bool PointsTo::operator|=(const NodeBS &rhs) +bool PointsTo::operator|=(const NodeBS& rhs) { // TODO: bool changed = false; for (NodeID n : rhs) { - if (changed) set(n); - else changed = test_and_set(n); + if (changed) + set(n); + else + changed = test_and_set(n); } return changed; } -bool PointsTo::operator&=(const PointsTo &rhs) +bool PointsTo::operator&=(const PointsTo& rhs) { assert(metaSame(rhs) && "PointsTo::&=: mappings of operands do not match!"); - if (type == CBV) return cbv &= rhs.cbv; - else if (type == SBV) return sbv &= rhs.sbv; - else if (type == BV) return bv &= rhs.bv; + if (type == CBV) + return cbv &= rhs.cbv; + else if (type == SBV) + return sbv &= rhs.sbv; + else if (type == BV) + return bv &= rhs.bv; else { assert(false && "PointsTo::&=: unknown type"); @@ -269,13 +336,16 @@ bool PointsTo::operator&=(const PointsTo &rhs) } } -bool PointsTo::operator-=(const PointsTo &rhs) +bool PointsTo::operator-=(const PointsTo& rhs) { assert(metaSame(rhs) && "PointsTo::-=: mappings of operands do not match!"); - if (type == CBV) return cbv.intersectWithComplement(rhs.cbv); - else if (type == SBV) return sbv.intersectWithComplement(rhs.sbv); - else if (type == BV) return bv.intersectWithComplement(rhs.bv); + if (type == CBV) + return cbv.intersectWithComplement(rhs.cbv); + else if (type == SBV) + return sbv.intersectWithComplement(rhs.sbv); + else if (type == BV) + return bv.intersectWithComplement(rhs.bv); else { assert(false && "PointsTo::-=: unknown type"); @@ -283,29 +353,39 @@ bool PointsTo::operator-=(const PointsTo &rhs) } } -bool PointsTo::intersectWithComplement(const PointsTo &rhs) +bool PointsTo::intersectWithComplement(const PointsTo& rhs) { - assert(metaSame(rhs) && "PointsTo::intersectWithComplement: mappings of operands do not match!"); + assert(metaSame(rhs) && "PointsTo::intersectWithComplement: mappings of " + "operands do not match!"); - if (type == CBV) return cbv.intersectWithComplement(rhs.cbv); - else if (type == SBV) return sbv.intersectWithComplement(rhs.sbv); - else if (type == BV) return bv.intersectWithComplement(rhs.bv); + if (type == CBV) + return cbv.intersectWithComplement(rhs.cbv); + else if (type == SBV) + return sbv.intersectWithComplement(rhs.sbv); + else if (type == BV) + return bv.intersectWithComplement(rhs.bv); assert(false && "PointsTo::intersectWithComplement(PT): unknown type"); abort(); } -void PointsTo::intersectWithComplement(const PointsTo &lhs, const PointsTo &rhs) +void PointsTo::intersectWithComplement(const PointsTo& lhs, const PointsTo& rhs) { - assert(metaSame(rhs) && "PointsTo::intersectWithComplement: mappings of operands do not match!"); - assert(metaSame(lhs) && "PointsTo::intersectWithComplement: mappings of operands do not match!"); + assert(metaSame(rhs) && "PointsTo::intersectWithComplement: mappings of " + "operands do not match!"); + assert(metaSame(lhs) && "PointsTo::intersectWithComplement: mappings of " + "operands do not match!"); - if (type == CBV) cbv.intersectWithComplement(lhs.cbv, rhs.cbv); - else if (type == SBV) sbv.intersectWithComplement(lhs.sbv, rhs.sbv); - else if (type == BV) bv.intersectWithComplement(lhs.bv, rhs.bv); + if (type == CBV) + cbv.intersectWithComplement(lhs.cbv, rhs.cbv); + else if (type == SBV) + sbv.intersectWithComplement(lhs.sbv, rhs.sbv); + else if (type == BV) + bv.intersectWithComplement(lhs.bv, rhs.bv); else { - assert(false && "PointsTo::intersectWithComplement(PT, PT): unknown type"); + assert(false && + "PointsTo::intersectWithComplement(PT, PT): unknown type"); abort(); } } @@ -313,19 +393,22 @@ void PointsTo::intersectWithComplement(const PointsTo &lhs, const PointsTo &rhs) NodeBS PointsTo::toNodeBS() const { NodeBS nbs; - for (const NodeID o : *this) nbs.set(o); + for (const NodeID o : *this) + nbs.set(o); return nbs; } size_t PointsTo::hash() const { - if (type == CBV) return cbv.hash(); + if (type == CBV) + return cbv.hash(); else if (type == SBV) { std::hash> h; return h(sbv); } - else if (type == BV) return bv.hash(); + else if (type == BV) + return bv.hash(); else { @@ -341,21 +424,24 @@ PointsTo::MappingPtr PointsTo::getNodeMapping() const NodeID PointsTo::getInternalNode(NodeID n) const { - if (nodeMapping == nullptr) return n; + if (nodeMapping == nullptr) + return n; assert(n < nodeMapping->size()); return nodeMapping->at(n); } NodeID PointsTo::getExternalNode(NodeID n) const { - if (reverseNodeMapping == nullptr) return n; + if (reverseNodeMapping == nullptr) + return n; assert(n < reverseNodeMapping->size()); return reverseNodeMapping->at(n); } -bool PointsTo::metaSame(const PointsTo &pt) const +bool PointsTo::metaSame(const PointsTo& pt) const { - return nodeMapping == pt.nodeMapping && reverseNodeMapping == pt.reverseNodeMapping; + return nodeMapping == pt.nodeMapping && + reverseNodeMapping == pt.reverseNodeMapping; } PointsTo::MappingPtr PointsTo::getCurrentBestNodeMapping() @@ -368,8 +454,9 @@ PointsTo::MappingPtr PointsTo::getCurrentBestReverseNodeMapping() return currentBestReverseNodeMapping; } -void PointsTo::setCurrentBestNodeMapping(MappingPtr newCurrentBestNodeMapping, - MappingPtr newCurrentBestReverseNodeMapping) +void PointsTo::setCurrentBestNodeMapping( + MappingPtr newCurrentBestNodeMapping, + MappingPtr newCurrentBestReverseNodeMapping) { currentBestNodeMapping = std::move(newCurrentBestNodeMapping); currentBestReverseNodeMapping = std::move(newCurrentBestReverseNodeMapping); @@ -381,21 +468,24 @@ void PointsTo::checkAndRemap() { // newPt constructed with correct node mapping. PointsTo newPt; - for (const NodeID o : *this) newPt.set(o); + for (const NodeID o : *this) + newPt.set(o); *this = std::move(newPt); } } -PointsTo::PointsToIterator::PointsToIterator(const PointsTo *pt, bool end) +PointsTo::PointsToIterator::PointsToIterator(const PointsTo* pt, bool end) : pt(pt) { if (pt->type == Type::CBV) { - new (&cbvIt) CoreBitVector::iterator(end ? pt->cbv.end() : pt->cbv.begin()); + new (&cbvIt) + CoreBitVector::iterator(end ? pt->cbv.end() : pt->cbv.begin()); } else if (pt->type == Type::SBV) { - new (&sbvIt) SparseBitVector<>::iterator(end ? pt->sbv.end() : pt->sbv.begin()); + new (&sbvIt) + SparseBitVector<>::iterator(end ? pt->sbv.end() : pt->sbv.begin()); } else if (pt->type == Type::BV) { @@ -408,7 +498,7 @@ PointsTo::PointsToIterator::PointsToIterator(const PointsTo *pt, bool end) } } -PointsTo::PointsToIterator::PointsToIterator(const PointsToIterator &pt) +PointsTo::PointsToIterator::PointsToIterator(const PointsToIterator& pt) : pt(pt.pt) { if (this->pt->type == PointsTo::Type::SBV) @@ -430,8 +520,8 @@ PointsTo::PointsToIterator::PointsToIterator(const PointsToIterator &pt) } } -PointsTo::PointsToIterator::PointsToIterator(PointsToIterator &&pt) -noexcept : pt(pt.pt) +PointsTo::PointsToIterator::PointsToIterator(PointsToIterator&& pt) noexcept + : pt(pt.pt) { if (this->pt->type == PointsTo::Type::SBV) { @@ -452,7 +542,30 @@ noexcept : pt(pt.pt) } } -PointsTo::PointsToIterator &PointsTo::PointsToIterator::operator=(const PointsToIterator &rhs) +PointsTo::PointsToIterator::~PointsToIterator() +{ + if (this->pt) + { + if (this->pt->type == PointsTo::Type::SBV) + { + using sbv_iter = SparseBitVector<>::iterator; + sbvIt.~sbv_iter(); + } + else if (this->pt->type == PointsTo::Type::CBV) + { + using cbv_iter = CoreBitVector::iterator; + cbvIt.~cbv_iter(); + } + else if (this->pt->type == PointsTo::Type::BV) + { + using bv_iter = BitVector::iterator; + bvIt.~bv_iter(); + } + } +} + +PointsTo::PointsToIterator& PointsTo::PointsToIterator::operator=( + const PointsToIterator& rhs) { this->pt = rhs.pt; @@ -468,12 +581,14 @@ PointsTo::PointsToIterator &PointsTo::PointsToIterator::operator=(const PointsTo { new (&bvIt) BitVector::iterator(rhs.bvIt); } - else assert(false && "PointsToIterator::PointsToIterator&: unknown type"); + else + assert(false && "PointsToIterator::PointsToIterator&: unknown type"); return *this; } -PointsTo::PointsToIterator &PointsTo::PointsToIterator::operator=(PointsToIterator &&rhs) noexcept +PointsTo::PointsToIterator& PointsTo::PointsToIterator::operator=( + PointsToIterator&& rhs) noexcept { this->pt = rhs.pt; @@ -489,18 +604,23 @@ PointsTo::PointsToIterator &PointsTo::PointsToIterator::operator=(PointsToIterat { new (&bvIt) BitVector::iterator(std::move(rhs.bvIt)); } - else assert(false && "PointsToIterator::PointsToIterator&&: unknown type"); + else + assert(false && "PointsToIterator::PointsToIterator&&: unknown type"); return *this; } -const PointsTo::PointsToIterator &PointsTo::PointsToIterator::operator++() +const PointsTo::PointsToIterator& PointsTo::PointsToIterator::operator++() { assert(!atEnd() && "PointsToIterator::++(pre): incrementing past end!"); - if (pt->type == Type::CBV) ++cbvIt; - else if (pt->type == Type::SBV) ++sbvIt; - else if (pt->type == Type::BV) ++bvIt; - else assert(false && "PointsToIterator::++(void): unknown type"); + if (pt->type == Type::CBV) + ++cbvIt; + else if (pt->type == Type::SBV) + ++sbvIt; + else if (pt->type == Type::BV) + ++bvIt; + else + assert(false && "PointsToIterator::++(void): unknown type"); return *this; } @@ -516,9 +636,12 @@ const PointsTo::PointsToIterator PointsTo::PointsToIterator::operator++(int) NodeID PointsTo::PointsToIterator::operator*() const { assert(!atEnd() && "PointsToIterator: dereferencing end!"); - if (pt->type == Type::CBV) return pt->getExternalNode(*cbvIt); - else if (pt->type == Type::SBV) return pt->getExternalNode(*sbvIt); - else if (pt->type == Type::BV) return pt->getExternalNode(*bvIt); + if (pt->type == Type::CBV) + return pt->getExternalNode(*cbvIt); + else if (pt->type == Type::SBV) + return pt->getExternalNode(*sbvIt); + else if (pt->type == Type::BV) + return pt->getExternalNode(*bvIt); else { assert(false && "PointsToIterator::*: unknown type"); @@ -526,15 +649,19 @@ NodeID PointsTo::PointsToIterator::operator*() const } } -bool PointsTo::PointsToIterator::operator==(const PointsToIterator &rhs) const +bool PointsTo::PointsToIterator::operator==(const PointsToIterator& rhs) const { - assert(pt == rhs.pt - && "PointsToIterator::==: comparing iterators from different PointsTos!"); + assert( + pt == rhs.pt && + "PointsToIterator::==: comparing iterators from different PointsTos!"); // Handles end implicitly. - if (pt->type == Type::CBV) return cbvIt == rhs.cbvIt; - else if (pt->type == Type::SBV) return sbvIt == rhs.sbvIt; - else if (pt->type == Type::BV) return bvIt == rhs.bvIt; + if (pt->type == Type::CBV) + return cbvIt == rhs.cbvIt; + else if (pt->type == Type::SBV) + return sbvIt == rhs.sbvIt; + else if (pt->type == Type::BV) + return bvIt == rhs.bvIt; else { assert(false && "PointsToIterator::==: unknown type"); @@ -542,19 +669,24 @@ bool PointsTo::PointsToIterator::operator==(const PointsToIterator &rhs) const } } -bool PointsTo::PointsToIterator::operator!=(const PointsToIterator &rhs) const +bool PointsTo::PointsToIterator::operator!=(const PointsToIterator& rhs) const { - assert(pt == rhs.pt - && "PointsToIterator::!=: comparing iterators from different PointsTos!"); + assert( + pt == rhs.pt && + "PointsToIterator::!=: comparing iterators from different PointsTos!"); return !(*this == rhs); } bool PointsTo::PointsToIterator::atEnd() const { - assert(pt != nullptr && "PointsToIterator::atEnd: iterator iterating over nothing!"); - if (pt->type == Type::CBV) return cbvIt == pt->cbv.end(); - else if (pt->type == Type::SBV) return sbvIt == pt->sbv.end(); - else if (pt->type == Type::BV) return bvIt == pt->bv.end(); + assert(pt != nullptr && + "PointsToIterator::atEnd: iterator iterating over nothing!"); + if (pt->type == Type::CBV) + return cbvIt == pt->cbv.end(); + else if (pt->type == Type::SBV) + return sbvIt == pt->sbv.end(); + else if (pt->type == Type::BV) + return bvIt == pt->bv.end(); else { assert(false && "PointsToIterator::atEnd: unknown type"); @@ -562,7 +694,7 @@ bool PointsTo::PointsToIterator::atEnd() const } } -PointsTo operator|(const PointsTo &lhs, const PointsTo &rhs) +PointsTo operator|(const PointsTo& lhs, const PointsTo& rhs) { // TODO: optimise. PointsTo result = lhs; @@ -570,7 +702,7 @@ PointsTo operator|(const PointsTo &lhs, const PointsTo &rhs) return result; } -PointsTo operator&(const PointsTo &lhs, const PointsTo &rhs) +PointsTo operator&(const PointsTo& lhs, const PointsTo& rhs) { // TODO: optimise. PointsTo result = lhs; @@ -578,7 +710,7 @@ PointsTo operator&(const PointsTo &lhs, const PointsTo &rhs) return result; } -PointsTo operator-(const PointsTo &lhs, const PointsTo &rhs) +PointsTo operator-(const PointsTo& lhs, const PointsTo& rhs) { // TODO: optimise. PointsTo result = lhs; @@ -586,4 +718,4 @@ PointsTo operator-(const PointsTo &lhs, const PointsTo &rhs) return result; } -}; // namespace SVF +}; // namespace SVF diff --git a/svf/lib/SABER/SaberCheckerAPI.cpp b/svf/lib/SABER/SaberCheckerAPI.cpp index 9baab29dc4..45ac9e9bb1 100644 --- a/svf/lib/SABER/SaberCheckerAPI.cpp +++ b/svf/lib/SABER/SaberCheckerAPI.cpp @@ -40,16 +40,15 @@ namespace /// string and type pair struct ei_pair { - const char *n; + const char* n; SaberCheckerAPI::CHECKER_TYPE t; }; } // End anonymous namespace -//Each (name, type) pair will be inserted into the map. -//All entries of the same type must occur together (for error detection). -static const ei_pair ei_pairs[]= -{ +// Each (name, type) pair will be inserted into the map. +// All entries of the same type must occur together (for error detection). +static const ei_pair ei_pairs[] = { {"alloc", SaberCheckerAPI::CK_ALLOC}, {"alloc_check", SaberCheckerAPI::CK_ALLOC}, {"alloc_clear", SaberCheckerAPI::CK_ALLOC}, @@ -77,6 +76,16 @@ static const ei_pair ei_pairs[]= {"SSL_CTX_new", SaberCheckerAPI::CK_ALLOC}, {"SSL_new", SaberCheckerAPI::CK_ALLOC}, {"VOS_MemAlloc", SaberCheckerAPI::CK_ALLOC}, + {"HeapAlloc", SaberCheckerAPI::CK_ALLOC}, + {"\01HeapAlloc", SaberCheckerAPI::CK_ALLOC}, + {"LocalAlloc", SaberCheckerAPI::CK_ALLOC}, + {"\01LocalAlloc", SaberCheckerAPI::CK_ALLOC}, + {"GlobalAlloc", SaberCheckerAPI::CK_ALLOC}, + {"\01GlobalAlloc", SaberCheckerAPI::CK_ALLOC}, + {"_malloc_dbg", SaberCheckerAPI::CK_ALLOC}, + {"\01_malloc_dbg", SaberCheckerAPI::CK_ALLOC}, + {"_aligned_malloc", SaberCheckerAPI::CK_ALLOC}, + {"\01_aligned_malloc", SaberCheckerAPI::CK_ALLOC}, {"VOS_MemFree", SaberCheckerAPI::CK_FREE}, {"cfree", SaberCheckerAPI::CK_FREE}, @@ -98,6 +107,16 @@ static const ei_pair ei_pairs[]= {"SSL_CTX_free", SaberCheckerAPI::CK_FREE}, {"SSL_free", SaberCheckerAPI::CK_FREE}, {"XFree", SaberCheckerAPI::CK_FREE}, + {"HeapFree", SaberCheckerAPI::CK_FREE}, + {"\01HeapFree", SaberCheckerAPI::CK_FREE}, + {"LocalFree", SaberCheckerAPI::CK_FREE}, + {"\01LocalFree", SaberCheckerAPI::CK_FREE}, + {"GlobalFree", SaberCheckerAPI::CK_FREE}, + {"\01GlobalFree", SaberCheckerAPI::CK_FREE}, + {"_free_dbg", SaberCheckerAPI::CK_FREE}, + {"\01_free_dbg", SaberCheckerAPI::CK_FREE}, + {"_aligned_free", SaberCheckerAPI::CK_FREE}, + {"\01_aligned_free", SaberCheckerAPI::CK_FREE}, {"fopen", SaberCheckerAPI::CK_FOPEN}, {"\01_fopen", SaberCheckerAPI::CK_FOPEN}, @@ -119,7 +138,6 @@ static const ei_pair ei_pairs[]= {"gcry_md_open", SaberCheckerAPI::CK_FOPEN}, {"gcry_cipher_open", SaberCheckerAPI::CK_FOPEN}, - {"fclose", SaberCheckerAPI::CK_FCLOSE}, {"XCloseDisplay", SaberCheckerAPI::CK_FCLOSE}, {"XtCloseDisplay", SaberCheckerAPI::CK_FCLOSE}, @@ -132,45 +150,40 @@ static const ei_pair ei_pairs[]= {"gcry_md_close", SaberCheckerAPI::CK_FCLOSE}, {"gcry_cipher_close", SaberCheckerAPI::CK_FCLOSE}, - //This must be the last entry. + // This must be the last entry. {0, SaberCheckerAPI::CK_DUMMY} }; - /*! * initialize the map */ void SaberCheckerAPI::init() { set t_seen; - CHECKER_TYPE prev_t= CK_DUMMY; + CHECKER_TYPE prev_t = CK_DUMMY; t_seen.insert(CK_DUMMY); - for(const ei_pair *p= ei_pairs; p->n; ++p) + for (const ei_pair* p = ei_pairs; p->n; ++p) { - if(p->t != prev_t) + if (p->t != prev_t) { - //This will detect if you move an entry to another block - // but forget to change the type. - if(t_seen.count(p->t)) + // This will detect if you move an entry to another block + // but forget to change the type. + if (t_seen.count(p->t)) { fputs(p->n, stderr); putc('\n', stderr); assert(!"ei_pairs not grouped by type"); } t_seen.insert(p->t); - prev_t= p->t; + prev_t = p->t; } - if(tdAPIMap.count(p->n)) + if (tdAPIMap.count(p->n)) { fputs(p->n, stderr); putc('\n', stderr); assert(!"duplicate name in ei_pairs"); } - tdAPIMap[p->n]= p->t; + tdAPIMap[p->n] = p->t; } } - - - - diff --git a/svf/lib/SVFIR/SVFType.cpp b/svf/lib/SVFIR/SVFType.cpp index a464cda7ec..b21dd72f8b 100644 --- a/svf/lib/SVFIR/SVFType.cpp +++ b/svf/lib/SVFIR/SVFType.cpp @@ -1,13 +1,19 @@ #include "SVFIR/SVFType.h" #include +#ifdef _MSC_VER +# define SVF_WEAK inline +#else +# define SVF_WEAK __attribute__((weak)) +#endif + namespace SVF { SVFType* SVFType::svfI8Ty = nullptr; SVFType* SVFType::svfPtrTy = nullptr; -__attribute__((weak)) +SVF_WEAK std::string SVFType::toString() const { std::ostringstream os; diff --git a/svf/lib/SVFIR/SVFValue.cpp b/svf/lib/SVFIR/SVFValue.cpp index bc79261958..7e2113c148 100644 --- a/svf/lib/SVFIR/SVFValue.cpp +++ b/svf/lib/SVFIR/SVFValue.cpp @@ -30,27 +30,35 @@ */ #include "SVFIR/SVFValue.h" -#include "Util/SVFUtil.h" #include "Graphs/BasicBlockG.h" #include "Graphs/GenericGraph.h" #include "Util/SVFLoopAndDomInfo.h" +#include "Util/SVFUtil.h" +#ifdef _MSC_VER +# define SVF_WEAK inline +#else +# define SVF_WEAK __attribute__((weak)) +#endif using namespace SVF; using namespace SVFUtil; - -__attribute__((weak)) +SVF_WEAK const std::string SVFValue::valueOnlyToString() const { - assert("SVFBaseNode::valueOnlyToString should be implemented or supported by fronted" && false); + assert("SVFBaseNode::valueOnlyToString should be implemented or supported " + "by fronted" && + false); abort(); } -__attribute__((weak)) +SVF_WEAK const bool SVFValue::hasLLVMValue() const { - assert("SVFBaseNode::hasLLVMValue should be implemented or supported by fronted" && false); + assert("SVFBaseNode::hasLLVMValue should be implemented or supported by " + "fronted" && + false); abort(); } @@ -62,26 +70,29 @@ void StInfo::addFldWithType(u32_t fldIdx, const SVFType* type, u32_t elemIdx) fldIdx2TypeMap[fldIdx] = type; } -/// struct A { int id; int salary; }; struct B { char name[20]; struct A a;} B b; -/// OriginalFieldType of b with field_idx 1 : Struct A -/// FlatternedFieldType of b with field_idx 1 : int +/// struct A { int id; int salary; }; struct B { char name[20]; struct A a;} B +/// b; OriginalFieldType of b with field_idx 1 : Struct A FlatternedFieldType +/// of b with field_idx 1 : int //{@ const SVFType* StInfo::getOriginalElemType(u32_t fldIdx) const { Map::const_iterator it = fldIdx2TypeMap.find(fldIdx); - if(it!=fldIdx2TypeMap.end()) + if (it != fldIdx2TypeMap.end()) return it->second; return nullptr; } -const SVFLoopAndDomInfo::LoopBBs& SVFLoopAndDomInfo::getLoopInfo(const SVFBasicBlock* bb) const +const SVFLoopAndDomInfo::LoopBBs& SVFLoopAndDomInfo::getLoopInfo( + const SVFBasicBlock* bb) const { assert(hasLoopInfo(bb) && "loopinfo does not exist (bb not in a loop)"); - Map::const_iterator mapIter = bb2LoopMap.find(bb); + Map::const_iterator mapIter = + bb2LoopMap.find(bb); return mapIter->second; } -void SVFLoopAndDomInfo::getExitBlocksOfLoop(const SVFBasicBlock* bb, BBList& exitbbs) const +void SVFLoopAndDomInfo::getExitBlocksOfLoop(const SVFBasicBlock* bb, + BBList& exitbbs) const { if (hasLoopInfo(bb)) { @@ -92,7 +103,8 @@ void SVFLoopAndDomInfo::getExitBlocksOfLoop(const SVFBasicBlock* bb, BBList& exi { for (const SVFBasicBlock* succ : block->getSuccessors()) { - if ((std::find(blocks.begin(), blocks.end(), succ)==blocks.end())) + if ((std::find(blocks.begin(), blocks.end(), succ) == + blocks.end())) exitbbs.push_back(succ); } } @@ -100,7 +112,8 @@ void SVFLoopAndDomInfo::getExitBlocksOfLoop(const SVFBasicBlock* bb, BBList& exi } } -bool SVFLoopAndDomInfo::dominate(const SVFBasicBlock* bbKey, const SVFBasicBlock* bbValue) const +bool SVFLoopAndDomInfo::dominate(const SVFBasicBlock* bbKey, + const SVFBasicBlock* bbValue) const { if (bbKey == bbValue) return true; @@ -117,11 +130,12 @@ bool SVFLoopAndDomInfo::dominate(const SVFBasicBlock* bbKey, const SVFBasicBlock return false; } - const Map& dtBBsMap = getDomTreeMap(); - Map::const_iterator mapIter = dtBBsMap.find(bbKey); + const Map& dtBBsMap = getDomTreeMap(); + Map::const_iterator mapIter = + dtBBsMap.find(bbKey); if (mapIter != dtBBsMap.end()) { - const BBSet & dtBBs = mapIter->second; + const BBSet& dtBBs = mapIter->second; if (dtBBs.find(bbValue) != dtBBs.end()) { return true; @@ -131,7 +145,8 @@ bool SVFLoopAndDomInfo::dominate(const SVFBasicBlock* bbKey, const SVFBasicBlock return false; } -bool SVFLoopAndDomInfo::postDominate(const SVFBasicBlock* bbKey, const SVFBasicBlock* bbValue) const +bool SVFLoopAndDomInfo::postDominate(const SVFBasicBlock* bbKey, + const SVFBasicBlock* bbValue) const { if (bbKey == bbValue) return true; @@ -148,11 +163,12 @@ bool SVFLoopAndDomInfo::postDominate(const SVFBasicBlock* bbKey, const SVFBasicB return false; } - const Map& dtBBsMap = getPostDomTreeMap(); - Map::const_iterator mapIter = dtBBsMap.find(bbKey); + const Map& dtBBsMap = getPostDomTreeMap(); + Map::const_iterator mapIter = + dtBBsMap.find(bbKey); if (mapIter != dtBBsMap.end()) { - const BBSet & dtBBs = mapIter->second; + const BBSet& dtBBs = mapIter->second; if (dtBBs.find(bbValue) != dtBBs.end()) { return true; @@ -161,7 +177,8 @@ bool SVFLoopAndDomInfo::postDominate(const SVFBasicBlock* bbKey, const SVFBasicB return false; } -const SVFBasicBlock* SVFLoopAndDomInfo::findNearestCommonPDominator(const SVFBasicBlock* A, const SVFBasicBlock* B) const +const SVFBasicBlock* SVFLoopAndDomInfo::findNearestCommonPDominator( + const SVFBasicBlock* A, const SVFBasicBlock* B) const { assert(A && B && "Pointers are not valid"); assert(A->getParent() == B->getParent() && @@ -172,12 +189,14 @@ const SVFBasicBlock* SVFLoopAndDomInfo::findNearestCommonPDominator(const SVFBas while (A != B) { // no common PDominator - if(A == NULL) return NULL; + if (A == NULL) + return NULL; const auto lvA = getBBPDomLevel().find(A); const auto lvB = getBBPDomLevel().find(B); assert(lvA != getBBPDomLevel().end() && lvB != getBBPDomLevel().end()); - if (lvA->second < lvB->second) std::swap(A, B); + if (lvA->second < lvB->second) + std::swap(A, B); const auto lvAIdom = getBB2PIdom().find(A); assert(lvAIdom != getBB2PIdom().end()); diff --git a/svf/lib/Util/ExtAPI.cpp b/svf/lib/Util/ExtAPI.cpp index 34e65974be..5f4f6cbb95 100644 --- a/svf/lib/Util/ExtAPI.cpp +++ b/svf/lib/Util/ExtAPI.cpp @@ -32,9 +32,18 @@ #include "Util/Options.h" #include "Util/config.h" #include -#include +#ifdef _WIN32 +# include +# include +# include +# define stat _stat +# define popen _popen +# define pclose _pclose +#else +# include +# include +#endif #include "SVFIR/SVFVariables.h" -#include using namespace SVF; @@ -142,12 +151,31 @@ static std::string getFilePath(const std::string& path) // This is useful for locating resource files (such as extapi.bc) relative to the module at runtime. std::string getCurrentSOPath() { +#ifdef _WIN32 + char path[MAX_PATH]; + HMODULE hm = NULL; + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR)&getCurrentSOPath, &hm)) + { + GetModuleFileNameA(hm, path, sizeof(path)); + std::string s(path); + for (size_t i = 0; i < s.length(); ++i) { + if (s[i] == '\\') { + s[i] = '/'; + } + } + return s; + } + return ""; +#else Dl_info info; if (dladdr((void*)&getCurrentSOPath, &info) && info.dli_fname) { return std::string(info.dli_fname); } return ""; +#endif } // Get extapi.bc path diff --git a/svf/lib/Util/SVFStat.cpp b/svf/lib/Util/SVFStat.cpp index 9655b8fa49..6985988691 100644 --- a/svf/lib/Util/SVFStat.cpp +++ b/svf/lib/Util/SVFStat.cpp @@ -33,6 +33,9 @@ #include "Util/Options.h" #include "Util/SVFStat.h" #include "Graphs/CallGraph.h" +#if defined(_WIN32) +#include +#endif using namespace SVF; using namespace std; @@ -54,9 +57,16 @@ double SVFStat::getClk(bool mark) if (Options::ClockType() == ClockType::Wall) { +#if defined(_WIN32) + LARGE_INTEGER freq, counter; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&counter); + return (double)counter.QuadPart / (double)freq.QuadPart * 1000.0; +#else struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time); return (double)(time.tv_nsec + time.tv_sec * 1000000000) / 1000000.0; +#endif } else if (Options::ClockType() == ClockType::CPU) { diff --git a/svf/lib/Util/SVFUtil.cpp b/svf/lib/Util/SVFUtil.cpp index 5df9c925f2..dc80a82ab2 100644 --- a/svf/lib/Util/SVFUtil.cpp +++ b/svf/lib/Util/SVFUtil.cpp @@ -27,8 +27,10 @@ * Author: Yulei Sui */ +#ifndef _WIN32 #include #include +#endif #include "Util/Options.h" #include "Util/SVFUtil.h" @@ -37,7 +39,9 @@ #include "SVFIR/SVFIR.h" #include "SVFIR/SVFVariables.h" +#ifndef _WIN32 #include /// increase stack size +#endif using namespace SVF; @@ -232,6 +236,7 @@ bool SVFUtil::getMemoryUsageKB(u32_t* vmrss_kb, u32_t* vmsize_kb) */ void SVFUtil::increaseStackSize() { +#ifndef _WIN32 const rlim_t kStackSize = 256L * 1024L * 1024L; // min stack size = 256 Mb struct rlimit rl; int result = getrlimit(RLIMIT_STACK, &rl); @@ -245,6 +250,7 @@ void SVFUtil::increaseStackSize() writeWrnMsg("setrlimit returned result !=0 \n"); } } +#endif } @@ -280,6 +286,7 @@ void SVFUtil::timeLimitReached(int) bool SVFUtil::startAnalysisLimitTimer(unsigned timeLimit) { +#ifndef _WIN32 if (timeLimit == 0) return false; // If an alarm is already set, don't set another. That means this analysis @@ -295,13 +302,21 @@ bool SVFUtil::startAnalysisLimitTimer(unsigned timeLimit) signal(SIGALRM, &timeLimitReached); alarm(timeLimit); return true; +#else + (void)timeLimit; + return false; +#endif } /// Stops an analysis timer. limitTimerSet indicates whether the caller set the /// timer or not (return value of startLimitTimer). void SVFUtil::stopAnalysisLimitTimer(bool limitTimerSet) { +#ifndef _WIN32 if (limitTimerSet) alarm(0); +#else + (void)limitTimerSet; +#endif } /// Match arguments for callsite at caller and callee diff --git a/svf/lib/Util/ThreadAPI.cpp b/svf/lib/Util/ThreadAPI.cpp index f0dc8eab3a..b397886014 100644 --- a/svf/lib/Util/ThreadAPI.cpp +++ b/svf/lib/Util/ThreadAPI.cpp @@ -31,21 +31,21 @@ #define THREADAPI_CPP_ #include "Util/ThreadAPI.h" -#include "Util/SVFUtil.h" #include "Graphs/CallGraph.h" -#include "SVFIR/SVFIR.h" #include "MemoryModel/PointerAnalysis.h" +#include "SVFIR/SVFIR.h" +#include "Util/SVFUtil.h" -#include /// std output +#include /// for setw +#include /// std output #include -#include /// for setw using namespace std; namespace { -SVF::NodeBS collectJoinedThreadObjects(SVF::PointerAnalysis* pta, - const SVF::SVFVar* joinArg, - SVF::ThreadAPI::ForkJoinAliasCache& cache) +SVF::NodeBS collectJoinedThreadObjects( + SVF::PointerAnalysis* pta, const SVF::SVFVar* joinArg, + SVF::ThreadAPI::ForkJoinAliasCache& cache) { SVF::Map::const_iterator cacheIt = cache.joinedThreadObjects.find(joinArg); @@ -64,16 +64,21 @@ SVF::NodeBS collectJoinedThreadObjects(SVF::PointerAnalysis* pta, for (const SVF::SVFStmt* st : v->getInEdges()) { - if (const SVF::LoadStmt* load = SVF::SVFUtil::dyn_cast(st)) + if (const SVF::LoadStmt* load = + SVF::SVFUtil::dyn_cast(st)) objects |= pta->getPts(load->getRHSVarID()).toNodeBS(); - else if (const SVF::CopyStmt* copy = SVF::SVFUtil::dyn_cast(st)) + else if (const SVF::CopyStmt* copy = + SVF::SVFUtil::dyn_cast(st)) worklist.push_back(copy->getRHSVar()); - else if (const SVF::PhiStmt* phi = SVF::SVFUtil::dyn_cast(st)) + else if (const SVF::PhiStmt* phi = + SVF::SVFUtil::dyn_cast(st)) for (SVF::u32_t i = 0; i < phi->getOpVarNum(); ++i) worklist.push_back(phi->getOpVar(i)); - else if (const SVF::GepStmt* gep = SVF::SVFUtil::dyn_cast(st)) + else if (const SVF::GepStmt* gep = + SVF::SVFUtil::dyn_cast(st)) worklist.push_back(gep->getRHSVar()); - else if (const SVF::CallPE* call = SVF::SVFUtil::dyn_cast(st)) + else if (const SVF::CallPE* call = + SVF::SVFUtil::dyn_cast(st)) for (SVF::u32_t i = 0; i < call->getOpVarNum(); ++i) worklist.push_back(call->getOpVar(i)); } @@ -82,7 +87,7 @@ SVF::NodeBS collectJoinedThreadObjects(SVF::PointerAnalysis* pta, cache.joinedThreadObjects[joinArg] = objects; return objects; } -} +} // namespace using namespace SVF; @@ -94,19 +99,22 @@ namespace /// string and type pair struct ei_pair { - const char *n; + const char* n; ThreadAPI::TD_TYPE t; }; } // End anonymous namespace -//Each (name, type) pair will be inserted into the map. -//All entries of the same type must occur together (for error detection). -static const ei_pair ei_pairs[]= -{ - //The current llvm-gcc puts in the \01. +// Each (name, type) pair will be inserted into the map. +// All entries of the same type must occur together (for error detection). +static const ei_pair ei_pairs[] = { + // The current llvm-gcc puts in the \01. {"pthread_create", ThreadAPI::TD_FORK}, {"apr_thread_create", ThreadAPI::TD_FORK}, + {"CreateThread", ThreadAPI::TD_FORK}, + {"\01CreateThread", ThreadAPI::TD_FORK}, + {"_beginthreadex", ThreadAPI::TD_FORK}, + {"\01_beginthreadex", ThreadAPI::TD_FORK}, {"pthread_join", ThreadAPI::TD_JOIN}, {"\01_pthread_join", ThreadAPI::TD_JOIN}, {"pthread_cancel", ThreadAPI::TD_JOIN}, @@ -115,13 +123,17 @@ static const ei_pair ei_pairs[]= {"sem_wait", ThreadAPI::TD_ACQUIRE}, {"_spin_lock", ThreadAPI::TD_ACQUIRE}, {"SRE_SplSpecLockEx", ThreadAPI::TD_ACQUIRE}, + {"EnterCriticalSection", ThreadAPI::TD_ACQUIRE}, + {"\01EnterCriticalSection", ThreadAPI::TD_ACQUIRE}, {"pthread_mutex_trylock", ThreadAPI::TD_TRY_ACQUIRE}, {"pthread_mutex_unlock", ThreadAPI::TD_RELEASE}, {"pthread_rwlock_unlock", ThreadAPI::TD_RELEASE}, {"sem_post", ThreadAPI::TD_RELEASE}, {"_spin_unlock", ThreadAPI::TD_RELEASE}, {"SRE_SplSpecUnlockEx", ThreadAPI::TD_RELEASE}, -// {"pthread_cancel", ThreadAPI::TD_CANCEL}, + {"LeaveCriticalSection", ThreadAPI::TD_RELEASE}, + {"\01LeaveCriticalSection", ThreadAPI::TD_RELEASE}, + // {"pthread_cancel", ThreadAPI::TD_CANCEL}, {"pthread_exit", ThreadAPI::TD_EXIT}, {"pthread_detach", ThreadAPI::TD_DETACH}, {"pthread_cond_wait", ThreadAPI::TD_COND_WAIT}, @@ -137,9 +149,8 @@ static const ei_pair ei_pairs[]= // Hare APIs {"hare_parallel_for", ThreadAPI::HARE_PAR_FOR}, - //This must be the last entry. - {0, ThreadAPI::TD_DUMMY} -}; + // This must be the last entry. + {0, ThreadAPI::TD_DUMMY}}; /*! * initialize the map @@ -147,56 +158,56 @@ static const ei_pair ei_pairs[]= void ThreadAPI::init() { set t_seen; - TD_TYPE prev_t= TD_DUMMY; + TD_TYPE prev_t = TD_DUMMY; t_seen.insert(TD_DUMMY); - for(const ei_pair *p= ei_pairs; p->n; ++p) + for (const ei_pair* p = ei_pairs; p->n; ++p) { - if(p->t != prev_t) + if (p->t != prev_t) { - //This will detect if you move an entry to another block - // but forget to change the type. - if(t_seen.count(p->t)) + // This will detect if you move an entry to another block + // but forget to change the type. + if (t_seen.count(p->t)) { fputs(p->n, stderr); putc('\n', stderr); assert(!"ei_pairs not grouped by type"); } t_seen.insert(p->t); - prev_t= p->t; + prev_t = p->t; } - if(tdAPIMap.count(p->n)) + if (tdAPIMap.count(p->n)) { fputs(p->n, stderr); putc('\n', stderr); assert(!"duplicate name in ei_pairs"); } - tdAPIMap[p->n]= p->t; + tdAPIMap[p->n] = p->t; } } /// Get the function type if it is a threadAPI function ThreadAPI::TD_TYPE ThreadAPI::getType(const FunObjVar* F) const { - if(F) + if (F) { - TDAPIMap::const_iterator it= tdAPIMap.find(F->getName()); - if(it != tdAPIMap.end()) + TDAPIMap::const_iterator it = tdAPIMap.find(F->getName()); + if (it != tdAPIMap.end()) return it->second; } return TD_DUMMY; } -bool ThreadAPI::isTDFork(const CallICFGNode *inst) const +bool ThreadAPI::isTDFork(const CallICFGNode* inst) const { return getType(inst->getCalledFunction()) == TD_FORK; } -bool ThreadAPI::isTDJoin(const CallICFGNode *inst) const +bool ThreadAPI::isTDJoin(const CallICFGNode* inst) const { return getType(inst->getCalledFunction()) == TD_JOIN; } -bool ThreadAPI::isTDExit(const CallICFGNode *inst) const +bool ThreadAPI::isTDExit(const CallICFGNode* inst) const { return getType(inst->getCalledFunction()) == TD_EXIT; } @@ -206,24 +217,31 @@ bool ThreadAPI::isTDAcquire(const CallICFGNode* inst) const return getType(inst->getCalledFunction()) == TD_ACQUIRE; } -bool ThreadAPI::isTDRelease(const CallICFGNode *inst) const +bool ThreadAPI::isTDRelease(const CallICFGNode* inst) const { return getType(inst->getCalledFunction()) == TD_RELEASE; } -bool ThreadAPI::isTDBarWait(const CallICFGNode *inst) const +bool ThreadAPI::isTDBarWait(const CallICFGNode* inst) const { return getType(inst->getCalledFunction()) == TD_BAR_WAIT; } - -const ValVar* ThreadAPI::getForkedThread(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getForkedThread(const CallICFGNode* inst) const { assert(isTDFork(inst) && "not a thread fork function!"); + const FunObjVar* fun = inst->getCalledFunction(); + if (fun && (fun->getName() == "CreateThread" || + fun->getName() == "_beginthreadex" || + fun->getName() == "\01CreateThread" || + fun->getName() == "\01_beginthreadex")) + { + return inst->getArgument(5); + } return inst->getArgument(0); } -const ValVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getForkedFun(const CallICFGNode* inst) const { assert(isTDFork(inst) && "not a thread fork function!"); return inst->getArgument(2); @@ -231,7 +249,7 @@ const ValVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const /// Return the forth argument of the call, /// Note that, it is the sole argument of start routine ( a void* pointer ) -const ValVar* ThreadAPI::getActualParmAtForkSite(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getActualParmAtForkSite(const CallICFGNode* inst) const { assert(isTDFork(inst) && "not a thread fork function!"); return inst->getArgument(3); @@ -239,28 +257,31 @@ const ValVar* ThreadAPI::getActualParmAtForkSite(const CallICFGNode *inst) const const SVFVar* ThreadAPI::getFormalParmOfForkedFun(const FunObjVar* F) const { - assert(PAG::getPAG()->hasFunArgsList(F) && "forked function has no args list!"); + assert(PAG::getPAG()->hasFunArgsList(F) && + "forked function has no args list!"); const SVFIR::ValVarList& funArgList = PAG::getPAG()->getFunArgsList(F); // in pthread, forked functions are of type void *()(void *args) - assert(funArgList.size() == 1 && "num of pthread forked function args is not 1!"); + assert(funArgList.size() == 1 && + "num of pthread forked function args is not 1!"); return funArgList[0]; } -const SVFVar* ThreadAPI::getRetParmAtJoinedSite(const CallICFGNode *inst) const +const SVFVar* ThreadAPI::getRetParmAtJoinedSite(const CallICFGNode* inst) const { assert(isTDJoin(inst) && "not a thread join function!"); return inst->getArgument(1); } -const SVFVar* ThreadAPI::getLockVal(const ICFGNode *cs) const +const SVFVar* ThreadAPI::getLockVal(const ICFGNode* cs) const { const CallICFGNode* call = SVFUtil::dyn_cast(cs); assert(call && "not a call ICFGNode?"); - assert((isTDAcquire(call) || isTDRelease(call)) && "not a lock acquire or release function"); + assert((isTDAcquire(call) || isTDRelease(call)) && + "not a lock acquire or release function"); return call->getArgument(0); } -const SVFVar* ThreadAPI::getJoinedThread(const CallICFGNode *cs) const +const SVFVar* ThreadAPI::getJoinedThread(const CallICFGNode* cs) const { assert(isTDJoin(cs) && "not a thread join function!"); return cs->getArgument(0); @@ -273,14 +294,16 @@ const SVFVar* ThreadAPI::getJoinedThread(const CallICFGNode *cs) const * - joinArg is the value first argument of pthread_join * (pthread_t) */ -bool ThreadAPI::isAliasedForkJoin(PointerAnalysis *pta, const SVFVar *forkArg, const SVFVar *joinArg) const +bool ThreadAPI::isAliasedForkJoin(PointerAnalysis* pta, const SVFVar* forkArg, + const SVFVar* joinArg) const { ForkJoinAliasCache cache; return isAliasedForkJoin(pta, forkArg, joinArg, cache); } -bool ThreadAPI::isAliasedForkJoin(PointerAnalysis *pta, const SVFVar *forkArg, - const SVFVar *joinArg, ForkJoinAliasCache& cache) const +bool ThreadAPI::isAliasedForkJoin(PointerAnalysis* pta, const SVFVar* forkArg, + const SVFVar* joinArg, + ForkJoinAliasCache& cache) const { // pthread_create receives &t (a pointer to the pthread_t object), so the // forked thread is identified by the pthread_t object(s) in pts(forkArg). @@ -289,7 +312,8 @@ bool ThreadAPI::isAliasedForkJoin(PointerAnalysis *pta, const SVFVar *forkArg, if (forkObjs.toNodeBS().intersects(joinedObjs)) return true; - // (1) Direct case: the join handle is itself a pointer to the same pthread_t. + // (1) Direct case: the join handle is itself a pointer to the same + // pthread_t. for (NodeID o : forkObjs) if (pta->alias(o, joinArg->getId())) return true; @@ -299,9 +323,9 @@ bool ThreadAPI::isAliasedForkJoin(PointerAnalysis *pta, const SVFVar *forkArg, // value is loaded from the pthread_t storage, possibly after flowing // through copies / phis / casts / by-value parameter passing. We // backward value-track the join handle to every load it may originate - // from and check whether the loaded-from storage is the fork's pthread_t - // object. This covers the common shapes soundly (an over-approximate - // match only adds a sound join-related value flow). + // from and check whether the loaded-from storage is the fork's + // pthread_t object. This covers the common shapes soundly (an + // over-approximate match only adds a sound join-related value flow). return false; } @@ -356,122 +380,106 @@ void ThreadAPI::performAPIStat() statInit(tdAPIStatMap); const CallGraph* svfirCallGraph = PAG::getPAG()->getCallGraph(); - for (const auto& item: *svfirCallGraph) + for (const auto& item : *svfirCallGraph) { - for (FunObjVar::const_bb_iterator bit = (item.second)->getFunction()->begin(), ebit = (item.second)->getFunction()->end(); bit != ebit; ++bit) + for (FunObjVar::const_bb_iterator + bit = (item.second)->getFunction()->begin(), + ebit = (item.second)->getFunction()->end(); + bit != ebit; ++bit) { const SVFBasicBlock* bb = bit->second; - for (const auto& svfInst: bb->getICFGNodeList()) + for (const auto& svfInst : bb->getICFGNodeList()) { if (!SVFUtil::isCallSite(svfInst)) continue; - const FunObjVar* fun = SVFUtil::cast(svfInst)->getCalledFunction(); + const FunObjVar* fun = + SVFUtil::cast(svfInst)->getCalledFunction(); TD_TYPE type = getType(fun); switch (type) { - case TD_FORK: - { + case TD_FORK: { tdAPIStatMap["pthread_create"]++; break; } - case TD_JOIN: - { + case TD_JOIN: { tdAPIStatMap["pthread_join"]++; break; } - case TD_ACQUIRE: - { + case TD_ACQUIRE: { tdAPIStatMap["pthread_mutex_lock"]++; break; } - case TD_TRY_ACQUIRE: - { + case TD_TRY_ACQUIRE: { tdAPIStatMap["pthread_mutex_trylock"]++; break; } - case TD_RELEASE: - { + case TD_RELEASE: { tdAPIStatMap["pthread_mutex_unlock"]++; break; } - case TD_CANCEL: - { + case TD_CANCEL: { tdAPIStatMap["pthread_cancel"]++; break; } - case TD_EXIT: - { + case TD_EXIT: { tdAPIStatMap["pthread_exit"]++; break; } - case TD_DETACH: - { + case TD_DETACH: { tdAPIStatMap["pthread_detach"]++; break; } - case TD_COND_WAIT: - { + case TD_COND_WAIT: { tdAPIStatMap["pthread_cond_wait"]++; break; } - case TD_COND_SIGNAL: - { + case TD_COND_SIGNAL: { tdAPIStatMap["pthread_cond_signal"]++; break; } - case TD_COND_BROADCAST: - { + case TD_COND_BROADCAST: { tdAPIStatMap["pthread_cond_broadcast"]++; break; } - case TD_CONDVAR_INI: - { + case TD_CONDVAR_INI: { tdAPIStatMap["pthread_cond_init"]++; break; } - case TD_CONDVAR_DESTROY: - { + case TD_CONDVAR_DESTROY: { tdAPIStatMap["pthread_cond_destroy"]++; break; } - case TD_MUTEX_INI: - { + case TD_MUTEX_INI: { tdAPIStatMap["pthread_mutex_init"]++; break; } - case TD_MUTEX_DESTROY: - { + case TD_MUTEX_DESTROY: { tdAPIStatMap["pthread_mutex_destroy"]++; break; } - case TD_BAR_INIT: - { + case TD_BAR_INIT: { tdAPIStatMap["pthread_barrier_init"]++; break; } - case TD_BAR_WAIT: - { + case TD_BAR_WAIT: { tdAPIStatMap["pthread_barrier_wait"]++; break; } - case HARE_PAR_FOR: - { + case HARE_PAR_FOR: { tdAPIStatMap["hare_parallel_for"]++; break; } - case TD_DUMMY: - { + case TD_DUMMY: { break; } } } } - } std::string name(PAG::getPAG()->getModuleIdentifier()); - std::vector fullNames = SVFUtil::split(name,'/'); + std::vector fullNames = SVFUtil::split(name, '/'); if (fullNames.size() > 1) { name = fullNames[fullNames.size() - 1]; @@ -480,17 +488,17 @@ void ThreadAPI::performAPIStat() << ")###############\n"; SVFUtil::outs().flags(std::ios::left); unsigned field_width = 20; - for (Map::iterator it = tdAPIStatMap.begin(), eit = - tdAPIStatMap.end(); it != eit; ++it) + for (Map::iterator it = tdAPIStatMap.begin(), + eit = tdAPIStatMap.end(); + it != eit; ++it) { std::string apiName = it->first; // format out put with width 20 space - SVFUtil::outs() << std::setw(field_width) << apiName << " : " << it->second - << "\n"; + SVFUtil::outs() << std::setw(field_width) << apiName << " : " + << it->second << "\n"; } SVFUtil::outs() << "#######################################################" << std::endl; - } #endif /* THREADAPI_CPP_ */ diff --git a/svf/lib/WPA/Andersen.cpp b/svf/lib/WPA/Andersen.cpp index b3401a89fb..598dcc7d31 100644 --- a/svf/lib/WPA/Andersen.cpp +++ b/svf/lib/WPA/Andersen.cpp @@ -27,20 +27,19 @@ * Author: Yulei Sui */ +#include "WPA/Andersen.h" #include "Graphs/ThreadCallGraph.h" #include "MemoryModel/PointsTo.h" -#include "WPA/Andersen.h" -#include "WPA/Steensgaard.h" -#include "WPA/WPAStat.h" #include "Util/GeneralType.h" #include "Util/Options.h" #include "Util/SVFUtil.h" +#include "WPA/Steensgaard.h" +#include "WPA/WPAStat.h" using namespace SVF; using namespace SVFUtil; using namespace std; - u32_t AndersenBase::numOfProcessedAddr = 0; u32_t AndersenBase::numOfProcessedCopy = 0; u32_t AndersenBase::numOfProcessedGep = 0; @@ -104,7 +103,8 @@ void AndersenBase::solveConstraints() // Start solving constraints DBOUT(DGENERAL, outs() << SVFUtil::pasMsg("Start Solving Constraints\n")); - bool limitTimerSet = SVFUtil::startAnalysisLimitTimer(Options::AnderTimeLimit()); + bool limitTimerSet = + SVFUtil::startAnalysisLimitTimer(Options::AnderTimeLimit()); initWorklist(); do @@ -120,8 +120,7 @@ void AndersenBase::solveConstraints() if (updateCallGraph(getIndirectCallsites())) reanalyze = true; - } - while (reanalyze); + } while (reanalyze); // Analysis is finished, reset the alarm if we set it. SVFUtil::stopAnalysisLimitTimer(limitTimerSet); @@ -134,13 +133,13 @@ void AndersenBase::solveConstraints() */ void AndersenBase::analyze() { - if(!Options::ReadAnder().empty()) + if (!Options::ReadAnder().empty()) { readPtsFromFile(Options::ReadAnder()); } else { - if(Options::WriteAnder().empty()) + if (Options::WriteAnder().empty()) { initialize(); solveConstraints(); @@ -165,9 +164,10 @@ void AndersenBase::readPtsFromFile(const std::string& filename) } /*! - * Andersen analysis: solve constraints and write pointer analysis result to file + * Andersen analysis: solve constraints and write pointer analysis result to + * file */ -void AndersenBase:: solveAndwritePtsToFile(const std::string& filename) +void AndersenBase::solveAndwritePtsToFile(const std::string& filename) { /// Initialization for the Solver initialize(); @@ -182,11 +182,13 @@ void AndersenBase:: solveAndwritePtsToFile(const std::string& filename) void AndersenBase::cleanConsCG(NodeID id) { consCG->resetSubs(consCG->getRep(id)); - for (NodeID sub: consCG->getSubs(id)) + for (NodeID sub : consCG->getSubs(id)) consCG->resetRep(sub); consCG->resetSubs(id); consCG->resetRep(id); - assert(!consCG->hasGNode(id) && "this is either a rep nodeid or a sub nodeid should have already been merged to its field-insensitive base! "); + assert(!consCG->hasGNode(id) && + "this is either a rep nodeid or a sub nodeid should have already " + "been merged to its field-insensitive base! "); } bool AndersenBase::updateCallGraph(const CallSiteToFunPtrMap& callsites) @@ -198,11 +200,11 @@ bool AndersenBase::updateCallGraph(const CallSiteToFunPtrMap& callsites) onTheFlyCallGraphSolve(callsites, newEdges); NodePairSet cpySrcNodes; /// nodes as a src of a generated new copy edge for (CallEdgeMap::iterator it = newEdges.begin(), eit = newEdges.end(); - it != eit; ++it) + it != eit; ++it) { for (FunctionSet::iterator cit = it->second.begin(), - ecit = it->second.end(); - cit != ecit; ++cit) + ecit = it->second.end(); + cit != ecit; ++cit) { connectCaller2CalleeParams(it->first, *cit, cpySrcNodes); } @@ -211,8 +213,8 @@ bool AndersenBase::updateCallGraph(const CallSiteToFunPtrMap& callsites) bool hasNewForkEdges = updateThreadCallGraph(callsites, cpySrcNodes); for (NodePairSet::iterator it = cpySrcNodes.begin(), - eit = cpySrcNodes.end(); - it != eit; ++it) + eit = cpySrcNodes.end(); + it != eit; ++it) { pushIntoWorklist(it->first); } @@ -224,15 +226,17 @@ bool AndersenBase::updateCallGraph(const CallSiteToFunPtrMap& callsites) } bool AndersenBase::updateThreadCallGraph(const CallSiteToFunPtrMap& callsites, - NodePairSet& cpySrcNodes) + NodePairSet& cpySrcNodes) { CallEdgeMap newForkEdges; onTheFlyThreadCallGraphSolve(callsites, newForkEdges); - for (CallEdgeMap::iterator it = newForkEdges.begin(), eit = newForkEdges.end(); it != eit; it++) + for (CallEdgeMap::iterator it = newForkEdges.begin(), + eit = newForkEdges.end(); + it != eit; it++) { for (FunctionSet::iterator cit = it->second.begin(), - ecit = it->second.end(); - cit != ecit; ++cit) + ecit = it->second.end(); + cit != ecit; ++cit) { connectCaller2ForkedFunParams(it->first, *cit, cpySrcNodes); } @@ -243,24 +247,28 @@ bool AndersenBase::updateThreadCallGraph(const CallSiteToFunPtrMap& callsites, /*! * Connect formal and actual parameters for indirect forksites */ -void AndersenBase::connectCaller2ForkedFunParams(const CallICFGNode* cs, const FunObjVar* F, - NodePairSet& cpySrcNodes) +void AndersenBase::connectCaller2ForkedFunParams(const CallICFGNode* cs, + const FunObjVar* F, + NodePairSet& cpySrcNodes) { assert(F); DBOUT(DAndersen, outs() << "connect parameters from indirect forksite " - << cs->valueOnlyToString() << " to forked function " - << *F << "\n"); + << cs->valueOnlyToString() << " to forked function " + << *F << "\n"); - ThreadCallGraph *tdCallGraph = SVFUtil::dyn_cast(callgraph); + ThreadCallGraph* tdCallGraph = + SVFUtil::dyn_cast(callgraph); - const PAGNode *cs_arg = tdCallGraph->getThreadAPI()->getActualParmAtForkSite(cs); - const PAGNode *fun_arg = tdCallGraph->getThreadAPI()->getFormalParmOfForkedFun(F); + const PAGNode* cs_arg = + tdCallGraph->getThreadAPI()->getActualParmAtForkSite(cs); + const PAGNode* fun_arg = + tdCallGraph->getThreadAPI()->getFormalParmOfForkedFun(F); - if(cs_arg->isPointer() && fun_arg->isPointer()) + if (cs_arg->isPointer() && fun_arg->isPointer()) { - DBOUT(DAndersen, outs() << "process actual parm" - << cs_arg->toString() << "\n"); + DBOUT(DAndersen, + outs() << "process actual parm" << cs_arg->toString() << "\n"); NodeID srcAA = sccRepNode(cs_arg->getId()); NodeID dstFA = sccRepNode(fun_arg->getId()); if (addCopyEdge(srcAA, dstFA)) @@ -274,18 +282,22 @@ void AndersenBase::connectCaller2ForkedFunParams(const CallICFGNode* cs, const F // * Connect formal and actual parameters for indirect callsites // */ void AndersenBase::connectCaller2CalleeParams(const CallICFGNode* cs, - const FunObjVar* F, NodePairSet &cpySrcNodes) + const FunObjVar* F, + NodePairSet& cpySrcNodes) { assert(F); - DBOUT(DAndersen, outs() << "connect parameters from indirect callsite " << cs->valueOnlyToString() << " to callee " << *F << "\n"); + DBOUT(DAndersen, outs() << "connect parameters from indirect callsite " + << cs->valueOnlyToString() << " to callee " << *F + << "\n"); const CallICFGNode* callBlockNode = cs; const RetICFGNode* retBlockNode = cs->getRetICFGNode(); - if(SVFUtil::isHeapAllocExtFunViaRet(F) && pag->callsiteHasRet(retBlockNode)) + if (SVFUtil::isHeapAllocExtFunViaRet(F) && + pag->callsiteHasRet(retBlockNode)) { - heapAllocatorViaIndCall(cs,cpySrcNodes); + heapAllocatorViaIndCall(cs, cpySrcNodes); } if (pag->funHasRet(F) && pag->callsiteHasRet(retBlockNode)) @@ -296,9 +308,9 @@ void AndersenBase::connectCaller2CalleeParams(const CallICFGNode* cs, { NodeID dstrec = sccRepNode(cs_return->getId()); NodeID srcret = sccRepNode(fun_return->getId()); - if(addCopyEdge(srcret, dstrec)) + if (addCopyEdge(srcret, dstrec)) { - cpySrcNodes.insert(std::make_pair(srcret,dstrec)); + cpySrcNodes.insert(std::make_pair(srcret, dstrec)); } } else @@ -311,54 +323,59 @@ void AndersenBase::connectCaller2CalleeParams(const CallICFGNode* cs, { // connect actual and formal param - const SVFIR::ValVarList& csArgList = pag->getCallSiteArgsList(callBlockNode); + const SVFIR::ValVarList& csArgList = + pag->getCallSiteArgsList(callBlockNode); const SVFIR::ValVarList& funArgList = pag->getFunArgsList(F); - //Go through the fixed parameters. + // Go through the fixed parameters. DBOUT(DPAGBuild, outs() << " args:"); - SVFIR::ValVarList::const_iterator funArgIt = funArgList.begin(), funArgEit = funArgList.end(); - SVFIR::ValVarList::const_iterator csArgIt = csArgList.begin(), csArgEit = csArgList.end(); + SVFIR::ValVarList::const_iterator funArgIt = funArgList.begin(), + funArgEit = funArgList.end(); + SVFIR::ValVarList::const_iterator csArgIt = csArgList.begin(), + csArgEit = csArgList.end(); for (; funArgIt != funArgEit; ++csArgIt, ++funArgIt) { - //Some programs (e.g. Linux kernel) leave unneeded parameters empty. - if (csArgIt == csArgEit) + // Some programs (e.g. Linux kernel) leave unneeded parameters + // empty. + if (csArgIt == csArgEit) { DBOUT(DAndersen, outs() << " !! not enough args\n"); break; } - const PAGNode *cs_arg = *csArgIt ; - const PAGNode *fun_arg = *funArgIt; + const PAGNode* cs_arg = *csArgIt; + const PAGNode* fun_arg = *funArgIt; if (cs_arg->isPointer() && fun_arg->isPointer()) { - DBOUT(DAndersen, outs() << "process actual parm " << cs_arg->toString() << " \n"); + DBOUT(DAndersen, outs() << "process actual parm " + << cs_arg->toString() << " \n"); NodeID srcAA = sccRepNode(cs_arg->getId()); NodeID dstFA = sccRepNode(fun_arg->getId()); - if(addCopyEdge(srcAA, dstFA)) + if (addCopyEdge(srcAA, dstFA)) { - cpySrcNodes.insert(std::make_pair(srcAA,dstFA)); + cpySrcNodes.insert(std::make_pair(srcAA, dstFA)); } } } - //Any remaining actual args must be varargs. + // Any remaining actual args must be varargs. if (F->isVarArg()) { NodeID vaF = sccRepNode(pag->getVarargNode(F)); DBOUT(DPAGBuild, outs() << "\n varargs:"); for (; csArgIt != csArgEit; ++csArgIt) { - const PAGNode *cs_arg = *csArgIt; + const PAGNode* cs_arg = *csArgIt; if (cs_arg->isPointer()) { NodeID vnAA = sccRepNode(cs_arg->getId()); - if (addCopyEdge(vnAA,vaF)) + if (addCopyEdge(vnAA, vaF)) { - cpySrcNodes.insert(std::make_pair(vnAA,vaF)); + cpySrcNodes.insert(std::make_pair(vnAA, vaF)); } } } } - if(csArgIt != csArgEit) + if (csArgIt != csArgEit) { writeWrnMsg("too many args to non-vararg func."); writeWrnMsg("(" + cs->getSourceLoc() + ")"); @@ -366,14 +383,15 @@ void AndersenBase::connectCaller2CalleeParams(const CallICFGNode* cs, } } -void AndersenBase::heapAllocatorViaIndCall(const CallICFGNode* cs, NodePairSet &cpySrcNodes) +void AndersenBase::heapAllocatorViaIndCall(const CallICFGNode* cs, + NodePairSet& cpySrcNodes) { assert(cs->getCalledFunction() == nullptr && "not an indirect callsite?"); const RetICFGNode* retBlockNode = cs->getRetICFGNode(); const PAGNode* cs_return = pag->getCallSiteRet(retBlockNode); NodeID srcret; CallSite2DummyValPN::const_iterator it = callsite2DummyValPN.find(cs); - if(it != callsite2DummyValPN.end()) + if (it != callsite2DummyValPN.end()) { srcret = sccRepNode(it->second); } @@ -381,26 +399,26 @@ void AndersenBase::heapAllocatorViaIndCall(const CallICFGNode* cs, NodePairSet & { NodeID valNode = pag->addDummyValNode(); NodeID objNode = pag->addDummyObjNode(cs->getType()); - addPts(valNode,objNode); - callsite2DummyValPN.insert(std::make_pair(cs,valNode)); - consCG->addConstraintNode(new ConstraintNode(valNode),valNode); - consCG->addConstraintNode(new ConstraintNode(objNode),objNode); + addPts(valNode, objNode); + callsite2DummyValPN.insert(std::make_pair(cs, valNode)); + consCG->addConstraintNode(new ConstraintNode(valNode), valNode); + consCG->addConstraintNode(new ConstraintNode(objNode), objNode); srcret = valNode; } NodeID dstrec = sccRepNode(cs_return->getId()); - if(addCopyEdge(srcret, dstrec)) - cpySrcNodes.insert(std::make_pair(srcret,dstrec)); + if (addCopyEdge(srcret, dstrec)) + cpySrcNodes.insert(std::make_pair(srcret, dstrec)); } void AndersenBase::normalizePointsTo() { - SVFIR::MemObjToFieldsMap &memToFieldsMap = pag->getMemToFieldsMap(); - SVFIR::OffsetToGepVarMap &GepObjVarMap = pag->getGepObjNodeMap(); + SVFIR::MemObjToFieldsMap& memToFieldsMap = pag->getMemToFieldsMap(); + SVFIR::OffsetToGepVarMap& GepObjVarMap = pag->getGepObjNodeMap(); // clear GepObjVarMap/memToFieldsMap/nodeToSubsMap/nodeToRepMap // for redundant gepnodes and remove those nodes from pag - for (NodeID n: redundantGepNodes) + for (NodeID n : redundantGepNodes) { NodeID base = pag->getBaseObjVarID(n); const GepObjVar* gepNode = pag->getGepObjVar(n); @@ -422,7 +440,8 @@ void Andersen::initialize() resetData(); AndersenBase::initialize(); - if (Options::ClusterAnder()) cluster(); + if (Options::ClusterAnder()) + cluster(); /// Initialize worklist processAllAddr(); @@ -437,10 +456,12 @@ void Andersen::finalize() if (Options::ClusterAnder()) { Map stats; - const PTDataTy *ptd = getPTDataTy(); + const PTDataTy* ptd = getPTDataTy(); // TODO: should we use liveOnly? // TODO: parameterise final arg. - NodeIDAllocator::Clusterer::evaluate(*PointsTo::getCurrentBestNodeMapping(), ptd->getAllPts(true), stats, true); + NodeIDAllocator::Clusterer::evaluate( + *PointsTo::getCurrentBestNodeMapping(), ptd->getAllPts(true), stats, + true); if (print_stat) { NodeIDAllocator::Clusterer::printStats("post-main", stats); @@ -497,16 +518,18 @@ void Andersen::handleCopyGep(ConstraintNode* node) /*! * Process load and store edges */ -void Andersen::handleLoadStore(ConstraintNode *node) +void Andersen::handleLoadStore(ConstraintNode* node) { NodeID nodeId = node->getId(); - for (PointsTo::iterator piter = getPts(nodeId).begin(), epiter = - getPts(nodeId).end(); piter != epiter; ++piter) + for (PointsTo::iterator piter = getPts(nodeId).begin(), + epiter = getPts(nodeId).end(); + piter != epiter; ++piter) { NodeID ptd = *piter; // handle load for (ConstraintNode::const_iterator it = node->outgoingLoadsBegin(), - eit = node->outgoingLoadsEnd(); it != eit; ++it) + eit = node->outgoingLoadsEnd(); + it != eit; ++it) { if (processLoad(ptd, *it)) pushIntoWorklist(ptd); @@ -514,7 +537,8 @@ void Andersen::handleLoadStore(ConstraintNode *node) // handle store for (ConstraintNode::const_iterator it = node->incomingStoresBegin(), - eit = node->incomingStoresEnd(); it != eit; ++it) + eit = node->incomingStoresEnd(); + it != eit; ++it) { if (processStore(ptd, *it)) pushIntoWorklist((*it)->getSrcID()); @@ -527,11 +551,14 @@ void Andersen::handleLoadStore(ConstraintNode *node) */ void Andersen::processAllAddr() { - for (ConstraintGraph::const_iterator nodeIt = consCG->begin(), nodeEit = consCG->end(); nodeIt != nodeEit; nodeIt++) + for (ConstraintGraph::const_iterator nodeIt = consCG->begin(), + nodeEit = consCG->end(); + nodeIt != nodeEit; nodeIt++) { - ConstraintNode * cgNode = nodeIt->second; - for (ConstraintNode::const_iterator it = cgNode->incomingAddrsBegin(), eit = cgNode->incomingAddrsEnd(); - it != eit; ++it) + ConstraintNode* cgNode = nodeIt->second; + for (ConstraintNode::const_iterator it = cgNode->incomingAddrsBegin(), + eit = cgNode->incomingAddrsEnd(); + it != eit; ++it) processAddr(SVFUtil::cast(*it)); } } @@ -545,7 +572,7 @@ void Andersen::processAddr(const AddrCGEdge* addr) NodeID dst = addr->getDstID(); NodeID src = addr->getSrcID(); - if(addPts(dst,src)) + if (addPts(dst, src)) pushIntoWorklist(dst); } @@ -559,8 +586,9 @@ bool Andersen::processLoad(NodeID node, const ConstraintEdge* load) /// TODO: New copy edges are also added for black hole obj node to /// make gcc in spec 2000 pass the flow-sensitive analysis. /// Try to handle black hole obj in an appropriate way. -// if (pag->isBlkObjOrConstantObj(node)) - if (pag->isConstantObj(node) || pag->getSVFVar(load->getDstID())->isPointer() == false) + // if (pag->isBlkObjOrConstantObj(node)) + if (pag->isConstantObj(node) || + pag->getSVFVar(load->getDstID())->isPointer() == false) return false; numOfProcessedLoad++; @@ -579,8 +607,9 @@ bool Andersen::processStore(NodeID node, const ConstraintEdge* store) /// TODO: New copy edges are also added for black hole obj node to /// make gcc in spec 2000 pass the flow-sensitive analysis. /// Try to handle black hole obj in an appropriate way -// if (pag->isBlkObjOrConstantObj(node)) - if (pag->isConstantObj(node) || pag->getSVFVar(store->getSrcID())->isPointer() == false) + // if (pag->isBlkObjOrConstantObj(node)) + if (pag->isConstantObj(node) || + pag->getSVFVar(store->getSrcID())->isPointer() == false) return false; numOfProcessedStore++; @@ -652,7 +681,8 @@ bool Andersen::processGepPts(const PointsTo& pts, const GepCGEdge* edge) tmpDstPts.set(baseId); } } - else if (const NormalGepCGEdge* normalGepEdge = SVFUtil::dyn_cast(edge)) + else if (const NormalGepCGEdge* normalGepEdge = + SVFUtil::dyn_cast(edge)) { // TODO: after the node is set to field insensitive, handling invariant // gep edge may lose precision because offsets here are ignored, and the @@ -665,7 +695,8 @@ bool Andersen::processGepPts(const PointsTo& pts, const GepCGEdge* edge) continue; } - NodeID fieldSrcPtdNode = consCG->getGepObjVar(o, normalGepEdge->getAccessPath().getConstantStructFldIdx()); + NodeID fieldSrcPtdNode = consCG->getGepObjVar( + o, normalGepEdge->getAccessPath().getConstantStructFldIdx()); tmpDstPts.set(fieldSrcPtdNode); } } @@ -684,30 +715,6 @@ bool Andersen::processGepPts(const PointsTo& pts, const GepCGEdge* edge) return false; } -/** - * Detect and collapse PWC nodes produced by processing gep edges, under the constraint of field limit. - */ -inline void Andersen::collapsePWCNode(NodeID nodeId) -{ - // If a node is a PWC node, collapse all its points-to target. - // collapseNodePts() may change the points-to set of the nodes which have been processed - // before, in this case, we may need to re-do the analysis. - if (consCG->isPWCNode(nodeId) && collapseNodePts(nodeId)) - reanalyze = true; -} - -inline void Andersen::collapseFields() -{ - while (consCG->hasNodesToBeCollapsed()) - { - NodeID node = consCG->getNextCollapseNode(); - // collapseField() may change the points-to set of the nodes which have been processed - // before, in this case, we may need to re-do the analysis. - if (collapseField(node)) - reanalyze = true; - } -} - /* * Merge constraint graph nodes based on SCC cycle detected. */ @@ -730,14 +737,14 @@ void Andersen::mergeSccCycle() } } - /** * Union points-to of subscc nodes into its rep nodes * Move incoming/outgoing direct edges of sub node to rep node */ void Andersen::mergeSccNodes(NodeID repNodeId, const NodeBS& subNodes) { - for (NodeBS::iterator nodeIt = subNodes.begin(); nodeIt != subNodes.end(); nodeIt++) + for (NodeBS::iterator nodeIt = subNodes.begin(); nodeIt != subNodes.end(); + nodeIt++) { NodeID subNodeId = *nodeIt; if (subNodeId != repNodeId) @@ -748,7 +755,8 @@ void Andersen::mergeSccNodes(NodeID repNodeId, const NodeBS& subNodes) } /** - * Collapse node's points-to set. Change all points-to elements into field-insensitive. + * Collapse node's points-to set. Change all points-to elements into + * field-insensitive. */ bool Andersen::collapseNodePts(NodeID nodeId) { @@ -756,7 +764,8 @@ bool Andersen::collapseNodePts(NodeID nodeId) const PointsTo& nodePts = getPts(nodeId); /// Points to set may be changed during collapse, so use a clone instead. PointsTo ptsClone = nodePts; - for (PointsTo::iterator ptsIt = ptsClone.begin(), ptsEit = ptsClone.end(); ptsIt != ptsEit; ptsIt++) + for (PointsTo::iterator ptsIt = ptsClone.begin(), ptsEit = ptsClone.end(); + ptsIt != ptsEit; ptsIt++) { if (isFieldInsensitive(*ptsIt)) continue; @@ -768,14 +777,15 @@ bool Andersen::collapseNodePts(NodeID nodeId) } /** - * Collapse field. make struct with the same base as nodeId become field-insensitive. + * Collapse field. make struct with the same base as nodeId become + * field-insensitive. */ bool Andersen::collapseField(NodeID nodeId) { /// Black hole doesn't have structures, no collapse is needed. /// In later versions, instead of using base node to represent the struct, - /// we'll create new field-insensitive node. To avoid creating a new "black hole" - /// node, do not collapse field for black hole node. + /// we'll create new field-insensitive node. To avoid creating a new "black + /// hole" node, do not collapse field for black hole node. if (consCG->isBlkObjOrConstantObj(nodeId)) return false; @@ -789,13 +799,16 @@ bool Andersen::collapseField(NodeID nodeId) // replace all occurrences of each field with the field-insensitive node NodeID baseId = consCG->getFIObjVar(nodeId); NodeID baseRepNodeId = consCG->sccRepNode(baseId); - NodeBS & allFields = consCG->getAllFieldsObjVars(baseId); - for (NodeBS::iterator fieldIt = allFields.begin(), fieldEit = allFields.end(); fieldIt != fieldEit; fieldIt++) + NodeBS& allFields = consCG->getAllFieldsObjVars(baseId); + for (NodeBS::iterator fieldIt = allFields.begin(), + fieldEit = allFields.end(); + fieldIt != fieldEit; fieldIt++) { NodeID fieldId = *fieldIt; if (fieldId != baseId) { - // use the reverse pts of this field node to find all pointers point to it + // use the reverse pts of this field node to find all pointers point + // to it const NodeSet revPts = getRevPts(fieldId); for (const NodeID o : revPts) { @@ -811,8 +824,10 @@ bool Andersen::collapseField(NodeID nodeId) mergeNodeToRep(fieldRepNodeId, baseRepNodeId); if (fieldId != baseRepNodeId) { - // gep node fieldId becomes redundant if it is merged to its base node who is set as field-insensitive - // two node IDs should be different otherwise this field is actually the base and should not be removed. + // gep node fieldId becomes redundant if it is merged to its + // base node who is set as field-insensitive two node IDs should + // be different otherwise this field is actually the base and + // should not be removed. redundantGepNodes.set(fieldId); } } @@ -839,7 +854,7 @@ NodeStack& Andersen::SCCDetect() WPAConstraintSolver::SCCDetect(); double sccEnd = stat->getClk(); - timeOfSCCDetection += (sccEnd - sccStart)/TIMEINTERVAL; + timeOfSCCDetection += (sccEnd - sccStart) / TIMEINTERVAL; double mergeStart = stat->getClk(); @@ -847,7 +862,7 @@ NodeStack& Andersen::SCCDetect() double mergeEnd = stat->getClk(); - timeOfSCCMerges += (mergeEnd - mergeStart)/TIMEINTERVAL; + timeOfSCCMerges += (mergeEnd - mergeStart) / TIMEINTERVAL; return getSCCDetector()->topoNodeStack(); } @@ -858,26 +873,27 @@ NodeStack& Andersen::SCCDetect() bool Andersen::mergeSrcToTgt(NodeID nodeId, NodeID newRepId) { - if(nodeId==newRepId) + if (nodeId == newRepId) return false; /// union pts of node to rep updatePropaPts(newRepId, nodeId); - unionPts(newRepId,nodeId); + unionPts(newRepId, nodeId); /// move the edges from node to rep, and remove the node ConstraintNode* node = consCG->getConstraintNode(nodeId); - bool pwc = consCG->moveEdgesToRepNode(node, consCG->getConstraintNode(newRepId)); - - /// 1. if find gep edges inside SCC cycle, the rep node will become a PWC node and - /// its pts should be collapsed later. - /// 2. if the node to be merged is already a PWC node, the rep node will also become - /// a PWC node as it will have a self-cycle gep edge. - if(node->isPWCNode()) + bool pwc = + consCG->moveEdgesToRepNode(node, consCG->getConstraintNode(newRepId)); + + /// 1. if find gep edges inside SCC cycle, the rep node will become a PWC + /// node and its pts should be collapsed later. + /// 2. if the node to be merged is already a PWC node, the rep node will + /// also become a PWC node as it will have a self-cycle gep edge. + if (node->isPWCNode()) pwc = true; /// set rep and sub relations - updateNodeRepAndSubs(node->getId(),newRepId); + updateNodeRepAndSubs(node->getId(), newRepId); consCG->removeConstraintNode(node); @@ -886,10 +902,10 @@ bool Andersen::mergeSrcToTgt(NodeID nodeId, NodeID newRepId) /* * Merge a node to its rep node based on SCC detection */ -void Andersen::mergeNodeToRep(NodeID nodeId,NodeID newRepId) +void Andersen::mergeNodeToRep(NodeID nodeId, NodeID newRepId) { - if (mergeSrcToTgt(nodeId,newRepId)) + if (mergeSrcToTgt(nodeId, newRepId)) consCG->setPWCNode(newRepId); } @@ -898,26 +914,30 @@ void Andersen::mergeNodeToRep(NodeID nodeId,NodeID newRepId) */ void Andersen::updateNodeRepAndSubs(NodeID nodeId, NodeID newRepId) { - consCG->setRep(nodeId,newRepId); + consCG->setRep(nodeId, newRepId); NodeBS repSubs; repSubs.set(nodeId); - /// update nodeToRepMap, for each subs of current node updates its rep to newRepId + /// update nodeToRepMap, for each subs of current node updates its rep to + /// newRepId // update nodeToSubsMap, union its subs with its rep Subs NodeBS& nodeSubs = consCG->sccSubNodes(nodeId); - for(NodeBS::iterator sit = nodeSubs.begin(), esit = nodeSubs.end(); sit!=esit; ++sit) + for (NodeBS::iterator sit = nodeSubs.begin(), esit = nodeSubs.end(); + sit != esit; ++sit) { NodeID subId = *sit; - consCG->setRep(subId,newRepId); + consCG->setRep(subId, newRepId); } repSubs |= nodeSubs; - consCG->setSubs(newRepId,repSubs); + consCG->setSubs(newRepId, repSubs); consCG->resetSubs(nodeId); } void Andersen::cluster(void) const { - assert(Options::MaxFieldLimit() == 0 && "Andersen::cluster: clustering for Andersen's is currently only supported in field-insensitive analysis"); - Steensgaard *steens = Steensgaard::createSteensgaard(pag); + assert(Options::MaxFieldLimit() == 0 && + "Andersen::cluster: clustering for Andersen's is currently only " + "supported in field-insensitive analysis"); + Steensgaard* steens = Steensgaard::createSteensgaard(pag); std::vector> keys; for (SVFIR::iterator pit = pag->begin(); pit != pag->end(); ++pit) { @@ -925,12 +945,12 @@ void Andersen::cluster(void) const } std::vector>> candidates; - PointsTo::MappingPtr nodeMapping = - std::make_shared>( - NodeIDAllocator::Clusterer::cluster(steens, keys, candidates, "aux-steens", print_stat) - ); + PointsTo::MappingPtr nodeMapping = std::make_shared>( + NodeIDAllocator::Clusterer::cluster(steens, keys, candidates, + "aux-steens", print_stat)); PointsTo::MappingPtr reverseNodeMapping = - std::make_shared>(NodeIDAllocator::Clusterer::getReverseNodeMapping(*nodeMapping)); + std::make_shared>( + NodeIDAllocator::Clusterer::getReverseNodeMapping(*nodeMapping)); PointsTo::setCurrentBestNodeMapping(nodeMapping, reverseNodeMapping); } @@ -941,7 +961,7 @@ void Andersen::cluster(void) const void Andersen::dumpTopLevelPtsTo() { for (OrderedNodeSet::iterator nIter = this->getAllValidPtrs().begin(); - nIter != this->getAllValidPtrs().end(); ++nIter) + nIter != this->getAllValidPtrs().end(); ++nIter) { const SVFVar* node = getPAG()->getSVFVar(*nIter); if (getPAG()->isValidTopLevelPtr(node)) @@ -959,15 +979,17 @@ void Andersen::dumpTopLevelPtsTo() multiset line; for (PointsTo::iterator it = pts.begin(), eit = pts.end(); - it != eit; ++it) + it != eit; ++it) { line.insert(*it); } - for (multiset::const_iterator it = line.begin(); it != line.end(); ++it) + for (multiset::const_iterator it = line.begin(); + it != line.end(); ++it) { - if(Options::PrintFieldWithBasePrefix()) + if (Options::PrintFieldWithBasePrefix()) if (auto gepNode = pag->getGepObjVar(*it)) - outs() << gepNode->getBaseNode() << "_" << gepNode->getConstantFieldIdx() << " "; + outs() << gepNode->getBaseNode() << "_" + << gepNode->getConstantFieldIdx() << " "; else outs() << *it << " "; else @@ -980,4 +1002,3 @@ void Andersen::dumpTopLevelPtsTo() outs().flush(); } -