microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
4c4e9d5f767314c193e5cc06ad889516c3c69b93

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/workflows/fuzz.yml

192lines · modecode

1name: fuzz
2run-name: Fuzz
3env:
4 OWNER_RDPATH: . # Rel path to the dir that contains the fuzzing infra (contains "fuzz" dir).
5 DURATION_SEC: 7200 # Fuzzing run duration in seconds.
6 STDERR_LOG_FNAME: fuzz.stderr.log # File name to redirect the fuzzing run's stderr to.
7 TMIN_LOG_FNAME: fuzz.tmin.log # File name to redirect the fuzzing input minimization log to.
8 GH_ISSUE_TEMPLATE_RFPATH: .github/ISSUE_TEMPLATE/fuzz_bug_report.md
9 # GitHub issue template rel file path.
10 TARGET_NAME: compile # Fuzzing target name. Fuzzes the `compile` func of the Q# compiler.
11 ARTIFACTS_RDPATH: fuzz/artifacts # Fuzzing artifacts rel dir path.
12 SEEDS_RDPATH: fuzz/seed_inputs # Fuzzing seed inputs rel dir path.
13 SEEDS_FNAME: list.txt # Fuzzing seed inputs list file name.
14on:
15 schedule: # Production runs against default branch.
16 - cron: '24 11 * * 0' # Run after 11:24 UTC (4:24am PDT/3:24am PST) on Sun.
17 workflow_dispatch: # Manual runs.
18
19jobs:
20 fuzz:
21 name: Fuzzing
22 strategy:
23 matrix:
24 os: [ubuntu-latest] # Fuzzing is not supported on Win. The macos is temporarily removed
25 # because of low availability.
26 runs-on: ${{ matrix.os }}
27
28 steps:
29 - name: Install and Configure Tools
30 run: |
31 rustup install nightly # Install nightly toolchain.
32 rustup default nightly # Make nightly toolchain default.
33 cargo install cargo-fuzz # Install cargo-fuzz (fuzzing tool).
34
35 - name: Checkout the Repo
36 uses: actions/checkout@v3
37 with:
38 submodules: "true"
39
40 - name: Gather the Seed Inputs
41 run: |
42 cd $OWNER_RDPATH # Enter the dir containing the fuzzing infra.
43
44 # Clone the submodules of QDK:
45 REPOS="Quantum Quantum-NC QuantumKatas QuantumLibraries iqsharp qdk-python qsharp-compiler qsharp-runtime"
46 for REPO in $REPOS ; do
47 git clone --depth 1 --single-branch --no-tags --recurse-submodules --shallow-submodules --jobs 4 \
48 https://github.com/microsoft/$REPO.git $SEEDS_RDPATH/$TARGET_NAME/$REPO
49 done
50
51 # Build a comma-separated list of all the .qs files in $SEEDS_FNAME file:
52 find $SEEDS_RDPATH/$TARGET_NAME -name "*.qs" | tr "\n" "," > \
53 $SEEDS_RDPATH/$TARGET_NAME/$SEEDS_FNAME
54
55 - name: Build and Run the Fuzz Target
56 run: |
57 cd $OWNER_RDPATH # Enter the dir containing the fuzzing infra.
58 cargo fuzz build --features do_fuzz $TARGET_NAME # Build the fuzz target.
59
60 # Run fuzzing for specified number of seconds and redirect the `stderr` to a file
61 # whose name is specified by the STDERR_LOG_FNAME env var:
62 RUST_BACKTRACE=1 cargo fuzz run --features do_fuzz $TARGET_NAME -- \
63 -seed_inputs=@$SEEDS_RDPATH/$TARGET_NAME/$SEEDS_FNAME \
64 -max_total_time=$DURATION_SEC \
65 -rss_limit_mb=4096 \
66 -max_len=32767 \
67 2>$STDERR_LOG_FNAME
68 # The `-rss_limit_mb` and `-max_len` work around running out of memory.
69
70 - name: "If Fuzzing Failed: Collect Failure Info"
71 if: failure()
72 run: |
73 cd $OWNER_RDPATH # Enter the dir containing the fuzzing infra.
74
75 # Extract from stderr log the panic message:
76 PANIC_MESSAGE=`cat $STDERR_LOG_FNAME |
77 grep "panicked at" | sed "s|thread '<unnamed>' panicked at '\([^']*\).*|\1|"`
78 # Explanation:
79 # `cat $STDERR_LOG_FNAME |`: Display the contents of the stderr log file and pass the contents
80 # to the next command.
81 # `grep "panicked at" |`: Filter out (drop) all the lines except the ones containing "panicked at",
82 # the script expects that there is only one such line, pass that line to the next command. Line example:
83 # thread '<unnamed>' panicked at 'global item should have type', . . ./compiler/qsc_frontend/src/typeck/rules.rs:300:26
84 # `sed "s|thread '<unnamed>' panicked at '\([^']*\).*|\1|"`: `sed` - stream editor.
85 # `s` after quote: search command. After `s` there are two sections, each between a pair of '|'.
86 # First section:
87 # In the incoming stream search for a sequence starting with "thread '<unnamed>' panicked at '"
88 # (sequence from the beginning of the line until after the apostrophe where the panic message starts),
89 # followed by zero or more ('*' after ']') non-apostrophe chars (`[^']`)
90 # and memorize ( `\(`, `\)` ) that sequence of non-apostrophe chars (between apostrophes -
91 # "global item should have type") as a memory item 1;
92 # followed by zero or more ('*' after '.') arbitrary chars ('.') till the end of the line.
93 # Second section (`\1`):
94 # If the sequence specified by the first section is found, then replace that sequence (the whole line)
95 # with the memory item 1 (`\1`), ending up in a panic message between the apostrophes.
96 # PANIC_MESSAGE=`. . .`: The output of the command(s) between the backticks ('`') is saved in the
97 # env var PANIC_MESSAGE.
98 # If the failure is not panic-based then extract any ERROR message(s):
99 if [ "$PANIC_MESSAGE" == "" ]; then
100 PANIC_MESSAGE=`cat $STDERR_LOG_FNAME | grep "ERROR"`
101 fi
102 echo "PANIC_MESSAGE: '$PANIC_MESSAGE'" # Output the PANIC_MESSAGE var value to the log
103 # (optional, for workflow failure analysis and sanity check).
104 echo "PANIC_MESSAGE=$PANIC_MESSAGE" >> "$GITHUB_ENV" # Save the PANIC_MESSAGE var in the env, will be used in
105 # the subsequent `run:` and `uses:` steps.
106
107 # Determine the name of a file containing the input of interest (that triggers the panic/crash):
108 if [ -e $ARTIFACTS_RDPATH/$TARGET_NAME/crash-* ]; then # Panic and Stack Overflow Cases.
109 TO_MINIMIZE_FNAME=crash-*;
110 elif [ -e $ARTIFACTS_RDPATH/$TARGET_NAME/oom-* ]; then # Out-of-Memory Case.
111 TO_MINIMIZE_FNAME=oom-*;
112 else
113 echo -e "File to minimize not found.\nContents of artifacts dir \"$ARTIFACTS_RDPATH/$TARGET_NAME/\":"
114 ls $ARTIFACTS_RDPATH/$TARGET_NAME/
115 fi
116
117 if [ "$TO_MINIMIZE_FNAME" != "" ]; then
118 echo "TO_MINIMIZE_FNAME: $TO_MINIMIZE_FNAME"
119
120 # Minimize the input:
121 ( cargo fuzz tmin --features do_fuzz -r 10000 $TARGET_NAME $ARTIFACTS_RDPATH/$TARGET_NAME/$TO_MINIMIZE_FNAME 2>&1 ) > \
122 $TMIN_LOG_FNAME || MINIMIZATION_FAILED=1
123
124 # Get the minimized input relative faile path:
125 if [ "$MINIMIZATION_FAILED" == "1" ]; then
126 # Minimization failed, get the latest successful minimized input relative faile path:
127 MINIMIZED_INPUT_RFPATH=`
128 cat $TMIN_LOG_FNAME | grep "CRASH_MIN: minimizing crash input: " | tail -n 1 |
129 sed "s|^.*\($ARTIFACTS_RDPATH/$TARGET_NAME/[^\']*\).*|\1|"`
130 else
131 # Minimization Succeeded, get the reported minimized input relative faile path::
132 MINIMIZED_INPUT_RFPATH=`
133 cat $TMIN_LOG_FNAME | grep "failed to minimize beyond" |
134 sed "s|.*\($ARTIFACTS_RDPATH/$TARGET_NAME/[^ ]*\).*|\1|" `
135 fi
136 echo "MINIMIZED_INPUT_RFPATH: $MINIMIZED_INPUT_RFPATH"
137 echo "MINIMIZED_INPUT_RFPATH=$MINIMIZED_INPUT_RFPATH" >> "$GITHUB_ENV"
138
139 # Extract the minimized input:
140 MINIMIZED_INPUT=`cat $MINIMIZED_INPUT_RFPATH | tr "\n" "\r"`
141 # Display the contents of the minimized input file and replace all the occurrences of '\n' with '\r'
142 # so that the potentially multiline sequence can be "serialized" into the env var,
143 # while preserving the information about the line breaks.
144 else
145 MINIMIZED_INPUT="(Input minimization failed, see the workflow logs and artifacts)"
146 fi
147 echo "MINIMIZED_INPUT: '$MINIMIZED_INPUT'"
148 echo "MINIMIZED_INPUT=$MINIMIZED_INPUT" >> "$GITHUB_ENV"
149
150 # Get the workflow agent system info:
151 WF_AGENT_SYS_INFO="`uname -a`"
152 echo "WF_AGENT_SYS_INFO: $WF_AGENT_SYS_INFO"
153 echo "WF_AGENT_SYS_INFO=$WF_AGENT_SYS_INFO" >> "$GITHUB_ENV"
154 echo "WF_AGENT_OS=${{ matrix.os }}" >> "$GITHUB_ENV"
155
156 # Get the commit info:
157 COMMIT_INFO=`git log -1 | tr "\n" "\r"`
158 echo "COMMIT_INFO: '$COMMIT_INFO'"
159 echo "COMMIT_INFO=$COMMIT_INFO" >> "$GITHUB_ENV"
160
161 # Get the last N bytes of the fuzzing stderr log into the env var
162 # (N is such that the subsequent GitHub issue reporting does not overflow):
163 STDERR_LOG=`tail -c 63488 $STDERR_LOG_FNAME | tr "\n" "\r"`
164 echo "STDERR_LOG: '$STDERR_LOG'"
165 echo "STDERR_LOG=$STDERR_LOG" >> "$GITHUB_ENV"
166
167 - name: "If Fuzzing Failed: Upload Failure Artifacts"
168 if: failure()
169 uses: actions/upload-artifact@v3
170 with:
171 path: |
172 ${{ env.OWNER_RDPATH }}/${{ env.STDERR_LOG_FNAME }}
173 ${{ env.OWNER_RDPATH }}/${{ env.TMIN_LOG_FNAME }}
174 ${{ env.OWNER_RDPATH }}/${{ env.ARTIFACTS_RDPATH }}/${{ env.TARGET_NAME }}/*
175 ${{ env.OWNER_RDPATH }}/${{ env.SEEDS_RDPATH }}/${{ env.TARGET_NAME }}/${{ env.SEEDS_FNAME }}
176 if-no-files-found: error
177
178 - name: "If Fuzzing Failed: Report GutHub Issue"
179 if: failure()
180 uses: JasonEtco/create-an-issue@v2
181 env:
182 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
183 WORKFLOW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
184 with:
185 filename: ${{ env.GH_ISSUE_TEMPLATE_RFPATH }}
186 # This issue template file uses a number of env vars collected above.
187 id: create-issue
188
189 - name: "If Fuzzing Failed: Log Issue Info"
190 if: failure()
191 run: |
192 echo "Created issue #${{ steps.create-issue.outputs.number }} ${{ steps.create-issue.outputs.url }}"