|  | 
|  | 1 | +#!/bin/bash | 
|  | 2 | + | 
|  | 3 | +# Infer script for performing | 
|  | 4 | +# static analysis on the MariaDB codebase | 
|  | 5 | + | 
|  | 6 | +set -x -e | 
|  | 7 | + | 
|  | 8 | +if [ $# -lt 1 ]; then | 
|  | 9 | +	echo insufficient args >&2 | 
|  | 10 | +	exit 1 | 
|  | 11 | +fi | 
|  | 12 | + | 
|  | 13 | +# Testing this version | 
|  | 14 | +branch=$1 | 
|  | 15 | + | 
|  | 16 | +if [ -z "$branch" ]; then | 
|  | 17 | +  echo "usage $0 {branch/commit}" >&2 | 
|  | 18 | +  exit 1 | 
|  | 19 | +fi | 
|  | 20 | + | 
|  | 21 | +: "${JOBS:=4}" | 
|  | 22 | + | 
|  | 23 | +base=$PWD | 
|  | 24 | +result_dir=$PWD/infer_results | 
|  | 25 | + | 
|  | 26 | +## Fetch | 
|  | 27 | + | 
|  | 28 | +pushd /mnt/src | 
|  | 29 | +git fetch origin "$branch" | 
|  | 30 | +git checkout -f FETCH_HEAD | 
|  | 31 | +git submodule update --init --recursive | 
|  | 32 | +commit=$(git rev-parse FETCH_HEAD) | 
|  | 33 | + | 
|  | 34 | +if [ -d "/mnt/infer/$commit" ]; then | 
|  | 35 | +  echo "Already scanned $commit" | 
|  | 36 | +  exit 0 | 
|  | 37 | +fi | 
|  | 38 | + | 
|  | 39 | +# What can we use as a reference | 
|  | 40 | + | 
|  | 41 | +populate_differences() | 
|  | 42 | +# input $merge_base | 
|  | 43 | +{ | 
|  | 44 | +  # Find something closer - e.g. we've appended to a branch | 
|  | 45 | +  # we've already tested | 
|  | 46 | +  mapfile -t commits < <(git rev-list "${merge_base}..FETCH_HEAD") | 
|  | 47 | +  for common_commit in "${commits[@]}"; do | 
|  | 48 | +    if [ -d /mnt/infer/"$common_commit" ]; then | 
|  | 49 | +      break; | 
|  | 50 | +    fi | 
|  | 51 | +  done | 
|  | 52 | +  if [ ! -d "/mnt/infer/$common_commit" ]; then | 
|  | 53 | +    return 1 | 
|  | 54 | +  fi | 
|  | 55 | +  merge_base=$common_commit | 
|  | 56 | +  # The file changes we from last results | 
|  | 57 | +  git diff --name-only FETCH_HEAD.."${merge_base}" | tee "$base"/index.txt | 
|  | 58 | + | 
|  | 59 | +  if [ ! -s "$base"/index.txt ]; then | 
|  | 60 | +    echo "Empty changes - nothing necessary" | 
|  | 61 | +    rm "$base"/index.txt | 
|  | 62 | +    exit 0 | 
|  | 63 | +  fi | 
|  | 64 | + | 
|  | 65 | +  # use previous results as a base | 
|  | 66 | +  cp -a "/mnt/infer/$merge_base" "$result_dir" | 
|  | 67 | + | 
|  | 68 | +  # Using as a recently used maker | 
|  | 69 | +  touch "/mnt/infer/$merge_base" | 
|  | 70 | +  return 0 | 
|  | 71 | +} | 
|  | 72 | + | 
|  | 73 | +# Just assume we diverged from main at some point | 
|  | 74 | +# Using $commit because merge-base didn't process | 
|  | 75 | +# pull request references. | 
|  | 76 | +merge_base=$(git merge-base "$commit" origin/main) | 
|  | 77 | + | 
|  | 78 | +if populate_differences; then | 
|  | 79 | +  echo "No common commit ancestor with analysis" >&2 | 
|  | 80 | + | 
|  | 81 | +  echo "This is going to take a while for a full scan" | 
|  | 82 | +fi | 
|  | 83 | + | 
|  | 84 | +# back from /mnt/src | 
|  | 85 | +popd | 
|  | 86 | + | 
|  | 87 | +# Build | 
|  | 88 | + | 
|  | 89 | +build() | 
|  | 90 | +{ | 
|  | 91 | +  cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ | 
|  | 92 | +        -DCMAKE_C_COMPILER=clang \ | 
|  | 93 | +        -DCMAKE_CXX_COMPILER=clang++ \ | 
|  | 94 | +        -S /mnt/src -B bld | 
|  | 95 | +  cmake --build bld \ | 
|  | 96 | +        --target GenError GenServerSource GenUnicodeDataSource GenFixPrivs \ | 
|  | 97 | +        --parallel "$JOBS" | 
|  | 98 | +} | 
|  | 99 | + | 
|  | 100 | +if [ ! -d bld ]; then | 
|  | 101 | +  mkdir bld | 
|  | 102 | +  build | 
|  | 103 | +fi | 
|  | 104 | + | 
|  | 105 | +# | 
|  | 106 | +capture() | 
|  | 107 | +{ | 
|  | 108 | +  infer capture --compilation-database compile_commands.json --project-root /mnt/src --results-dir "${result_dir}" "$@" | 
|  | 109 | +} | 
|  | 110 | + | 
|  | 111 | +analyze() | 
|  | 112 | +{ | 
|  | 113 | +  infer analyze --project-root /mnt/src --results-dir "${result_dir}" --max-jobs "${JOBS}" "$@" | 
|  | 114 | +} | 
|  | 115 | +# Capture and analyze the feature of the files changes in index | 
|  | 116 | +# | 
|  | 117 | +cd bld | 
|  | 118 | + | 
|  | 119 | +if [ ! -f ../index.txt ]; then | 
|  | 120 | +  echo "full run, this could take a while" | 
|  | 121 | +  capture | 
|  | 122 | +  analyze | 
|  | 123 | +  mv "$result_dir" /mnt/infer/"$commit" | 
|  | 124 | +  cd .. | 
|  | 125 | +  rm -rf bld | 
|  | 126 | +  exit | 
|  | 127 | +fi | 
|  | 128 | + | 
|  | 129 | +# We've copied over a result dir, so we're continuing | 
|  | 130 | +# https://fbinfer.com/docs/infer-workflow/#differential-workflow | 
|  | 131 | +# using 'infer capture" instead infer run | 
|  | 132 | +capture --reactive | 
|  | 133 | + | 
|  | 134 | +# some form of incremental | 
|  | 135 | +analyze --changed-files-index ../index.txt | 
|  | 136 | + | 
|  | 137 | +# Preserve result | 
|  | 138 | +cp "${result_dir}"/report.json ../report.json | 
|  | 139 | + | 
|  | 140 | +cp -a "${result_dir}" "${result_dir}_preserved" | 
|  | 141 | + | 
|  | 142 | +pushd /mnt/src | 
|  | 143 | +git checkout "$merge_base" | 
|  | 144 | +popd | 
|  | 145 | + | 
|  | 146 | +# TODO | 
|  | 147 | +# How can we use the previous captured /mnt/infer/$merge_base | 
|  | 148 | + | 
|  | 149 | +# just in case these have changed, including generated files | 
|  | 150 | +cd .. | 
|  | 151 | +build | 
|  | 152 | +cd bld | 
|  | 153 | + | 
|  | 154 | +capture --reactive --mark-unchanged-procs | 
|  | 155 | +analyze --incremental-analysis  --changed-files-index ../index.txt | 
|  | 156 | + | 
|  | 157 | +# TODO useful enough to save as /mnt/infer/$commit | 
|  | 158 | +# it may be merged next, or a commit pushed on top of it. | 
|  | 159 | +infer reportdiff --report-current ../report.json --report-previous "${result_dir}"/report.json  --project-root /mnt/src --results-dir "${result_dir}" | 
|  | 160 | +cd .. | 
|  | 161 | +rm -rf bld index.txt | 
|  | 162 | +# report.json | 
|  | 163 | + | 
|  | 164 | +check() | 
|  | 165 | +{ | 
|  | 166 | +  file=$1 | 
|  | 167 | +  msg=$2 | 
|  | 168 | +  if [ -f "${file}" ]; then | 
|  | 169 | +    filesize=$(stat -c%s "$file") | 
|  | 170 | +    # 2 is the size of an empty json array '[]' | 
|  | 171 | +    if [ "$filesize" -gt 2 ]; then | 
|  | 172 | +      echo "$msg" | 
|  | 173 | +      echo | 
|  | 174 | +      jq . "${file}" | 
|  | 175 | +      return 1 | 
|  | 176 | +    fi | 
|  | 177 | +  fi | 
|  | 178 | +  return 0 | 
|  | 179 | +} | 
|  | 180 | + | 
|  | 181 | +check "${result_dir}"/differential/fixed.json "Good human! Thanks for fixing the bad things" | 
|  | 182 | + | 
|  | 183 | +if check "${result_dir}"/differential/introduced.json "Bad human! Don't introduce bad things" >&2; then | 
|  | 184 | +  exit 1 | 
|  | 185 | +fi | 
0 commit comments