mod parser;
mod types;
pub use parser::{PtxSourceMap, SanitizerParser};
pub use types::{
AddressRegistry, BufferInfo, MemoryViolation, MemoryViolationType, SourceLocation,
};
use std::process::{Command, Stdio};
#[derive(Debug)]
pub struct SanitizerReport {
pub violations: Vec<MemoryViolation>,
pub success: bool,
pub raw_output: String,
}
impl SanitizerReport {
pub fn format(&self) -> String {
if self.success {
return "✅ No memory violations detected".to_string();
}
let registry = AddressRegistry::global().lock().expect("address registry lock poisoned");
let mut output = String::new();
output.push_str(&format!(
"🚨 SANITIZER REPORT: {} violation(s) detected\n\n",
self.violations.len()
));
for (i, violation) in self.violations.iter().enumerate() {
output.push_str(&format!("━━━ Violation {} ━━━\n", i + 1));
output.push_str(&violation.format_with_registry(®istry));
output.push_str("\n\n");
}
output
}
pub fn format_with_ptx(&self, ptx_map: &PtxSourceMap) -> String {
if self.success {
return "✅ No memory violations detected".to_string();
}
let registry = AddressRegistry::global().lock().expect("address registry lock poisoned");
let mut output = String::new();
output.push_str(&format!(
"🚨 SANITIZER REPORT: {} violation(s) detected\n\n",
self.violations.len()
));
for (i, violation) in self.violations.iter().enumerate() {
output.push_str(&format!("━━━ Violation {} ━━━\n", i + 1));
output.push_str(&violation.format_with_registry(®istry));
output.push('\n');
if let Some(label) = ptx_map.label_at_line(1) {
if let Some(context) = ptx_map.context_around_label(label, 5) {
output.push_str("\n📜 PTX Context:\n");
output.push_str(&context);
}
}
output.push_str("\n\n");
}
output
}
}
pub fn sanitizer_available() -> bool {
Command::new("compute-sanitizer")
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
pub fn run_with_sanitizer(args: &[&str]) -> Result<SanitizerReport, std::io::Error> {
let mut cmd = Command::new("compute-sanitizer");
cmd.arg("--tool").arg("memcheck");
cmd.args(args);
cmd.stdout(Stdio::piped());
cmd.stderr(Stdio::piped());
let output = cmd.output()?;
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let combined = format!("{}\n{}", stdout, stderr);
let violations = SanitizerParser::parse(&combined);
let success = violations.is_empty() && output.status.success();
Ok(SanitizerReport { violations, success, raw_output: combined })
}
#[cfg(test)]
mod tests;