mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-15 19:38:11 +00:00
handle fake crash reports generated by debugging tools in regression tasks (#1233)
This commit is contained in:
29
src/agent/onefuzz-agent/data/fake-crash-report.json
Normal file
29
src/agent/onefuzz-agent/data/fake-crash-report.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"input_url": null,
|
||||||
|
"input_blob": {
|
||||||
|
"account": "fakestorageaccount",
|
||||||
|
"container": "fake-storage-container",
|
||||||
|
"name": "fake-crash-sample"
|
||||||
|
},
|
||||||
|
"executable": "dds.exe",
|
||||||
|
"crash_type": "fake crash report",
|
||||||
|
"crash_site": "fake crash site",
|
||||||
|
"call_stack": [
|
||||||
|
"#0 fake",
|
||||||
|
"#1 call",
|
||||||
|
"#2 stack"
|
||||||
|
],
|
||||||
|
"call_stack_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"input_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
|
"asan_log": "fake asan log",
|
||||||
|
"task_id": "2061fc8d-9f02-4d06-838a-87f59880e4e8",
|
||||||
|
"job_id": "510f8e4e-3c4d-4b54-968c-4da459d09f04",
|
||||||
|
"scariness_score": null,
|
||||||
|
"scariness_description": null,
|
||||||
|
"minimized_stack": [],
|
||||||
|
"minimized_stack_sha256": null,
|
||||||
|
"minimized_stack_function_names": [],
|
||||||
|
"minimized_stack_function_names_sha256": null,
|
||||||
|
"minimized_stack_function_lines": null,
|
||||||
|
"minimized_stack_function_lines_sha256": null
|
||||||
|
}
|
@ -40,8 +40,8 @@ pub struct CrashReport {
|
|||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub minimized_stack_function_names_sha256: Option<String>,
|
pub minimized_stack_function_names_sha256: Option<String>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub minimized_stack_function_lines: Vec<String>,
|
pub minimized_stack_function_lines: Option<Vec<String>>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub minimized_stack_function_lines_sha256: Option<String>,
|
pub minimized_stack_function_lines_sha256: Option<String>,
|
||||||
|
|
||||||
@ -206,6 +206,21 @@ impl CrashReport {
|
|||||||
} else {
|
} else {
|
||||||
Some(crash_log.minimized_stack_function_names_sha256(minimized_stack_depth))
|
Some(crash_log.minimized_stack_function_names_sha256(minimized_stack_depth))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let minimized_stack_function_lines = if crash_log.minimized_stack_function_lines.is_empty()
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(crash_log.minimized_stack_function_lines)
|
||||||
|
};
|
||||||
|
|
||||||
|
let minimized_stack_function_names = if crash_log.minimized_stack_function_names.is_empty()
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(crash_log.minimized_stack_function_names)
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
input_sha256,
|
input_sha256,
|
||||||
input_blob,
|
input_blob,
|
||||||
@ -215,9 +230,9 @@ impl CrashReport {
|
|||||||
call_stack_sha256,
|
call_stack_sha256,
|
||||||
minimized_stack: Some(crash_log.minimized_stack),
|
minimized_stack: Some(crash_log.minimized_stack),
|
||||||
minimized_stack_sha256,
|
minimized_stack_sha256,
|
||||||
minimized_stack_function_names: Some(crash_log.minimized_stack_function_names),
|
minimized_stack_function_names,
|
||||||
minimized_stack_function_names_sha256,
|
minimized_stack_function_names_sha256,
|
||||||
minimized_stack_function_lines: crash_log.minimized_stack_function_lines,
|
minimized_stack_function_lines,
|
||||||
minimized_stack_function_lines_sha256,
|
minimized_stack_function_lines_sha256,
|
||||||
call_stack: crash_log.call_stack,
|
call_stack: crash_log.call_stack,
|
||||||
asan_log: crash_log.text,
|
asan_log: crash_log.text,
|
||||||
@ -251,15 +266,25 @@ pub async fn parse_report_file(path: PathBuf) -> Result<CrashTestResult> {
|
|||||||
.with_context(|| format_err!("invalid json: {} - {:?}", path.display(), raw))?;
|
.with_context(|| format_err!("invalid json: {} - {:?}", path.display(), raw))?;
|
||||||
|
|
||||||
let report: Result<CrashReport, serde_json::Error> = serde_json::from_value(json.clone());
|
let report: Result<CrashReport, serde_json::Error> = serde_json::from_value(json.clone());
|
||||||
if let Ok(report) = report {
|
|
||||||
return Ok(CrashTestResult::CrashReport(report));
|
|
||||||
}
|
|
||||||
let no_repro: Result<NoCrash, serde_json::Error> = serde_json::from_value(json);
|
|
||||||
if let Ok(no_repro) = no_repro {
|
|
||||||
return Ok(CrashTestResult::NoRepro(no_repro));
|
|
||||||
}
|
|
||||||
|
|
||||||
bail!("unable to parse report: {} - {:?}", path.display(), raw)
|
let report_err = match report {
|
||||||
|
Ok(report) => return Ok(CrashTestResult::CrashReport(report)),
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
let no_repro: Result<NoCrash, serde_json::Error> = serde_json::from_value(json);
|
||||||
|
|
||||||
|
let no_repro_err = match no_repro {
|
||||||
|
Ok(no_repro) => return Ok(CrashTestResult::NoRepro(no_repro)),
|
||||||
|
Err(err) => err,
|
||||||
|
};
|
||||||
|
|
||||||
|
bail!(
|
||||||
|
"unable to parse report: {} - {:?} - report error: {:?} no_repo error: {:?}",
|
||||||
|
path.display(),
|
||||||
|
raw,
|
||||||
|
report_err,
|
||||||
|
no_repro_err
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn monitor_reports(
|
pub async fn monitor_reports(
|
||||||
@ -281,3 +306,16 @@ pub async fn monitor_reports(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_parse_fake_crash_report() -> Result<()> {
|
||||||
|
let path = std::path::PathBuf::from("data/fake-crash-report.json");
|
||||||
|
parse_report_file(path).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -631,7 +631,7 @@ class DebugNotification(Command):
|
|||||||
|
|
||||||
def job(
|
def job(
|
||||||
self,
|
self,
|
||||||
job_id: str,
|
job_id: UUID_EXPANSION,
|
||||||
*,
|
*,
|
||||||
report_container_type: ContainerType = ContainerType.unique_reports,
|
report_container_type: ContainerType = ContainerType.unique_reports,
|
||||||
crash_name: str = "fake-crash-sample",
|
crash_name: str = "fake-crash-sample",
|
||||||
@ -655,7 +655,7 @@ class DebugNotification(Command):
|
|||||||
|
|
||||||
def task(
|
def task(
|
||||||
self,
|
self,
|
||||||
task_id: str,
|
task_id: UUID_EXPANSION,
|
||||||
*,
|
*,
|
||||||
report_container_type: ContainerType = ContainerType.unique_reports,
|
report_container_type: ContainerType = ContainerType.unique_reports,
|
||||||
crash_name: str = "fake-crash-sample",
|
crash_name: str = "fake-crash-sample",
|
||||||
|
@ -69,6 +69,7 @@ class Integration(BaseModel):
|
|||||||
reboot_after_setup: Optional[bool] = Field(default=False)
|
reboot_after_setup: Optional[bool] = Field(default=False)
|
||||||
test_repro: Optional[bool] = Field(default=True)
|
test_repro: Optional[bool] = Field(default=True)
|
||||||
target_options: Optional[List[str]]
|
target_options: Optional[List[str]]
|
||||||
|
inject_fake_regression: bool = Field(default=False)
|
||||||
|
|
||||||
|
|
||||||
TARGETS: Dict[str, Integration] = {
|
TARGETS: Dict[str, Integration] = {
|
||||||
@ -90,6 +91,7 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
ContainerType.inputs: 2,
|
ContainerType.inputs: 2,
|
||||||
},
|
},
|
||||||
reboot_after_setup=True,
|
reboot_after_setup=True,
|
||||||
|
inject_fake_regression=True,
|
||||||
),
|
),
|
||||||
"linux-libfuzzer-with-options": Integration(
|
"linux-libfuzzer-with-options": Integration(
|
||||||
template=TemplateType.libfuzzer,
|
template=TemplateType.libfuzzer,
|
||||||
@ -161,6 +163,7 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
target_exe="fuzz.exe",
|
target_exe="fuzz.exe",
|
||||||
inputs="seeds",
|
inputs="seeds",
|
||||||
wait_for_files={ContainerType.unique_reports: 1},
|
wait_for_files={ContainerType.unique_reports: 1},
|
||||||
|
inject_fake_regression=True,
|
||||||
),
|
),
|
||||||
"linux-trivial-crash-asan": Integration(
|
"linux-trivial-crash-asan": Integration(
|
||||||
template=TemplateType.radamsa,
|
template=TemplateType.radamsa,
|
||||||
@ -181,6 +184,7 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
ContainerType.unique_reports: 1,
|
ContainerType.unique_reports: 1,
|
||||||
ContainerType.coverage: 1,
|
ContainerType.coverage: 1,
|
||||||
},
|
},
|
||||||
|
inject_fake_regression=True,
|
||||||
),
|
),
|
||||||
"windows-libfuzzer-linked-library": Integration(
|
"windows-libfuzzer-linked-library": Integration(
|
||||||
template=TemplateType.libfuzzer,
|
template=TemplateType.libfuzzer,
|
||||||
@ -212,6 +216,7 @@ TARGETS: Dict[str, Integration] = {
|
|||||||
target_exe="fuzz.exe",
|
target_exe="fuzz.exe",
|
||||||
inputs="seeds",
|
inputs="seeds",
|
||||||
wait_for_files={ContainerType.unique_reports: 1},
|
wait_for_files={ContainerType.unique_reports: 1},
|
||||||
|
inject_fake_regression=True,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +342,9 @@ class TestOnefuzz:
|
|||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if config.inject_fake_regression and job is not None:
|
||||||
|
self.of.debug.notification.job(job.job_id)
|
||||||
|
|
||||||
if not job:
|
if not job:
|
||||||
raise Exception("missing job")
|
raise Exception("missing job")
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user