Skip to content

Commit 5f871aa

Browse files
authored
Handle segfaults and aborts in C# code (#220)
* Handle segfaults and aborts in C# code * add native C# test
1 parent 552636c commit 5f871aa

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

casr/src/bin/casr-csharp.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ fn main() -> Result<()> {
141141
if let Some(exception) = CSharpException::parse_exception(&report_str) {
142142
report.execution_class = exception;
143143
}
144+
} else {
145+
// Call casr-san
146+
return util::call_casr_san(&matches, &argv, "casr-csharp");
144147
}
145148

146149
let stacktrace = CSharpStacktrace::parse_stacktrace(&report.stacktrace)?;

casr/src/triage.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,10 @@ pub fn fuzzing_crash_triage_pipeline(
223223
.join(". ")
224224
);
225225
} else {
226-
bail!("{}", String::from_utf8_lossy(&casr_cluster_d.stderr));
226+
bail!(
227+
"{}",
228+
String::from_utf8_lossy(&casr_cluster_d.stderr).trim_end()
229+
);
227230
}
228231

229232
if !matches.get_flag("no-cluster") {
@@ -251,7 +254,10 @@ pub fn fuzzing_crash_triage_pipeline(
251254
String::from_utf8_lossy(&casr_cluster_c.stdout).trim_end()
252255
);
253256
} else {
254-
error!("{}", String::from_utf8_lossy(&casr_cluster_c.stderr));
257+
error!(
258+
"{}",
259+
String::from_utf8_lossy(&casr_cluster_c.stderr).trim_end()
260+
);
255261
}
256262

257263
// Remove reports from deduplication phase. They are in clusters now.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <iostream>
2+
3+
extern "C" void seg(int len)
4+
{
5+
int a[10];
6+
a[len] = -1;
7+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.IO;
3+
using System.Runtime.InteropServices;
4+
5+
public class Program
6+
{
7+
public static void Seg()
8+
{
9+
[DllImport("native.so", EntryPoint="seg")]
10+
static extern void seg(int size);
11+
12+
seg(100000000);
13+
}
14+
15+
public static void Main(string[] args)
16+
{
17+
Seg();
18+
}
19+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>disable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

casr/tests/tests.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5724,6 +5724,73 @@ fn test_casr_csharp() {
57245724
}
57255725
}
57265726

5727+
#[test]
5728+
#[cfg(target_arch = "x86_64")]
5729+
fn test_casr_csharp_native() {
5730+
let paths = [
5731+
abs_path("tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.cs"),
5732+
abs_path("tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.csproj"),
5733+
abs_path("tests/casr_tests/csharp/test_casr_csharp_native/native.cpp"),
5734+
abs_path("tests/tmp_tests_casr/test_casr_csharp_native"),
5735+
abs_path("tests/tmp_tests_casr/test_casr_csharp_native/test_casr_csharp_native.cs"),
5736+
abs_path("tests/tmp_tests_casr/test_casr_csharp_native/test_casr_csharp_native.csproj"),
5737+
abs_path("tests/tmp_tests_casr/test_casr_csharp_native/native.so"),
5738+
];
5739+
let _ = std::fs::create_dir_all(&paths[3]);
5740+
let _ = fs::copy(&paths[0], &paths[4]);
5741+
let _ = fs::copy(&paths[1], &paths[5]);
5742+
let Ok(dotnet_path) = which::which("dotnet") else {
5743+
panic!("No dotnet is found.");
5744+
};
5745+
5746+
let _ = Command::new("clang++")
5747+
.args([&paths[2], "-g", "-fPIC", "-shared", "-o", &paths[6]])
5748+
.output()
5749+
.expect("failed to compile .so library");
5750+
5751+
let _ = Command::new("dotnet")
5752+
.args(["build", &paths[5]])
5753+
.output()
5754+
.expect("failed to build test");
5755+
5756+
let output = Command::new(*EXE_CASR_CSHARP.read().unwrap())
5757+
.args([
5758+
"--stdout",
5759+
"--",
5760+
(dotnet_path.to_str().unwrap()),
5761+
format!("{}/bin/Debug/net8.0/test_casr_csharp_native.dll", &paths[3]).as_str(),
5762+
])
5763+
.env("LD_LIBRARY_PATH", &paths[3])
5764+
.output()
5765+
.expect("failed to start casr-csharp");
5766+
5767+
assert!(
5768+
output.status.success(),
5769+
"Stdout {}.\n Stderr: {}",
5770+
String::from_utf8_lossy(&output.stdout),
5771+
String::from_utf8_lossy(&output.stderr)
5772+
);
5773+
5774+
let report: Result<Value, _> = serde_json::from_slice(&output.stdout);
5775+
if let Ok(report) = report {
5776+
let severity_type = report["CrashSeverity"]["Type"].as_str().unwrap();
5777+
let severity_desc = report["CrashSeverity"]["ShortDescription"]
5778+
.as_str()
5779+
.unwrap()
5780+
.to_string();
5781+
5782+
assert_eq!(19, report["Stacktrace"].as_array().unwrap().iter().count());
5783+
assert_eq!(severity_type, "NOT_EXPLOITABLE");
5784+
assert_eq!(severity_desc, "AccessViolation");
5785+
assert!(report["CrashLine"]
5786+
.as_str()
5787+
.unwrap()
5788+
.contains("native.cpp:6"));
5789+
} else {
5790+
panic!("Couldn't parse json report file.");
5791+
}
5792+
}
5793+
57275794
#[test]
57285795
#[cfg(target_arch = "x86_64")]
57295796
fn test_casr_afl_csharp() {

0 commit comments

Comments
 (0)