mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 20:38:06 +00:00
add a single-shot crash report utility (#703)
Adds `test-input` and `test-input-libfuzzer`, which print the CrashTestResult in json form. While many of the existing tasks make sense running in a managed loop, crash report generation is something that having a single one-off is useful. Example: ``` $ onefuzz-agent local test-input /tmp/fuzz.exe /tmp/crash.txt { "crash_report": { "input_sha256": "a35b3ce1038750e9175a6dcd3f64c8d4e85720affb12cc11f5d0b6889274d06e", "executable": "/tmp/fuzz.exe", "crash_type": "SIGABRT", "crash_site": "0x7f0d9d4ad18b in gsignal+0xcb (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x4618b)", "call_stack": [ "#0 0x7f0d9d4ad18b in gsignal+0xcb (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x4618b)", "#1 0x7f0d9d48c859 in abort+0x12b (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x25859)", "#2 0x7f0d9d4f73ee in <unknown> (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x903ee)", "#3 0x7f0d9d599b4a in __fortify_fail+0x2a (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x132b4a)", "#4 0x7f0d9d5983e6 in __chk_fail+0x16 (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x1313e6)", "#5 0x7f0d9d597e09 in __strncpy_chk+0x19 (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x130e09)", "#6 0x400a54 in from_file+0xa4 (/tmp/fuzz.exe+0xa54)", "#7 0x7f0d9d48e0b3 in __libc_start_main+0xf3 (/usr/lib/x86_64-linux-gnu/libc-2.31.so+0x270b3)", "#8 0x40077a in _start+0x2a (/tmp/fuzz.exe+0x77a)" ], "call_stack_sha256": "6906234fb235690cc2843a1a55f49ff68b424e54bec55f9b8258415d97b3e638", "task_id": "00000000-0000-0000-0000-000000000000", "job_id": "00000000-0000-0000-0000-000000000000" } } $ ```
This commit is contained in:
@ -7,7 +7,7 @@ use clap::{App, SubCommand};
|
||||
use crate::local::{
|
||||
common::add_common_config, generic_analysis, generic_crash_report, generic_generator,
|
||||
libfuzzer, libfuzzer_coverage, libfuzzer_crash_report, libfuzzer_fuzz, libfuzzer_merge,
|
||||
radamsa,
|
||||
libfuzzer_test_input, radamsa, test_input,
|
||||
};
|
||||
|
||||
const RADAMSA: &str = "radamsa";
|
||||
@ -16,9 +16,11 @@ const LIBFUZZER_FUZZ: &str = "libfuzzer-fuzz";
|
||||
const LIBFUZZER_CRASH_REPORT: &str = "libfuzzer-crash-report";
|
||||
const LIBFUZZER_COVERAGE: &str = "libfuzzer-coverage";
|
||||
const LIBFUZZER_MERGE: &str = "libfuzzer-merge";
|
||||
const LIBFUZZER_TEST_INPUT: &str = "libfuzzer-test-input";
|
||||
const GENERIC_CRASH_REPORT: &str = "generic-crash-report";
|
||||
const GENERIC_GENERATOR: &str = "generic-generator";
|
||||
const GENERIC_ANALYSIS: &str = "generic-analysis";
|
||||
const GENERIC_TEST_INPUT: &str = "generic-test-input";
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
match args.subcommand() {
|
||||
@ -31,6 +33,8 @@ pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
(GENERIC_ANALYSIS, Some(sub)) => generic_analysis::run(sub).await,
|
||||
(GENERIC_CRASH_REPORT, Some(sub)) => generic_crash_report::run(sub).await,
|
||||
(GENERIC_GENERATOR, Some(sub)) => generic_generator::run(sub).await,
|
||||
(GENERIC_TEST_INPUT, Some(sub)) => test_input::run(sub).await,
|
||||
(LIBFUZZER_TEST_INPUT, Some(sub)) => libfuzzer_test_input::run(sub).await,
|
||||
_ => {
|
||||
anyhow::bail!("missing subcommand\nUSAGE: {}", args.usage());
|
||||
}
|
||||
@ -57,4 +61,8 @@ pub fn args(name: &str) -> App<'static, 'static> {
|
||||
GENERIC_GENERATOR,
|
||||
)))
|
||||
.subcommand(add_common_config(generic_analysis::args(GENERIC_ANALYSIS)))
|
||||
.subcommand(add_common_config(test_input::args(GENERIC_TEST_INPUT)))
|
||||
.subcommand(add_common_config(libfuzzer_test_input::args(
|
||||
LIBFUZZER_TEST_INPUT,
|
||||
)))
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ pub const CHECK_ASAN_LOG: &str = "check_asan_log";
|
||||
pub const TOOLS_DIR: &str = "tools_dir";
|
||||
pub const RENAME_OUTPUT: &str = "rename_output";
|
||||
pub const CHECK_FUZZER_HELP: &str = "check_fuzzer_help";
|
||||
pub const DISABLE_CHECK_DEBUGGER: &str = "disable_check_debugger";
|
||||
|
||||
pub const TARGET_EXE: &str = "target_exe";
|
||||
pub const TARGET_ENV: &str = "target_env";
|
||||
@ -176,9 +177,19 @@ pub fn get_synced_dir(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_common_config(args: &ArgMatches<'_>) -> Result<CommonConfig> {
|
||||
// NOTE: generate_task_id is intended to change the default behavior for local
|
||||
// fuzzing tasks from generating random task id to using UUID::nil(). This
|
||||
// enables making the one-shot crash report generation, which isn't really a task,
|
||||
// consistent across multiple runs.
|
||||
pub fn build_common_config(args: &ArgMatches<'_>, generate_task_id: bool) -> Result<CommonConfig> {
|
||||
let job_id = get_uuid("job_id", args).unwrap_or_else(|_| Uuid::nil());
|
||||
let task_id = get_uuid("task_id", args).unwrap_or_else(|_| Uuid::new_v4());
|
||||
let task_id = get_uuid("task_id", args).unwrap_or_else(|_| {
|
||||
if generate_task_id {
|
||||
Uuid::new_v4()
|
||||
} else {
|
||||
Uuid::nil()
|
||||
}
|
||||
});
|
||||
let instance_id = get_uuid("instance_id", args).unwrap_or_else(|_| Uuid::nil());
|
||||
|
||||
let setup_dir = if args.is_present(SETUP_DIR) {
|
||||
|
@ -55,7 +55,7 @@ pub fn build_analysis_config(
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_analysis_config(args, None, common)?;
|
||||
run_analysis(config).await
|
||||
}
|
||||
|
@ -4,8 +4,9 @@
|
||||
use crate::{
|
||||
local::common::{
|
||||
build_common_config, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
|
||||
CHECK_ASAN_LOG, CHECK_RETRY_COUNT, CRASHES_DIR, DISABLE_CHECK_QUEUE, NO_REPRO_DIR,
|
||||
REPORTS_DIR, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS, TARGET_TIMEOUT, UNIQUE_REPORTS_DIR,
|
||||
CHECK_ASAN_LOG, CHECK_RETRY_COUNT, CRASHES_DIR, DISABLE_CHECK_DEBUGGER,
|
||||
DISABLE_CHECK_QUEUE, NO_REPRO_DIR, REPORTS_DIR, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS,
|
||||
TARGET_TIMEOUT, UNIQUE_REPORTS_DIR,
|
||||
},
|
||||
tasks::{
|
||||
config::CommonConfig,
|
||||
@ -46,7 +47,7 @@ pub fn build_report_config(
|
||||
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
|
||||
let check_queue = !args.is_present(DISABLE_CHECK_QUEUE);
|
||||
let check_asan_log = args.is_present(CHECK_ASAN_LOG);
|
||||
let check_debugger = !args.is_present("disable_check_debugger");
|
||||
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER);
|
||||
|
||||
let config = Config {
|
||||
target_exe,
|
||||
@ -70,7 +71,7 @@ pub fn build_report_config(
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_report_config(args, None, common)?;
|
||||
ReportTask::new(config).managed_run().await
|
||||
}
|
||||
@ -121,9 +122,9 @@ pub fn build_shared_args() -> Vec<Arg<'static, 'static>> {
|
||||
Arg::with_name(CHECK_ASAN_LOG)
|
||||
.takes_value(false)
|
||||
.long(CHECK_ASAN_LOG),
|
||||
Arg::with_name("disable_check_debugger")
|
||||
Arg::with_name(DISABLE_CHECK_DEBUGGER)
|
||||
.takes_value(false)
|
||||
.long("disable_check_debugger"),
|
||||
.long(DISABLE_CHECK_DEBUGGER),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
use crate::{
|
||||
local::common::{
|
||||
build_common_config, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir,
|
||||
get_synced_dirs, CmdType, CHECK_ASAN_LOG, CHECK_RETRY_COUNT, CRASHES_DIR, GENERATOR_ENV,
|
||||
GENERATOR_EXE, GENERATOR_OPTIONS, READONLY_INPUTS, RENAME_OUTPUT, TARGET_ENV, TARGET_EXE,
|
||||
TARGET_OPTIONS, TARGET_TIMEOUT, TOOLS_DIR,
|
||||
get_synced_dirs, CmdType, CHECK_ASAN_LOG, CHECK_RETRY_COUNT, CRASHES_DIR,
|
||||
DISABLE_CHECK_DEBUGGER, GENERATOR_ENV, GENERATOR_EXE, GENERATOR_OPTIONS, READONLY_INPUTS,
|
||||
RENAME_OUTPUT, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS, TARGET_TIMEOUT, TOOLS_DIR,
|
||||
},
|
||||
tasks::{
|
||||
config::CommonConfig,
|
||||
@ -29,7 +29,7 @@ pub fn build_fuzz_config(args: &clap::ArgMatches<'_>, common: CommonConfig) -> R
|
||||
|
||||
let rename_output = args.is_present(RENAME_OUTPUT);
|
||||
let check_asan_log = args.is_present(CHECK_ASAN_LOG);
|
||||
let check_debugger = !args.is_present("disable_check_debugger");
|
||||
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER);
|
||||
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
|
||||
let target_timeout = Some(value_t!(args, TARGET_TIMEOUT, u64)?);
|
||||
|
||||
@ -60,7 +60,7 @@ pub fn build_fuzz_config(args: &clap::ArgMatches<'_>, common: CommonConfig) -> R
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_fuzz_config(args, common)?;
|
||||
GeneratorTask::new(config).run().await
|
||||
}
|
||||
@ -120,9 +120,9 @@ pub fn build_shared_args() -> Vec<Arg<'static, 'static>> {
|
||||
.takes_value(true)
|
||||
.long(TARGET_TIMEOUT)
|
||||
.default_value("30"),
|
||||
Arg::with_name("disable_check_debugger")
|
||||
Arg::with_name(DISABLE_CHECK_DEBUGGER)
|
||||
.takes_value(false)
|
||||
.long("disable_check_debugger"),
|
||||
.long(DISABLE_CHECK_DEBUGGER),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ use tokio::task::spawn;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let fuzz_config = build_fuzz_config(args, common.clone())?;
|
||||
let crash_dir = fuzz_config
|
||||
.crashes
|
||||
|
@ -55,7 +55,7 @@ pub fn build_coverage_config(
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_coverage_config(args, false, None, common)?;
|
||||
|
||||
let mut task = CoverageTask::new(config);
|
||||
|
@ -63,7 +63,7 @@ pub fn build_report_config(
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_report_config(args, None, common)?;
|
||||
ReportTask::new(config).managed_run().await
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ pub fn build_fuzz_config(args: &clap::ArgMatches<'_>, common: CommonConfig) -> R
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_fuzz_config(args, common)?;
|
||||
LibFuzzerFuzzTask::new(config)?.run().await
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ pub fn build_merge_config(
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_merge_config(args, None, common)?;
|
||||
spawn(std::sync::Arc::new(config)).await
|
||||
}
|
||||
|
72
src/agent/onefuzz-agent/src/local/libfuzzer_test_input.rs
Normal file
72
src/agent/onefuzz-agent/src/local/libfuzzer_test_input.rs
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::{
|
||||
local::common::{
|
||||
build_common_config, get_cmd_arg, get_cmd_env, CmdType, CHECK_RETRY_COUNT, TARGET_ENV,
|
||||
TARGET_EXE, TARGET_OPTIONS, TARGET_TIMEOUT,
|
||||
},
|
||||
tasks::report::libfuzzer_report::{test_input, TestInputArgs},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args, true)?;
|
||||
|
||||
let target_exe = value_t!(args, TARGET_EXE, PathBuf)?;
|
||||
let target_env = get_cmd_env(CmdType::Target, args)?;
|
||||
let target_options = get_cmd_arg(CmdType::Target, args);
|
||||
let input = value_t!(args, "input", PathBuf)?;
|
||||
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok();
|
||||
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
|
||||
|
||||
let config = TestInputArgs {
|
||||
target_exe: &target_exe.as_path(),
|
||||
target_env: &target_env,
|
||||
target_options: &target_options,
|
||||
input_url: None,
|
||||
input: input.as_path(),
|
||||
job_id: common.job_id,
|
||||
task_id: common.task_id,
|
||||
target_timeout,
|
||||
check_retry_count,
|
||||
setup_dir: &common.setup_dir,
|
||||
minimized_stack_depth: None,
|
||||
};
|
||||
|
||||
let result = test_input(config).await?;
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> {
|
||||
vec![
|
||||
Arg::with_name(TARGET_EXE).takes_value(true).required(true),
|
||||
Arg::with_name("input").takes_value(true).required(true),
|
||||
Arg::with_name(TARGET_ENV)
|
||||
.long(TARGET_ENV)
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
Arg::with_name(TARGET_OPTIONS)
|
||||
.default_value("{input}")
|
||||
.long(TARGET_OPTIONS)
|
||||
.takes_value(true)
|
||||
.value_delimiter(" ")
|
||||
.help("Use a quoted string with space separation to denote multiple arguments"),
|
||||
Arg::with_name(TARGET_TIMEOUT)
|
||||
.takes_value(true)
|
||||
.long(TARGET_TIMEOUT),
|
||||
Arg::with_name(CHECK_RETRY_COUNT)
|
||||
.takes_value(true)
|
||||
.long(CHECK_RETRY_COUNT)
|
||||
.default_value("0"),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn args(name: &'static str) -> App<'static, 'static> {
|
||||
SubCommand::with_name(name)
|
||||
.about("test a libfuzzer application with a specific input")
|
||||
.args(&build_shared_args())
|
||||
}
|
@ -11,4 +11,6 @@ pub mod libfuzzer_coverage;
|
||||
pub mod libfuzzer_crash_report;
|
||||
pub mod libfuzzer_fuzz;
|
||||
pub mod libfuzzer_merge;
|
||||
pub mod libfuzzer_test_input;
|
||||
pub mod radamsa;
|
||||
pub mod test_input;
|
||||
|
@ -17,7 +17,7 @@ use tokio::task::spawn;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args)?;
|
||||
let common = build_common_config(args, true)?;
|
||||
let fuzz_config = build_fuzz_config(args, common.clone())?;
|
||||
let crash_dir = fuzz_config
|
||||
.crashes
|
||||
|
82
src/agent/onefuzz-agent/src/local/test_input.rs
Normal file
82
src/agent/onefuzz-agent/src/local/test_input.rs
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::{
|
||||
local::common::{
|
||||
build_common_config, get_cmd_arg, get_cmd_env, CmdType, CHECK_ASAN_LOG, CHECK_RETRY_COUNT,
|
||||
DISABLE_CHECK_DEBUGGER, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS, TARGET_TIMEOUT,
|
||||
},
|
||||
tasks::report::generic::{test_input, TestInputArgs},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args, false)?;
|
||||
|
||||
let target_exe = value_t!(args, TARGET_EXE, PathBuf)?;
|
||||
let target_env = get_cmd_env(CmdType::Target, args)?;
|
||||
let target_options = get_cmd_arg(CmdType::Target, args);
|
||||
let input = value_t!(args, "input", PathBuf)?;
|
||||
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok();
|
||||
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
|
||||
let check_asan_log = args.is_present(CHECK_ASAN_LOG);
|
||||
let check_debugger = !args.is_present(DISABLE_CHECK_DEBUGGER);
|
||||
|
||||
let config = TestInputArgs {
|
||||
target_exe: &target_exe.as_path(),
|
||||
target_env: &target_env,
|
||||
target_options: &target_options,
|
||||
input_url: None,
|
||||
input: input.as_path(),
|
||||
job_id: common.job_id,
|
||||
task_id: common.task_id,
|
||||
target_timeout,
|
||||
check_retry_count,
|
||||
setup_dir: &common.setup_dir,
|
||||
minimized_stack_depth: None,
|
||||
check_asan_log,
|
||||
check_debugger,
|
||||
};
|
||||
|
||||
let result = test_input(config).await?;
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_shared_args() -> Vec<Arg<'static, 'static>> {
|
||||
vec![
|
||||
Arg::with_name(TARGET_EXE).takes_value(true).required(true),
|
||||
Arg::with_name("input").takes_value(true).required(true),
|
||||
Arg::with_name(TARGET_ENV)
|
||||
.long(TARGET_ENV)
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
Arg::with_name(TARGET_OPTIONS)
|
||||
.default_value("{input}")
|
||||
.long(TARGET_OPTIONS)
|
||||
.takes_value(true)
|
||||
.value_delimiter(" ")
|
||||
.help("Use a quoted string with space separation to denote multiple arguments"),
|
||||
Arg::with_name(TARGET_TIMEOUT)
|
||||
.takes_value(true)
|
||||
.long(TARGET_TIMEOUT),
|
||||
Arg::with_name(CHECK_RETRY_COUNT)
|
||||
.takes_value(true)
|
||||
.long(CHECK_RETRY_COUNT)
|
||||
.default_value("0"),
|
||||
Arg::with_name(CHECK_ASAN_LOG)
|
||||
.takes_value(false)
|
||||
.long(CHECK_ASAN_LOG),
|
||||
Arg::with_name(DISABLE_CHECK_DEBUGGER)
|
||||
.takes_value(false)
|
||||
.long("disable_check_debugger"),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn args(name: &'static str) -> App<'static, 'static> {
|
||||
SubCommand::with_name(name)
|
||||
.about("test an application with a specific input")
|
||||
.args(&build_shared_args())
|
||||
}
|
@ -32,24 +32,27 @@ pub struct CrashReport {
|
||||
pub call_stack: Vec<String>,
|
||||
pub call_stack_sha256: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub minimized_stack: Vec<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub minimized_stack_sha256: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub minimized_stack_function_names: Vec<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub minimized_stack_function_names_sha256: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub asan_log: Option<String>,
|
||||
|
||||
pub task_id: Uuid,
|
||||
|
||||
pub job_id: Uuid,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub scariness_score: Option<u32>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub scariness_description: Option<String>,
|
||||
}
|
||||
|
||||
@ -62,6 +65,7 @@ pub struct NoCrash {
|
||||
pub task_id: Uuid,
|
||||
pub job_id: Uuid,
|
||||
pub tries: u64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user