Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
3c8324d
add new json struture
ConnorJKY Sep 11, 2025
87efbe2
add detailed info for harnesses in json handler
ConnorJKY Sep 11, 2025
4c21c65
feat: finish phase2 prototype on harness_runner
yimingyinqwqq Sep 16, 2025
2351326
feat: add harness that fail fast to json handler and refactor logic t…
yimingyinqwqq Sep 17, 2025
e7fa713
Phase 3: Summary and Timing
jingfei-xu Sep 17, 2025
edc5550
Error Details + Property Details
jingfei-xu Sep 18, 2025
7b08e18
Move harness info to match the result; add version number and timeline
ConnorJKY Sep 18, 2025
5346c86
Merge remote-tracking branch 'origin/feat/json-handler' into feat/jso…
ConnorJKY Sep 18, 2025
cacdb7b
Move harness info to match the result; add version number and timeline
ConnorJKY Sep 18, 2025
f6d23e6
Error Details and Property Analysis
jingfei-xu Sep 18, 2025
f89bb7f
refactor existing json handler code to frontend folder
yimingyinqwqq Sep 19, 2025
c628621
Restore util.rs and refactor schema logic into frontend/schema_utils.rs
yimingyinqwqq Sep 20, 2025
3822a14
Extend frontend util function for project and export run metadata; Re…
ConnorJKY Sep 21, 2025
0591837
finish json schma implementation of verification_results
yimingyinqwqq Sep 23, 2025
961591c
Update metadata of target, contract in schema
ConnorJKY Sep 29, 2025
74bb569
Merge remote-tracking branch 'origin/feat/json-handler' into feat/jso…
ConnorJKY Sep 29, 2025
d432b8d
chore: Remove build artifacts from first-steps-v1/target
yimingyinqwqq Oct 7, 2025
6f3e506
Merge branch 'feat/json-handler' of https://github.com/yimingyinqwqq/…
yimingyinqwqq Oct 7, 2025
068e721
chore: Remove print lines and extract functions in kani-driver harnes…
yimingyinqwqq Oct 7, 2025
6747d35
chore: Remove unnecessary time information in main
yimingyinqwqq Oct 7, 2025
a2e7757
chore: Update s2n-quic submodule to match main branch
yimingyinqwqq Oct 7, 2025
29f8c18
Update schema_utils.rs - Structure for any tool's output
ShrivyasShrivyas Oct 12, 2025
b0b12cb
All CBMC changes
ShrivyasShrivyas Oct 13, 2025
162ea19
removed unnecessary methods
ShrivyasShrivyas Oct 13, 2025
94199fc
chore: format the code
yimingyinqwqq Oct 22, 2025
13db7d9
fix: revert version back to 0.65.0
yimingyinqwqq Oct 23, 2025
9a1deb3
chore: add example text for better commenting
yimingyinqwqq Oct 23, 2025
b169a7a
chore: remove s2n-quic submodule
yimingyinqwqq Oct 23, 2025
f5913e6
Revert "chore: Update s2n-quic submodule to match main branch"
yimingyinqwqq Oct 23, 2025
f9df1e4
chore: Update s2n-quic submodule to match main
yimingyinqwqq Oct 23, 2025
b560dc9
Roll back s2n-quic submodule to commit 26e2402
yimingyinqwqq Oct 28, 2025
947664b
Updated cbmc with original code and removed comments
ShrivyasShrivyas Oct 29, 2025
bb4a2a2
test: update regression test to support json handler
yimingyinqwqq Oct 30, 2025
9715a9c
fix: incoporate optional field in json schema when json not fail
yimingyinqwqq Oct 30, 2025
0cfaa00
chore: add json-handler rfc documentation
yimingyinqwqq Nov 5, 2025
d18aef7
Unit Tests for schema_utils
ShrivyasShrivyas Nov 5, 2025
83437d1
Merge branch 'feat/json-handler' of https://github.com/yimingyinqwqq/…
ShrivyasShrivyas Nov 5, 2025
e2d609a
chore: format unit tests
yimingyinqwqq Nov 5, 2025
ed8f985
Merge branch 'main' into feat/json-handler
yimingyinqwqq Nov 10, 2025
e077296
fix: fix unclose parenthesis
yimingyinqwqq Nov 10, 2025
99faa80
fix: resolve cbmc conflicts and remove unused import in main
yimingyinqwqq Nov 10, 2025
dc00668
chore: remove old json files
yimingyinqwqq Nov 10, 2025
ab5500d
Merge pull request #2 from yimingyinqwqq/feat/json-handler
yimingyinqwqq Nov 10, 2025
c035d82
Merge branch 'model-checking:main' into main
yimingyinqwqq Nov 12, 2025
ffd5565
Merge branch 'model-checking:main' into main
yimingyinqwqq Nov 13, 2025
f49b382
Merge branch 'model-checking:main' into main
yimingyinqwqq Nov 13, 2025
4537df2
fix: format frontend code and fix json file not found error
yimingyinqwqq Nov 14, 2025
0bfae8b
Merge pull request #5 from yimingyinqwqq/feat/json-handler
yimingyinqwqq Nov 14, 2025
664a644
fix: update cbmc for minimal changes, delete redundant changes
yimingyinqwqq Nov 14, 2025
e9dc6cf
fix: revert to previous commit
yimingyinqwqq Nov 14, 2025
0879d35
Merge pull request #6 from yimingyinqwqq/feat/json-handler
yimingyinqwqq Nov 14, 2025
4943397
Merge branch 'model-checking:main' into main
yimingyinqwqq Nov 18, 2025
d6ed20c
Add Kani MCP Server for Amazon Q integration
jingfei-xu Oct 21, 2025
9e9d46a
Add Kani MCP server and Amazon Q complete implementation
jingfei-xu Oct 23, 2025
f7f2575
Amazon Q CLI Integration
jingfei-xu Oct 30, 2025
d00d94e
Amazon Q latest integration (Amazon Q CLI)
jingfei-xu Nov 6, 2025
fe39541
Code Format Cleanup
jingfei-xu Nov 6, 2025
71bff51
Comments fixed
jingfei-xu Nov 18, 2025
fb10f35
Comments fixed: delete irrelevant files
ConnorJKY Nov 20, 2025
c0e58c8
Merge pull request #7 from yimingyinqwqq/mcp
ConnorJKY Nov 20, 2025
dca6c70
chore: update kani format on cbmc
yimingyinqwqq Nov 20, 2025
30382bb
Revert "Update: MCP Integration with Amazon Q CLI"
ConnorJKY Nov 20, 2025
7bd13c2
Merge pull request #8 from yimingyinqwqq/revert-7-mcp
ConnorJKY Nov 20, 2025
be0777a
Merge branch 'model-checking:main' into main
yimingyinqwqq Nov 20, 2025
678cabd
chore: add copyright to frontend module
yimingyinqwqq Nov 24, 2025
dc0a507
Merge pull request #9 from yimingyinqwqq/feat/json-handler
yimingyinqwqq Nov 24, 2025
f8f1a46
ci: fix copyright and clippy check
yimingyinqwqq Nov 24, 2025
064fbd6
Merge pull request #10 from yimingyinqwqq/feat/json-handler
yimingyinqwqq Nov 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions kani-driver/src/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ pub struct VerificationArgs {
#[arg(long)]
pub default_unwind: Option<u32>,

#[arg(long = "export-json")]
pub export_json: Option<PathBuf>,

/// When specified, the harness filter will only match the exact fully qualified name of a harness
#[arg(long, requires("harnesses"))]
pub exact: bool,
Expand Down
206 changes: 205 additions & 1 deletion kani-driver/src/call_cbmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,154 @@ use crate::coverage::cov_results::{CoverageRegion, CoverageTerm};
use crate::session::KaniSession;
use crate::util::render_command;

/// CBMC version and system information
#[derive(Debug, Clone)]
pub struct CbmcInfo {
pub version: String,
pub os_info: String,
}

/// CBMC runtime and execution statistics
#[derive(Debug, Clone, Default)]
pub struct CbmcStats {
pub runtime_symex_s: Option<f64>,
pub size_program_expression: Option<u32>,
pub slicing_removed_assignments: Option<u32>,
pub vccs_generated: Option<u32>,
pub vccs_remaining: Option<u32>,
pub runtime_postprocess_equation_s: Option<f64>,
pub runtime_convert_ssa_s: Option<f64>,
pub runtime_post_process_s: Option<f64>,
pub runtime_solver_s: Option<f64>,
pub runtime_decision_procedure_s: Option<f64>,
}

impl KaniSession {
/// Get CBMC version and system information
pub fn get_cbmc_info(&self) -> Result<CbmcInfo> {
let output = std::process::Command::new("cbmc")
.arg("--version")
.output()
.map_err(|_| anyhow::Error::msg("Failed to run cbmc --version"))?;

let version_output = String::from_utf8_lossy(&output.stdout);
let lines: Vec<&str> = version_output.lines().collect();

// Extract version from first line (e.g., "6.7.1 (cbmc-6.7.1)")
let version = lines
.first()
.and_then(|line| line.split_whitespace().next())
.unwrap_or("unknown")
.to_string();

// For OS info, we'll use the system information since CBMC --version doesn't provide it
let os_info = format!(
"{} {} {}",
std::env::consts::ARCH,
std::env::consts::OS,
std::env::consts::FAMILY
);

Ok(CbmcInfo { version, os_info })
}

/// Extract CBMC statistics from a message
fn extract_cbmc_stats_from_message(message: &str) -> Option<CbmcStats> {
let mut stats = CbmcStats::default();
let mut found_any = false;

// Example: "Runtime Symex: 0.00408627s"
if let Some(captures) =
regex::Regex::new(r"Runtime Symex: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_symex_s = Some(val);
found_any = true;
}

// Example: "size of program expression: 150 steps"
if let Some(captures) =
regex::Regex::new(r"size of program expression: (\d+) steps").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<u32>()
{
stats.size_program_expression = Some(val);
found_any = true;
}

// Example: "slicing removed 81 assignments"
if let Some(captures) =
regex::Regex::new(r"slicing removed (\d+) assignments").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<u32>()
{
stats.slicing_removed_assignments = Some(val);
found_any = true;
}

// Example: "Generated 1 VCC(s), 1 remaining after simplification"
if let Some(captures) =
regex::Regex::new(r"Generated (\d+) VCC\(s\), (\d+) remaining after simplification")
.ok()?
.captures(message)
{
if let Ok(generated) = captures[1].parse::<u32>() {
stats.vccs_generated = Some(generated);
found_any = true;
}
if let Ok(remaining) = captures[2].parse::<u32>() {
stats.vccs_remaining = Some(remaining);
found_any = true;
}
}

// Example: "Runtime Postprocess Equation: 0.000767182s"
if let Some(captures) =
regex::Regex::new(r"Runtime Postprocess Equation: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_postprocess_equation_s = Some(val);
found_any = true;
}

// Example: "Runtime Convert SSA: 0.000516981s"
if let Some(captures) =
regex::Regex::new(r"Runtime Convert SSA: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_convert_ssa_s = Some(val);
found_any = true;
}

// Example: "Runtime Post-process: 0.000189636s"
if let Some(captures) =
regex::Regex::new(r"Runtime Post-process: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_post_process_s = Some(val);
found_any = true;
}

// Example: "Runtime Solver: 0.00167592s"
if let Some(captures) =
regex::Regex::new(r"Runtime Solver: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_solver_s = Some(val);
found_any = true;
}

// Example: "Runtime decision procedure: 0.00452419s"
if let Some(captures) =
regex::Regex::new(r"Runtime decision procedure: ([-e\d\.]+)s").ok()?.captures(message)
&& let Ok(val) = captures[1].parse::<f64>()
{
stats.runtime_decision_procedure_s = Some(val);
found_any = true;
}

if found_any { Some(stats) } else { None }
}
}

/// We will use Cadical by default since it performed better than MiniSAT in our analysis.
/// Note: Kissat was marginally better, but it is an external solver which could be more unstable.
static DEFAULT_SOLVER: CbmcSolver = CbmcSolver::Cadical;
Expand Down Expand Up @@ -75,6 +223,8 @@ pub struct VerificationResult {
pub generated_concrete_test: bool,
/// The coverage results
pub coverage_results: Option<CoverageResults>,
/// CBMC execution statistics extracted from messages
pub cbmc_stats: Option<CbmcStats>,
}

impl KaniSession {
Expand Down Expand Up @@ -161,6 +311,7 @@ impl KaniSession {
runtime: start_time.elapsed(),
generated_concrete_test: false,
coverage_results: None,
cbmc_stats: None,
})
}
}
Expand Down Expand Up @@ -325,7 +476,56 @@ impl VerificationResult {
start_time: Instant,
) -> VerificationResult {
let runtime = start_time.elapsed();
let (_, results) = extract_results(output.processed_items);
let (remaining_items, results) = extract_results(output.processed_items);

// Collect CBMC stats from messages
let mut cbmc_stats = CbmcStats::default();
for item in &remaining_items {
if let crate::cbmc_output_parser::ParserItem::Message { message_text, .. } = item
&& let Some(stats) = KaniSession::extract_cbmc_stats_from_message(message_text)
{
// Merge stats (later messages may have more complete info)
if stats.runtime_symex_s.is_some() {
cbmc_stats.runtime_symex_s = stats.runtime_symex_s;
}
if stats.size_program_expression.is_some() {
cbmc_stats.size_program_expression = stats.size_program_expression;
}
if stats.slicing_removed_assignments.is_some() {
cbmc_stats.slicing_removed_assignments = stats.slicing_removed_assignments;
}
if stats.vccs_generated.is_some() {
cbmc_stats.vccs_generated = stats.vccs_generated;
}
if stats.vccs_remaining.is_some() {
cbmc_stats.vccs_remaining = stats.vccs_remaining;
}
if stats.runtime_postprocess_equation_s.is_some() {
cbmc_stats.runtime_postprocess_equation_s =
stats.runtime_postprocess_equation_s;
}
if stats.runtime_convert_ssa_s.is_some() {
cbmc_stats.runtime_convert_ssa_s = stats.runtime_convert_ssa_s;
}
if stats.runtime_post_process_s.is_some() {
cbmc_stats.runtime_post_process_s = stats.runtime_post_process_s;
}
if stats.runtime_solver_s.is_some() {
cbmc_stats.runtime_solver_s = stats.runtime_solver_s;
}
if stats.runtime_decision_procedure_s.is_some() {
cbmc_stats.runtime_decision_procedure_s = stats.runtime_decision_procedure_s;
}
}
}

let cbmc_stats = if cbmc_stats.runtime_symex_s.is_some()
|| cbmc_stats.size_program_expression.is_some()
{
Some(cbmc_stats)
} else {
None
};

if let Some(results) = results {
let (status, failed_properties) =
Expand All @@ -338,6 +538,7 @@ impl VerificationResult {
runtime,
generated_concrete_test: false,
coverage_results,
cbmc_stats,
}
} else {
// We never got results from CBMC - something went wrong (e.g. crash) so it's failure
Expand All @@ -353,6 +554,7 @@ impl VerificationResult {
runtime,
generated_concrete_test: false,
coverage_results: None,
cbmc_stats,
}
}
}
Expand All @@ -365,6 +567,7 @@ impl VerificationResult {
runtime: Duration::from_secs(0),
generated_concrete_test: false,
coverage_results: None,
cbmc_stats: None,
}
}

Expand All @@ -379,6 +582,7 @@ impl VerificationResult {
runtime: Duration::from_secs(0),
generated_concrete_test: false,
coverage_results: None,
cbmc_stats: None,
}
}

Expand Down
51 changes: 51 additions & 0 deletions kani-driver/src/frontend/json_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use serde_json::{Value, json};
use std::path::PathBuf;

/// A handler for building and exporting JSON data structures.
///
/// `JsonHandler` provides a convenient interface for constructing JSON objects,
/// adding key-value pairs, appending to arrays, and exporting the final result
/// to a file.
pub struct JsonHandler {
/// The JSON data being constructed.
pub(crate) data: Value,
/// Optional path where the JSON data will be exported.
export_path: Option<PathBuf>,
}

impl JsonHandler {
/// Creates a new `JsonHandler` with an optional export path.
/// If `export_path` is `None`, calls to `export()` will be no-ops.
pub fn new(export_path: Option<PathBuf>) -> Self {
Self { data: json!({}), export_path }
}

/// Adds or updates a key-value pair in the JSON object.
/// If the key already exists, its value will be overwritten.
pub fn add_item(&mut self, key: &str, value: Value) {
self.data[key] = value;
}

/// Appends a value to the array at the specified key.
/// Creates a new array if the key doesn't exist or is null.
/// Panics if the key exists but is not an array or null.
pub fn add_harness_detail(&mut self, key: &str, value: Value) {
if self.data[key].is_null() {
self.data[key] = json!([]);
}
self.data[key].as_array_mut().unwrap().push(value);
}

/// Exports the JSON data to the configured file path with pretty-printing.
/// Returns an error if the file cannot be written.
pub fn export(&self) -> Result<(), std::io::Error> {
if let Some(path) = &self.export_path {
std::fs::write(path, serde_json::to_string_pretty(&self.data)?)
} else {
Ok(())
}
}
}
14 changes: 14 additions & 0 deletions kani-driver/src/frontend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Frontend module for handling different output formats and JSON generation
//! This module separates the JSON handling logic from the main verification logic

pub mod json_handler;
pub mod schema_utils;

pub use json_handler::JsonHandler;
pub use schema_utils::*;

#[cfg(test)]
mod tests;
Loading
Loading