Skip to content

Commit 8446d5c

Browse files
authored
Add better fuzzing compilation (#2292)
1 parent 6568272 commit 8446d5c

File tree

11 files changed

+88
-44
lines changed

11 files changed

+88
-44
lines changed

.github/workflows/fuzz.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ jobs:
6767
find $SEEDS_RDPATH/${{ matrix.target_name }} -name "*.qs" | tr "\n" "," > \
6868
$SEEDS_RDPATH/${{ matrix.target_name }}/$SEEDS_FNAME
6969
70+
- name: Gather the Seed Inputs (qasm)
71+
if: matrix.target_name == 'qasm'
72+
run: |
73+
cd $OWNER_RDPATH # Enter the dir containing the fuzzing infra.
74+
75+
# Clone openqasm repo for samples:
76+
git clone --depth 1 --single-branch --no-tags --recurse-submodules --shallow-submodules --jobs 4 \
77+
https://github.com/openqasm/openqasm.git $SEEDS_RDPATH/${{ matrix.target_name }}/openqasm
78+
79+
80+
# Build a comma-separated list of all the .qasm and .inc files in $SEEDS_FNAME file:
81+
find $SEEDS_RDPATH/${{ matrix.target_name }} -name "*.qasm" | tr "\n" "," > \
82+
$SEEDS_RDPATH/${{ matrix.target_name }}/$SEEDS_FNAME
83+
find $SEEDS_RDPATH/${{ matrix.target_name }} -name "*.inc" | tr "\n" "," > \
84+
$SEEDS_RDPATH/${{ matrix.target_name }}/$SEEDS_FNAME
85+
7086
- name: Build and Run the Fuzz Target
7187
run: |
7288
cd $OWNER_RDPATH # Enter the dir containing the fuzzing infra.
@@ -188,6 +204,7 @@ jobs:
188204
if: failure()
189205
uses: actions/upload-artifact@v4
190206
with:
207+
name: ${{ matrix.target_name }}-fuzz-failure-artifacts
191208
path: |
192209
${{ env.OWNER_RDPATH }}/${{ env.STDERR_LOG_FNAME }}
193210
${{ env.OWNER_RDPATH }}/${{ env.TMIN_LOG_FNAME }}

compiler/qsc_qasm/src/compiler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl QasmCompiler {
128128
ProgramType::Fragments => (self.build_fragments(), None),
129129
};
130130

131-
QasmCompileUnit::new(self.source_map, self.errors, Some(package), signature)
131+
QasmCompileUnit::new(self.source_map, self.errors, package, signature)
132132
}
133133

134134
/// Build a package with namespace and an operation

compiler/qsc_qasm/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,10 @@ pub struct QasmCompileUnit {
231231
/// Semantic errors encountered during compilation.
232232
/// These are always fatal errors that prevent compilation.
233233
errors: Vec<WithSource<crate::Error>>,
234-
/// The compiled AST package, if compilation was successful.
234+
/// The compiled AST package
235235
/// There is no guarantee that this package is valid unless
236236
/// there are no errors.
237-
package: Option<Package>,
237+
package: Package,
238238
/// The signature of the operation created from the QASM source code.
239239
/// None if the program type is `ProgramType::Fragments`.
240240
signature: Option<OperationSignature>,
@@ -249,7 +249,7 @@ impl QasmCompileUnit {
249249
pub fn new(
250250
source_map: SourceMap,
251251
errors: Vec<WithSource<crate::Error>>,
252-
package: Option<Package>,
252+
package: Package,
253253
signature: Option<OperationSignature>,
254254
) -> Self {
255255
Self {
@@ -279,7 +279,7 @@ impl QasmCompileUnit {
279279
) -> (
280280
SourceMap,
281281
Vec<WithSource<crate::Error>>,
282-
Option<Package>,
282+
Package,
283283
Option<OperationSignature>,
284284
) {
285285
(self.source_map, self.errors, self.package, self.signature)

compiler/qsc_qasm/src/stdlib/compile.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ fn compiles_with_base_profile() {
1616
let _ = package_store_with_qasm(TargetCapabilityFlags::empty());
1717
}
1818

19+
/// return a tuple with the stdlib package id, the qasm library package id, and the package store
20+
/// that contains the core, std, and qasmstd packages.
1921
#[must_use]
2022
pub fn package_store_with_qasm(
2123
capabilities: TargetCapabilityFlags,

compiler/qsc_qasm/src/tests.rs

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ where
194194
fn compile_qasm_to_qir(source: &str, profile: Profile) -> Result<String, Vec<Report>> {
195195
let unit = compile(source)?;
196196
fail_on_compilation_errors(&unit);
197-
let package = unit.package.expect("no package found");
197+
let package = unit.package;
198198
let qir = generate_qir_from_ast(package, unit.source_map, profile).map_err(|errors| {
199199
errors
200200
.iter()
@@ -231,7 +231,7 @@ fn compile_qasm_best_effort(source: &str, profile: Profile) {
231231
let (mut _unit, _errors) = compile_ast(
232232
&store,
233233
&dependencies,
234-
package.expect("package must exist"),
234+
package,
235235
sources,
236236
PackageType::Lib,
237237
profile.into(),
@@ -244,7 +244,7 @@ pub(crate) fn gen_qsharp_stmt(stmt: &Stmt) -> String {
244244

245245
#[allow(dead_code)]
246246
pub(crate) fn compare_compilation_to_qsharp(unit: &QasmCompileUnit, expected: &str) {
247-
let package = unit.package.as_ref().expect("package must exist");
247+
let package = &unit.package;
248248
let despanned_ast = AstDespanner.despan(package);
249249
let qsharp = gen_qsharp(&despanned_ast);
250250
difference::assert_diff!(&qsharp, expected, "\n", 0);
@@ -306,10 +306,7 @@ pub fn compile_qasm_to_qsharp_file(source: &str) -> miette::Result<String, Vec<R
306306
let errors = unit.errors.into_iter().map(Report::new).collect();
307307
return Err(errors);
308308
}
309-
let Some(package) = unit.package else {
310-
panic!("Expected package, got None");
311-
};
312-
let qsharp = gen_qsharp(&package);
309+
let qsharp = gen_qsharp(&unit.package);
313310
Ok(qsharp)
314311
}
315312

@@ -326,10 +323,7 @@ pub fn compile_qasm_to_qsharp_operation(source: &str) -> miette::Result<String,
326323
let errors = unit.errors.into_iter().map(Report::new).collect();
327324
return Err(errors);
328325
}
329-
let Some(package) = unit.package else {
330-
panic!("Expected package, got None");
331-
};
332-
let qsharp = gen_qsharp(&package);
326+
let qsharp = gen_qsharp(&unit.package);
333327
Ok(qsharp)
334328
}
335329

@@ -357,10 +351,7 @@ pub fn qsharp_from_qasm_compilation(unit: QasmCompileUnit) -> miette::Result<Str
357351
let errors = unit.errors.into_iter().map(Report::new).collect();
358352
return Err(errors);
359353
}
360-
let Some(package) = unit.package else {
361-
panic!("Expected package, got None");
362-
};
363-
let qsharp = gen_qsharp(&package);
354+
let qsharp = gen_qsharp(&unit.package);
364355
Ok(qsharp)
365356
}
366357

@@ -384,10 +375,7 @@ pub fn compile_qasm_stmt_to_qsharp_with_semantics(
384375
let errors = unit.errors.into_iter().map(Report::new).collect();
385376
return Err(errors);
386377
}
387-
let Some(package) = unit.package else {
388-
panic!("Expected package, got None");
389-
};
390-
let qsharp = get_last_statement_as_qsharp(&package);
378+
let qsharp = get_last_statement_as_qsharp(&unit.package);
391379
Ok(qsharp)
392380
}
393381

@@ -471,8 +459,7 @@ pub(crate) fn compare_qasm_and_qasharp_asts(source: &str) {
471459
Some(&mut resolver),
472460
config,
473461
);
474-
let qasm_package = unit.package.as_ref().expect("package must exist");
475-
let despanned_qasm_ast = AstDespanner.despan(qasm_package);
462+
let despanned_qasm_ast = AstDespanner.despan(&unit.package);
476463

477464
// 2. Generate Q# source from the QASM ast.
478465
let qsharp_src = gen_qsharp(&despanned_qasm_ast);

compiler/qsc_qasm/src/tests/output.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn using_re_semantics_removes_output() -> miette::Result<(), Vec<Report>> {
3737
);
3838
let unit = compile_with_config(source, config).expect("parse failed");
3939
fail_on_compilation_errors(&unit);
40-
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
40+
let qsharp = gen_qsharp(&unit.package);
4141
expect![[r#"
4242
namespace qasm_import {
4343
import QasmStd.Angle.*;
@@ -88,7 +88,7 @@ fn using_qasm_semantics_captures_all_classical_decls_as_output() -> miette::Resu
8888
);
8989
let unit = compile_with_config(source, config).expect("parse failed");
9090
fail_on_compilation_errors(&unit);
91-
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
91+
let qsharp = gen_qsharp(&unit.package);
9292
expect![[r#"
9393
namespace qasm_import {
9494
import QasmStd.Angle.*;
@@ -139,7 +139,7 @@ fn using_qiskit_semantics_only_bit_array_is_captured_and_reversed(
139139
);
140140
let unit = compile_with_config(source, config).expect("parse failed");
141141
fail_on_compilation_errors(&unit);
142-
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
142+
let qsharp = gen_qsharp(&unit.package);
143143
expect![[r#"
144144
namespace qasm_import {
145145
import QasmStd.Angle.*;
@@ -197,7 +197,7 @@ c2[2] = measure q[4];
197197
);
198198
let unit = compile_with_config(source, config).expect("parse failed");
199199
fail_on_compilation_errors(&unit);
200-
let package = unit.package.expect("no package found");
200+
let package = unit.package;
201201
let qsharp = gen_qsharp(&package.clone());
202202
expect![[r#"
203203
namespace qasm_import {

compiler/qsc_qasm/src/tests/sample_circuits/bell_pair.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ fn it_compiles() {
3333

3434
print_compilation_errors(&unit);
3535
assert!(!unit.has_errors());
36-
let Some(package) = &unit.package else {
37-
panic!("no package found");
38-
};
39-
let qsharp = gen_qsharp(package);
36+
let qsharp = gen_qsharp(&unit.package);
4037
println!("{qsharp}");
4138
}

compiler/qsc_qasm/src/tests/sample_circuits/rgqft_multiplier.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ fn it_compiles() {
2121

2222
print_compilation_errors(&unit);
2323
assert!(!unit.has_errors());
24-
let Some(package) = &unit.package else {
25-
panic!("no package found");
26-
};
27-
let qsharp = gen_qsharp(package);
24+
let qsharp = gen_qsharp(&unit.package);
2825
println!("{qsharp}");
2926
}
3027

compiler/qsc_qasm/src/tests/statement/reset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn reset_calls_are_generated_from_qasm() -> miette::Result<(), Vec<Report>> {
3232
);
3333
let unit = compile_with_config(source, config)?;
3434
fail_on_compilation_errors(&unit);
35-
let qsharp = gen_qsharp(&unit.package.expect("no package found"));
35+
let qsharp = gen_qsharp(&unit.package);
3636
expect![[r#"
3737
namespace qasm_import {
3838
import QasmStd.Angle.*;

fuzz/fuzz_targets/qasm.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,57 @@ allocator::assign_global!();
88
#[cfg(feature = "do_fuzz")]
99
use libfuzzer_sys::fuzz_target;
1010

11+
use qsc::{
12+
compile::compile_ast,
13+
hir::PackageId,
14+
qasm::{
15+
compile_to_qsharp_ast_with_config, io::InMemorySourceResolver, package_store_with_qasm,
16+
CompilerConfig, OutputSemantics, ProgramType, QubitSemantics,
17+
},
18+
target::Profile,
19+
PackageStore, PackageType,
20+
};
21+
1122
fn compile(data: &[u8]) {
1223
if let Ok(fuzzed_code) = std::str::from_utf8(data) {
13-
let mut resolver = qsc::qasm::io::InMemorySourceResolver::from_iter([]);
14-
let _ = qsc::qasm::parser::parse_source(fuzzed_code, "fuzz.qasm", &mut resolver);
24+
thread_local! {
25+
static STORE_STD: (PackageId, PackageId, PackageStore) = {
26+
package_store_with_qasm(Profile::Unrestricted.into())
27+
};
28+
}
29+
STORE_STD.with(|(stdid, qasmid, store)| {
30+
let mut resolver = InMemorySourceResolver::from_iter([]);
31+
let config = CompilerConfig::new(
32+
QubitSemantics::Qiskit,
33+
OutputSemantics::OpenQasm,
34+
ProgramType::File,
35+
Some("Fuzz".into()),
36+
None,
37+
);
38+
39+
let unit = compile_to_qsharp_ast_with_config(
40+
fuzzed_code,
41+
"fuzz.qasm",
42+
Some(&mut resolver),
43+
config,
44+
);
45+
let (sources, _, package, _) = unit.into_tuple();
46+
47+
let dependencies = vec![
48+
(PackageId::CORE, None),
49+
(*stdid, None),
50+
(*qasmid, Some("QasmStd".into())),
51+
];
52+
53+
let (mut _unit, _errors) = compile_ast(
54+
store,
55+
&dependencies,
56+
package,
57+
sources,
58+
PackageType::Lib,
59+
Profile::Unrestricted.into(),
60+
);
61+
});
1562
}
1663
}
1764

pip/src/interop.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,6 @@ pub(crate) fn compile_qasm_enriching_errors<S: AsRef<str>, R: SourceResolver>(
287287
if !errors.is_empty() {
288288
return Err(QasmError::new_err(format_qasm_errors(errors)));
289289
}
290-
let Some(package) = package else {
291-
return Err(QasmError::new_err("package should have had value"));
292-
};
293290

294291
let Some(signature) = sig else {
295292
return Err(QasmError::new_err(

0 commit comments

Comments
 (0)