Unverified Commit a8574343 by van den Bosch Committed by GitHub

Macros and test changes (#380)

parent 2c766f5a
......@@ -79,12 +79,12 @@ fn main() -> Result<(), Error> {
/// Return `Ok(file_path)` only if `file_path` points to an existing file.
fn check_file_existence(file_path: &str) -> Result<String, String> {
if std::fs::metadata(file_path)
.map_err(|err| format!("{}", err))?
.map_err(|err| format!("{err}"))?
.is_file()
{
Ok(file_path.to_string())
} else {
Err(format!("{} is not a file.", file_path))
Err(format!("{file_path} is not a file."))
}
}
......@@ -95,7 +95,7 @@ fn run_with_ghidra(args: &CmdlineArgs) -> Result<(), Error> {
// Only print the module versions and then quit.
println!("[cwe_checker] module_versions:");
for module in modules.iter() {
println!("{}", module);
println!("{module}");
}
return Ok(());
}
......@@ -235,7 +235,7 @@ fn filter_modules_for_partial_run(
} else if module_name.is_empty() {
None
} else {
panic!("Error: {} is not a valid module name.", module_name)
panic!("Error: {module_name} is not a valid module name.")
}
})
.collect();
......
......@@ -180,11 +180,12 @@ impl std::fmt::Display for BitvectorDomain {
}
#[cfg(test)]
mod tests {
pub mod tests {
use super::*;
use crate::bitvec;
fn bv(value: i64) -> BitvectorDomain {
BitvectorDomain::Value(Bitvector::from_i64(value))
bitvec!(format!("{}:8", value)).into()
}
#[test]
......@@ -211,11 +212,11 @@ mod tests {
assert_eq!(
sixteen.bin_op(IntEqual, &bv(16)),
BitvectorDomain::Value(Bitvector::from_u8(true as u8))
BitvectorDomain::Value(bitvec!(format!("{}:1", true as u8)))
);
assert_eq!(
sixteen.bin_op(IntNotEqual, &bv(16)),
BitvectorDomain::Value(Bitvector::from_u8(false as u8))
BitvectorDomain::Value(bitvec!(format!("{}:1", false as u8)))
);
assert_eq!(sixteen.un_op(Int2Comp), bv(-16));
......@@ -223,27 +224,26 @@ mod tests {
assert_eq!(
sixteen.subpiece(ByteSize::new(0), ByteSize::new(4)),
BitvectorDomain::Value(Bitvector::from_i32(16))
BitvectorDomain::Value(bitvec!("16:4"))
);
assert_eq!(
sixteen.subpiece(ByteSize::new(4), ByteSize::new(4)),
BitvectorDomain::Value(Bitvector::from_i32(0))
BitvectorDomain::Value(bitvec!("0:4"))
);
assert_eq!(
BitvectorDomain::Value(Bitvector::from_i32(2)),
BitvectorDomain::Value(Bitvector::from_i64(2 << 32))
.subpiece(ByteSize::new(4), ByteSize::new(4))
BitvectorDomain::Value(bitvec!("2:4")),
bv(2 << 32).subpiece(ByteSize::new(4), ByteSize::new(4))
);
assert_eq!(
BitvectorDomain::Value(Bitvector::from_i32(-1))
.bin_op(Piece, &BitvectorDomain::Value(Bitvector::from_i32(-1))),
BitvectorDomain::Value(bitvec!("-1:4"))
.bin_op(Piece, &BitvectorDomain::Value(bitvec!("-1:4"))),
bv(-1)
);
assert_eq!(
BitvectorDomain::Value(Bitvector::from_i32(-1)).cast(PopCount, ByteSize::new(8)),
BitvectorDomain::Value(bitvec!("-1:4")).cast(PopCount, ByteSize::new(8)),
bv(32)
)
}
......@@ -262,26 +262,14 @@ mod tests {
#[test]
fn arshift() {
use BinOpType::IntSRight;
let positive_x = BitvectorDomain::Value(Bitvector::from_i64(31));
let negative_x = BitvectorDomain::Value(Bitvector::from_i64(-31));
let shift_3 = BitvectorDomain::Value(Bitvector::from_u8(3));
let shift_70 = BitvectorDomain::Value(Bitvector::from_u8(70));
assert_eq!(
positive_x.bin_op(IntSRight, &shift_3),
BitvectorDomain::Value(Bitvector::from_i64(3))
);
assert_eq!(
positive_x.bin_op(IntSRight, &shift_70),
BitvectorDomain::Value(Bitvector::from_i64(0))
);
assert_eq!(
negative_x.bin_op(IntSRight, &shift_3),
BitvectorDomain::Value(Bitvector::from_i64(-4))
);
assert_eq!(
negative_x.bin_op(IntSRight, &shift_70),
BitvectorDomain::Value(Bitvector::from_i64(-1))
);
let positive_x = bv(31);
let negative_x = bv(-31);
let shift_3 = BitvectorDomain::Value(bitvec!("3:1"));
let shift_70 = BitvectorDomain::Value(bitvec!("70:1"));
assert_eq!(positive_x.bin_op(IntSRight, &shift_3), bv(3));
assert_eq!(positive_x.bin_op(IntSRight, &shift_70), bv(0));
assert_eq!(negative_x.bin_op(IntSRight, &shift_3), bv(-4));
assert_eq!(negative_x.bin_op(IntSRight, &shift_70), bv(-1));
}
#[test]
......
......@@ -197,7 +197,7 @@ impl fmt::Display for BricksDomain {
BricksDomain::Value(brick_domains) => {
write!(f, "Bricks: ")?;
for brick_domain in brick_domains.iter() {
write!(f, "{} ", brick_domain)?;
write!(f, "{brick_domain} ")?;
}
Ok(())
......
......@@ -169,7 +169,7 @@ impl fmt::Display for CharacterInclusionDomain {
match self {
CharacterInclusionDomain::Top => write!(f, "Top"),
CharacterInclusionDomain::Value((certain_set, possible_set)) => {
write!(f, "Certain: {}, Possible: {}", certain_set, possible_set)
write!(f, "Certain: {certain_set}, Possible: {possible_set}")
}
}
}
......@@ -243,7 +243,7 @@ impl fmt::Display for CharacterSet {
match self {
CharacterSet::Top => write!(f, "Top"),
CharacterSet::Value(char_set) => {
write!(f, "{:?}", char_set)
write!(f, "{char_set:?}")
}
}
}
......
......@@ -215,8 +215,8 @@ impl<T: RegisterDomain + Display> DataDomain<T> {
if !self.relative_values.is_empty() {
let target_iter = self.relative_values.iter().map(|(id, offset)| {
(
format!("{}", id),
serde_json::Value::String(format!("{}", offset)),
format!("{id}"),
serde_json::Value::String(format!("{offset}")),
)
});
let targets = serde_json::Value::Object(target_iter.collect());
......@@ -226,8 +226,7 @@ impl<T: RegisterDomain + Display> DataDomain<T> {
}
if let Some(absolute_value) = &self.absolute_value {
values.push(serde_json::Value::String(format!(
"Value: {}",
absolute_value
"Value: {absolute_value}"
)));
}
if self.contains_top_values {
......@@ -248,6 +247,7 @@ impl<T: RegisterDomain + Display> DataDomain<T> {
mod tests {
use super::super::*;
use super::*;
use crate::{bitvec, variable};
impl<T: RegisterDomain> DataDomain<T> {
/// Return a new domain representing a set of relative values.
......@@ -267,13 +267,13 @@ mod tests {
}
fn bv(value: i64) -> BitvectorDomain {
BitvectorDomain::Value(Bitvector::from_i64(value))
bitvec!(format!("{}:8", value)).into()
}
fn new_id(name: &str) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new("time0"),
AbstractLocation::Register(Variable::mock(name, ByteSize::new(8))),
AbstractLocation::Register(variable!(format!("{}:8", name))),
)
}
......
......@@ -244,18 +244,18 @@ impl<T: RegisterDomain> std::ops::Sub for DataDomain<T> {
mod tests {
use super::super::*;
use super::*;
use crate::abstract_domain::*;
use crate::{abstract_domain::*, bitvec, variable};
type Data = DataDomain<BitvectorDomain>;
fn bv(value: i64) -> BitvectorDomain {
BitvectorDomain::Value(Bitvector::from_i64(value))
BitvectorDomain::Value(bitvec!(format!("{}:8", value)))
}
fn new_id(name: &str) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new("time0"),
AbstractLocation::Register(Variable::mock(name, ByteSize::new(8))),
AbstractLocation::Register(variable!(format!("{}:8", name))),
)
}
......@@ -313,7 +313,7 @@ mod tests {
assert_eq!(
three.subpiece(ByteSize::new(0), ByteSize::new(4)),
BitvectorDomain::Value(Bitvector::from_i32(3)).into()
BitvectorDomain::Value(bitvec!("3:4")).into()
);
assert_eq!(
......@@ -321,8 +321,8 @@ mod tests {
ByteSize::new(16)
);
let one: Data = BitvectorDomain::Value(Bitvector::from_i32(1)).into();
let two: Data = BitvectorDomain::Value(Bitvector::from_i32(2)).into();
let one: Data = BitvectorDomain::Value(bitvec!("1:4")).into();
let two: Data = BitvectorDomain::Value(bitvec!("2:4")).into();
let concat = new_value((1 << 32) + 2);
assert_eq!(one.bin_op(Piece, &two), concat);
}
......
......@@ -118,12 +118,12 @@ impl<T: SpecializeByConditional + RegisterDomain> SpecializeByConditional for Da
#[cfg(test)]
mod tests {
use super::*;
use crate::abstract_domain::*;
use crate::{abstract_domain::*, variable};
fn new_id(name: &str) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new("time0"),
AbstractLocation::Register(Variable::mock(name, ByteSize::new(8))),
AbstractLocation::Register(variable!(format!("{}:8", name))),
)
}
......
......@@ -109,18 +109,18 @@ impl<T: RegisterDomain + TryToInterval> TryToInterval for DataDomain<T> {
mod tests {
use super::super::*;
use super::*;
use crate::abstract_domain::*;
use crate::{abstract_domain::*, bitvec, variable};
type Data = DataDomain<BitvectorDomain>;
fn bv(value: i64) -> BitvectorDomain {
BitvectorDomain::Value(Bitvector::from_i64(value))
BitvectorDomain::Value(bitvec!(format!("{}:8", value)))
}
fn new_id(name: &str) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new("time0"),
AbstractLocation::Register(Variable::mock(name, ByteSize::new(8))),
AbstractLocation::Register(variable!(format!("{}:8", name))),
)
}
......
......@@ -217,23 +217,22 @@ impl<K: Ord + Clone, V: AbstractDomain + HasTop> MapMergeStrategy<K, V> for Merg
#[cfg(test)]
mod tests {
use super::*;
use crate::bitvec;
use std::collections::BTreeMap;
use crate::intermediate_representation::Bitvector;
#[test]
fn test_merge_strategies() {
let map_left: BTreeMap<u64, DataDomain<BitvectorDomain>> = [
(0u64, Bitvector::from_i64(0).into()),
(1u64, Bitvector::from_i64(0).into()),
(0u64, bitvec!("0:8").into()),
(1u64, bitvec!("0:8").into()),
(5u64, DataDomain::new_top(ByteSize::new(8))),
]
.iter()
.cloned()
.collect();
let map_right: BTreeMap<u64, DataDomain<BitvectorDomain>> = [
(1u64, Bitvector::from_i64(1).into()),
(2u64, Bitvector::from_i64(1).into()),
(1u64, bitvec!("1:8").into()),
(2u64, bitvec!("1:8").into()),
(5u64, DataDomain::new_top(ByteSize::new(8))),
]
.iter()
......@@ -244,12 +243,12 @@ mod tests {
let domain_map_left: DomainMap<_, _, UnionMergeStrategy> = map_left.clone().into();
let domain_map_right: DomainMap<_, _, UnionMergeStrategy> = map_right.clone().into();
let merged_map = domain_map_left.merge(&domain_map_right);
assert_eq!(merged_map.get(&0), Some(&Bitvector::from_i64(0).into()));
assert_eq!(merged_map.get(&0), Some(&bitvec!("0:8").into()));
assert_eq!(
merged_map.get(&1),
Some(&BitvectorDomain::new_top(ByteSize::new(8)).into())
);
assert_eq!(merged_map.get(&2), Some(&Bitvector::from_i64(1).into()));
assert_eq!(merged_map.get(&2), Some(&bitvec!("1:8").into()));
assert_eq!(
merged_map.get(&5),
Some(&DataDomain::new_top(ByteSize::new(8)).into())
......@@ -273,7 +272,7 @@ mod tests {
let merged_map = domain_map_left.merge(&domain_map_right);
assert_eq!(
merged_map.get(&0).unwrap().get_absolute_value(),
Some(&Bitvector::from_i64(0).into())
Some(&bitvec!("0:8").into())
);
assert!(merged_map.get(&0).unwrap().contains_top());
assert_eq!(
......@@ -282,7 +281,7 @@ mod tests {
);
assert_eq!(
merged_map.get(&2).unwrap().get_absolute_value(),
Some(&Bitvector::from_i64(1).into())
Some(&bitvec!("1:8").into())
);
assert!(merged_map.get(&2).unwrap().contains_top());
assert_eq!(merged_map.get(&5), None);
......
......@@ -144,7 +144,7 @@ impl std::fmt::Display for AbstractIdentifier {
} else {
write!(formatter, "{}(", self.0.time)?;
for hint in &self.0.path_hints {
write!(formatter, "->{}", hint)?;
write!(formatter, "->{hint}",)?;
}
write!(formatter, ") @ {}", self.0.location)
}
......@@ -185,10 +185,10 @@ impl std::fmt::Display for AbstractLocation {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Register(var) => write!(formatter, "{}", var.name),
Self::GlobalAddress { address, size: _ } => write!(formatter, "0x{:x}", address),
Self::GlobalAddress { address, size: _ } => write!(formatter, "0x{address:x}"),
Self::Pointer(var, location) => write!(formatter, "{}->{}", var.name, location),
Self::GlobalPointer(address, location) => {
write!(formatter, "0x{:x}->{}", address, location)
write!(formatter, "0x{address:x}->{location}")
}
}
}
......@@ -275,8 +275,8 @@ impl AbstractMemoryLocation {
impl std::fmt::Display for AbstractMemoryLocation {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Location { offset, .. } => write!(formatter, "({})", offset),
Self::Pointer { offset, target } => write!(formatter, "({})->{}", offset, target),
Self::Location { offset, .. } => write!(formatter, "({offset})"),
Self::Pointer { offset, target } => write!(formatter, "({offset})->{target}"),
}
}
}
......@@ -284,6 +284,7 @@ impl std::fmt::Display for AbstractMemoryLocation {
#[cfg(test)]
pub mod tests {
use super::*;
use crate::variable;
impl AbstractIdentifier {
/// Mock an abstract identifier with the given TID name and pointing to the value in the given register name.
......@@ -294,7 +295,12 @@ pub mod tests {
) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new(tid.to_string()),
AbstractLocation::from_var(&Variable::mock(register, size_in_bytes)).unwrap(),
AbstractLocation::from_var(&variable!(format!(
"{}:{}",
register.to_string(),
size_in_bytes
)))
.unwrap(),
)
}
}
......@@ -311,7 +317,7 @@ pub mod tests {
// Test uniqueness of TIDs in path hint array.
let id = AbstractIdentifier::new(
Tid::new("time_id"),
AbstractLocation::from_var(&Variable::mock("var", 8)).unwrap(),
AbstractLocation::from_var(&variable!("var:8")).unwrap(),
);
let id = id.with_path_hint(Tid::new("first_hint")).unwrap();
let id = id.with_path_hint(Tid::new("second_hint")).unwrap();
......@@ -321,7 +327,7 @@ pub mod tests {
#[test]
fn test_bytesize() {
let location =
AbstractLocation::from_stack_position(&Variable::mock("RSP", 8), 10, ByteSize::new(4));
AbstractLocation::from_stack_position(&variable!("RSP:8"), 10, ByteSize::new(4));
let id = AbstractIdentifier::new(Tid::new("id"), location);
assert_eq!(id.bytesize(), ByteSize::new(4));
}
......
use crate::bitvec;
use super::*;
impl Interval {
pub fn mock(start: i64, end: i64) -> Interval {
Interval::new(Bitvector::from_i64(start), Bitvector::from_i64(end), 1)
Interval::new(
bitvec!(format!("{}:8", start)),
bitvec!(format!("{}:8", end)),
1,
)
}
pub fn mock_i8(start: i8, end: i8) -> Interval {
Interval::new(Bitvector::from_i8(start), Bitvector::from_i8(end), 1)
Interval::new(
bitvec!(format!("{}:1", start)),
bitvec!(format!("{}:1", end)),
1,
)
}
pub fn with_stride(mut self, stride: u64) -> Interval {
......@@ -92,7 +102,7 @@ fn subpiece_higher() {
let val = Interval::mock(3, 21).with_stride(6);
assert_eq!(
val.subpiece_higher(ByteSize::new(7)),
Interval::from(Bitvector::from_i8(0))
Interval::from(bitvec!("0:1"))
)
}
......@@ -117,8 +127,8 @@ fn piece() {
assert_eq!(
left.piece(&right),
Interval {
start: Bitvector::from_i16(256),
end: Bitvector::from_i16(1278),
start: bitvec!("256:2"),
end: bitvec!("1278:2"),
stride: 2,
}
);
......@@ -127,8 +137,8 @@ fn piece() {
assert_eq!(
left.piece(&right),
Interval {
start: Bitvector::from_i16(259),
end: Bitvector::from_i16(1039),
start: bitvec!("259:2"),
end: bitvec!("1039:2"),
stride: 2,
}
);
......@@ -145,11 +155,11 @@ fn add_and_sub() {
#[test]
fn contains() {
let interval = Interval::mock(2, 10).with_stride(4);
let elem = Bitvector::from_i64(4);
let elem = bitvec!("4:8");
assert!(!interval.contains(&elem));
let elem = Bitvector::from_i64(6);
let elem = bitvec!("6:8");
assert!(interval.contains(&elem));
let elem = Bitvector::from_i64(14);
let elem = bitvec!("14:8");
assert!(!interval.contains(&elem));
}
......
use super::{create_computation, mock_context, NodeValue};
use crate::def;
use crate::expr;
use crate::intermediate_representation::*;
use mock_context::Context;
use mock_context::StartEnd;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use mock_context::Context;
use mock_context::StartEnd;
fn mock_program() -> Term<Program> {
let var = Variable {
name: String::from("RAX"),
size: ByteSize::new(8),
is_temp: false,
};
let value = Expression::UnOp {
op: UnOpType::IntNegate,
arg: Box::new(Expression::Var(var.clone())),
};
let def_term1 = Term {
tid: Tid::new("def1".to_string()),
term: Def::Assign {
var: var.clone(),
value: value.clone(),
},
};
let def_term2 = Term {
tid: Tid::new("def2".to_string()),
term: Def::Assign {
var: var.clone(),
value: value.clone(),
},
};
let def_term3 = Term {
tid: Tid::new("def3".to_string()),
term: Def::Assign {
var: var.clone(),
value: value.clone(),
},
};
let def_term4 = Term {
tid: Tid::new("def4".to_string()),
term: Def::Assign {
var: var.clone(),
value: value.clone(),
},
};
let def_term5 = Term {
tid: Tid::new("def5".to_string()),
term: Def::Assign {
var: var.clone(),
value: value.clone(),
},
};
let def_term1 = def!["def1: RAX:8 = -(RAX:8)"];
let def_term2 = def!["def2: RAX:8 = -(RAX:8)"];
let def_term3 = def!["def3: RAX:8 = -(RAX:8)"];
let def_term4 = def!["def4: RAX:8 = -(RAX:8)"];
let def_term5 = def!["def5: RAX:8 = -(RAX:8)"];
let call_term = Term {
tid: Tid::new("call".to_string()),
term: Jmp::Call {
......@@ -61,7 +24,7 @@ fn mock_program() -> Term<Program> {
};
let return_term = Term {
tid: Tid::new("return".to_string()),
term: Jmp::Return(Expression::Const(Bitvector::zero(64.into()))), // The return term does not matter
term: Jmp::Return(expr!("0:8")), // The return term does not matter
};
let jmp = Jmp::Branch(Tid::new("sub1_blk1"));
let jmp_term = Term {
......@@ -94,7 +57,7 @@ fn mock_program() -> Term<Program> {
};
let cond_jump = Jmp::CBranch {
target: Tid::new("sub1_blk1"),
condition: Expression::Const(Bitvector::from_u8(0)),
condition: expr!("0:1"),
};
let cond_jump_term = Term {
tid: Tid::new("cond_jump"),
......
......@@ -127,25 +127,18 @@ pub fn remove_dead_var_assignments(project: &mut Project) {
#[cfg(test)]
mod tests {
use super::*;
fn def_assign_term(term_index: u64, input: &str, output: &str) -> Term<Def> {
Def::assign(
&format!("def_{}", term_index),
Variable::mock(output, 8),
Expression::Var(Variable::mock(input, 8)),
)
}
use crate::defs;
#[test]
fn dead_assignment_removal() {
let defs = vec![
def_assign_term(1, "A", "B"),
def_assign_term(2, "B", "C"),
def_assign_term(3, "C", "RAX"), // dead assignment
def_assign_term(4, "B", "RAX"),
def_assign_term(5, "C", "RBX"),
def_assign_term(6, "A", "B"), // dead assignment, since the next assignment is dead
def_assign_term(7, "B", "C"), // dead assignment, since C is not a physical register
let defs = defs![
"def_1: B:8 = A:8",
"def_2: C:8 = B:8",
"def_3: RAX:8 = C:8",
"def_4: RAX:8 = B:8",
"def_5: RBX:8 = C:8",
"def_6: B:8 = A:8",
"def_7: C:8 = B:8"
];
let block = Term {
tid: Tid::new("block"),
......@@ -167,11 +160,11 @@ mod tests {
project.program.term.subs.insert(sub.tid.clone(), sub);
remove_dead_var_assignments(&mut project);
let cleaned_defs = vec![
def_assign_term(1, "A", "B"),
def_assign_term(2, "B", "C"),
def_assign_term(4, "B", "RAX"),
def_assign_term(5, "C", "RBX"),
let cleaned_defs = defs![
"def_1: B:8 = A:8",
"def_2: C:8 = B:8",
"def_4: RAX:8 = B:8",
"def_5: RBX:8 = C:8"
];
assert_eq!(
&project.program.term.subs[&Tid::new("sub")].term.blocks[0]
......
use super::*;
use crate::intermediate_representation::{Def, Expression, Variable};
use crate::{defs, expr, intermediate_representation::Def, variable};
/// Creates a specific project containing three blocks for expression propagation tests.
///
......@@ -12,11 +12,7 @@ fn mock_project() -> Project {
let callee_block = Term {
tid: Tid::new("callee_block"),
term: Blk {
defs: vec![Def::assign(
"callee_def_1",
Variable::mock("Y", 8),
Expression::var("Z", 8),
)],
defs: defs!["callee_def_1: Y:8 = Z:8"],
jmps: Vec::new(),
indirect_jmp_targets: Vec::new(),
},
......@@ -34,17 +30,9 @@ fn mock_project() -> Project {
let entry_jmp_block = Term {
tid: Tid::new("entry_jmp_block"),
term: Blk {
defs: vec![
Def::assign(
"entry_jmp_def_1",
Variable::mock("X", 8),
Expression::var("Z", 8).un_op(UnOpType::BoolNegate),
),
Def::assign(
"entry_jmp_def_2",
Variable::mock("Z", 8),
Expression::var("Z", 8).un_op(UnOpType::IntNegate),
),
defs: defs![
"entry_jmp_def_1: X:8 = ¬(Z:8)",
"entry_jmp_def_2: Z:8 = -(Z:8)"
],
jmps: vec![Term {
tid: Tid::new("call_to_called_function"),
......@@ -92,37 +80,13 @@ fn get_mock_entry_block() -> Term<Blk> {
Term {
tid: Tid::new("entry_block"),
term: Blk {
defs: vec![
Def::assign(
"tid_1",
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_2",
Variable::mock("X", 8),
Expression::var("Y", 8).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_3",
Variable::mock("Y", 8),
Expression::var("X", 8).plus(Expression::var("Y", 8)),
),
Def::assign(
"tid_4",
Variable::mock("X", 8),
Expression::var("X", 8).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_5",
Variable::mock("Y", 8),
Expression::var("Y", 8).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_6",
Variable::mock("Y", 8),
Expression::var("X", 8).plus(Expression::var("Y", 8)),
),
defs: defs![
"tid_1: Z:8 = -(42:4)",
"tid_2: X:8 = -(Y:8)",
"tid_3: Y:8 = X:8 + Y:8",
"tid_4: X:8 = -(X:8)",
"tid_5: Y:8 = -(Y:8)",
"tid_6: Y:8 = X:8 + Y:8"
],
jmps: Vec::new(),
indirect_jmp_targets: Vec::new(),
......@@ -149,17 +113,13 @@ fn inter_block_propagation() {
vec![
Def::assign(
"entry_jmp_def_1",
Variable::mock("X", 8),
Expression::const_from_i32(42)
.un_op(UnOpType::IntNegate)
.un_op(UnOpType::BoolNegate),
variable!("X:8"),
expr!("-(42:4)").un_op(UnOpType::BoolNegate),
),
Def::assign(
"entry_jmp_def_2",
Variable::mock("Z", 8),
Expression::const_from_i32(42)
.un_op(UnOpType::IntNegate)
.un_op(UnOpType::IntNegate),
variable!("Z:8"),
expr!("-(42:4)").un_op(UnOpType::IntNegate),
)
]
)
......@@ -181,11 +141,7 @@ fn no_propagation_on_calls() {
.unwrap()
.term
.defs,
vec![Def::assign(
"callee_def_1",
Variable::mock("Y", 8),
Expression::var("Z", 8),
)]
defs!["callee_def_1: Y:8 = Z:8"]
)
}
#[test]
......@@ -214,10 +170,7 @@ fn insertion_table_update() {
// Assignment is inserted into table, no other changes.
assert_eq!(
update.clone().unwrap(),
HashMap::from([(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
)])
HashMap::from([(variable!("Z:8"), expr!("-(42:4)"))])
);
let update = crate::analysis::forward_interprocedural_fixpoint::Context::update_def(
......@@ -229,14 +182,8 @@ fn insertion_table_update() {
assert_eq!(
update.clone().unwrap(),
HashMap::from([
(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
),
(
Variable::mock("X", 8),
Expression::var("Y", 8).un_op(UnOpType::IntNegate)
)
(variable!("Z:8"), expr!("-(42:4)")),
(variable!("X:8"), expr!("-(Y:8)"))
])
);
......@@ -248,10 +195,7 @@ fn insertion_table_update() {
// Expression for X is removed and Assignment is not inserted.
assert_eq!(
update.clone().unwrap(),
HashMap::from([(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
),])
HashMap::from([(variable!("Z:8"), expr!("-(42:4)")),])
);
let update = crate::analysis::forward_interprocedural_fixpoint::Context::update_def(
&context,
......@@ -261,10 +205,7 @@ fn insertion_table_update() {
// Expression for Y is removed and Assignment is not inserted.
assert_eq!(
update.clone().unwrap(),
HashMap::from([(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
),])
HashMap::from([(variable!("Z:8"), expr!("-(42:4)")),])
);
let update = crate::analysis::forward_interprocedural_fixpoint::Context::update_def(
......@@ -275,10 +216,7 @@ fn insertion_table_update() {
// Assignment not inserted.
assert_eq!(
update.clone().unwrap(),
HashMap::from([(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
),])
HashMap::from([(variable!("Z:8"), expr!("-(42:4)")),])
);
let update = crate::analysis::forward_interprocedural_fixpoint::Context::update_def(
......@@ -289,10 +227,7 @@ fn insertion_table_update() {
// Assignment not inserted.
assert_eq!(
update.clone().unwrap(),
HashMap::from([(
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate)
),])
HashMap::from([(variable!("Z:8"), expr!("-(42:4)")),])
);
}
#[test]
......@@ -300,35 +235,12 @@ fn insertion_table_update() {
fn expressions_inserted() {
let mut project = mock_project();
propagate_input_expression(&mut project);
let result_def_entry_block = vec![
Def::assign(
"tid_1",
Variable::mock("Z", 8),
Expression::const_from_i32(42).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_2",
Variable::mock("X", 8),
Expression::var("Y", 8).un_op(UnOpType::IntNegate),
),
Def::assign(
"tid_3",
Variable::mock("Y", 8),
Expression::var("Y", 8)
.un_op(UnOpType::IntNegate)
.plus(Expression::var("Y", 8)),
),
Def::assign(
"tid_4",
Variable::mock("X", 8),
Expression::var("X", 8).un_op(UnOpType::IntNegate),
),
// tid_5 is removed by merge_def_assignments_to_same_var()
Def::assign(
"tid_6",
Variable::mock("Y", 8),
Expression::var("X", 8).plus(Expression::var("Y", 8).un_op(UnOpType::IntNegate)),
),
let result_def_entry_block = defs![
"tid_1: Z:8 = -(42:4)",
"tid_2: X:8 = -(Y:8)",
"tid_3: Y:8 = -(Y:8) + Y:8",
"tid_4: X:8 = -(X:8)",
"tid_6: Y:8 = X:8 + -(Y:8)"
];
assert_eq!(
project
......@@ -357,17 +269,13 @@ fn expressions_inserted() {
vec![
Def::assign(
"entry_jmp_def_1",
Variable::mock("X", 8),
Expression::const_from_i32(42)
.un_op(UnOpType::IntNegate)
.un_op(UnOpType::BoolNegate),
variable!("X:8"),
expr!("-(42:4)").un_op(UnOpType::BoolNegate),
),
Def::assign(
"entry_jmp_def_2",
Variable::mock("Z", 8),
Expression::const_from_i32(42)
.un_op(UnOpType::IntNegate)
.un_op(UnOpType::IntNegate)
variable!("Z:8"),
expr!("-(42:4)").un_op(UnOpType::IntNegate)
)
]
);
......@@ -382,10 +290,6 @@ fn expressions_inserted() {
.blocks[0]
.term
.defs,
vec![Def::assign(
"callee_def_1",
Variable::mock("Y", 8),
Expression::var("Z", 8),
)]
defs!["callee_def_1: Y:8 = Z:8"]
);
}
use super::*;
use crate::{bitvec, variable};
use std::collections::HashSet;
#[test]
......@@ -25,20 +26,20 @@ fn test_compute_return_values_of_call() {
&call,
);
let expected_val = DataDomain::from_target(
AbstractIdentifier::from_var(Tid::new("call_tid"), &Variable::mock("RAX", 8)),
Bitvector::from_i64(0).into(),
AbstractIdentifier::from_var(Tid::new("call_tid"), &variable!("RAX:8")),
bitvec!("0x0:8").into(),
);
assert_eq!(return_values.iter().len(), 3);
assert_eq!(return_values[0], (&Variable::mock("RAX", 8), expected_val));
assert_eq!(return_values[0], (&variable!("RAX:8"), expected_val));
// Test returning a known value.
let param_ref = DataDomain::from_target(
AbstractIdentifier::from_var(Tid::new("callee"), &Variable::mock("RDI", 8)),
Bitvector::from_i64(0).into(),
AbstractIdentifier::from_var(Tid::new("callee"), &variable!("RDI:8")),
bitvec!("0x0:8").into(),
);
callee_state.set_register(&Variable::mock("RAX", 8), param_ref);
callee_state.set_register(&variable!("RAX:8"), param_ref);
let expected_val = DataDomain::from_target(
AbstractIdentifier::from_var(Tid::new("caller"), &Variable::mock("RDI", 8)),
Bitvector::from_i64(0).into(),
AbstractIdentifier::from_var(Tid::new("caller"), &variable!("RDI:8")),
bitvec!("0x0:8").into(),
);
let return_values = context.compute_return_values_of_call(
&mut caller_state,
......@@ -47,7 +48,7 @@ fn test_compute_return_values_of_call() {
&call,
);
assert_eq!(return_values.iter().len(), 3);
assert_eq!(return_values[0], (&Variable::mock("RAX", 8), expected_val));
assert_eq!(return_values[0], (&variable!("RAX:8"), expected_val));
}
#[test]
......@@ -69,17 +70,17 @@ fn test_call_stub_handling() {
assert_eq!(
state.get_params_of_current_function(),
vec![(
Arg::from_var(Variable::mock("r0", 4), None),
Arg::from_var(variable!("r0:4"), None),
AccessPattern::new().with_read_flag()
)]
);
assert_eq!(
state.get_register(&Variable::mock("r0", 4)),
state.get_register(&variable!("r0:4")),
DataDomain::from_target(
AbstractIdentifier::mock(call_tid, "r0", 4),
Bitvector::from_i32(0).into()
bitvec!("0x0:4").into()
)
.merge(&Bitvector::zero(ByteSize::new(4).into()).into())
.merge(&bitvec!("0x0:4").into())
);
// Test handling of sprintf call
......@@ -89,7 +90,7 @@ fn test_call_stub_handling() {
project.get_standard_calling_convention().unwrap(),
);
// Set the format string param register to a pointer to the string 'cat %s %s %s %s'.
state.set_register(&Variable::mock("r1", 4), Bitvector::from_i32(0x6000).into());
state.set_register(&variable!("r1:4"), bitvec!("0x6000:4").into());
let extern_symbol = ExternSymbol::mock_sprintf_symbol_arm();
let call_tid = Tid::new("call_sprintf");
context.handle_extern_symbol_call(&mut state, &extern_symbol, &call_tid);
......@@ -97,14 +98,14 @@ fn test_call_stub_handling() {
assert_eq!(
params[0],
(
Arg::from_var(Variable::mock("r0", 4), None),
Arg::from_var(variable!("r0:4"), None),
AccessPattern::new_unknown_access()
)
);
assert_eq!(
params[1],
(
Arg::from_var(Variable::mock("r2", 4), None),
Arg::from_var(variable!("r2:4"), None),
AccessPattern::new()
.with_read_flag()
.with_dereference_flag()
......@@ -121,15 +122,15 @@ fn test_get_global_mem_address() {
let context = Context::new(&project, &graph);
// Check global address from abstract ID
let global_address_id: DataDomain<BitvectorDomain> = DataDomain::from_target(
AbstractIdentifier::from_global_address(&Tid::new("fn_tid"), &Bitvector::from_i32(0x2000)),
Bitvector::from_i32(0x2).into(),
AbstractIdentifier::from_global_address(&Tid::new("fn_tid"), &bitvec!("0x2000:4")),
bitvec!("0x2:4").into(),
);
let result = context.get_global_mem_address(&global_address_id);
assert_eq!(result, Some(Bitvector::from_i32(0x2002)));
assert_eq!(result, Some(bitvec!("0x2002:4")));
// Check global address from absolute value
let global_address_const = Bitvector::from_i32(0x2003).into();
let global_address_const = bitvec!("0x2003:4").into();
let result = context.get_global_mem_address(&global_address_const);
assert_eq!(result, Some(Bitvector::from_i32(0x2003)));
assert_eq!(result, Some(bitvec!("0x2003:4")));
// Check global address not returned if it may not be unique
let value = global_address_id.merge(&global_address_const);
let result = context.get_global_mem_address(&value);
......
......@@ -277,6 +277,7 @@ impl Default for FunctionSignature {
#[cfg(test)]
pub mod tests {
use super::*;
use crate::variable;
impl FunctionSignature {
/// Create a mock x64 function signature with 2 parameters, one of which is accessed mutably,
......@@ -287,11 +288,11 @@ pub mod tests {
write_access_pattern.set_unknown_access_flags();
let parameters = HashMap::from_iter([
(
Arg::from_var(Variable::mock("RDI", 8), None),
Arg::from_var(variable!("RDI:8"), None),
AccessPattern::new(),
),
(
Arg::from_var(Variable::mock("RSI", 8), None),
Arg::from_var(variable!("RSI:8"), None),
write_access_pattern,
),
]);
......
......@@ -444,7 +444,7 @@ impl State {
let regs = self
.register
.iter()
.map(|(var, value)| (format!("{}", var), value.to_json_compact()))
.map(|(var, value)| (format!("{var}"), value.to_json_compact()))
.collect();
json_map.insert("Register".to_string(), serde_json::Value::Object(regs));
let access_patterns = self
......@@ -452,8 +452,8 @@ impl State {
.iter()
.map(|(id, pattern)| {
(
format!("{}", id),
serde_json::Value::String(format!("{}", pattern)),
format!("{id}"),
serde_json::Value::String(format!("{pattern}")),
)
})
.collect();
......
use super::*;
use crate::{bitvec, expr, variable};
impl State {
/// Generate a mock state for an ARM-32 state.
pub fn mock_arm32() -> State {
State::new(
&Tid::new("mock_fn"),
&Variable::mock("sp", 4),
&variable!("sp:4"),
&CallingConvention::mock_arm32(),
)
}
......@@ -14,7 +15,7 @@ impl State {
pub fn mock_x64(tid_name: &str) -> State {
State::new(
&Tid::new(tid_name),
&Variable::mock("RSP", 8),
&variable!("RSP:8"),
&CallingConvention::mock_x64(),
)
}
......@@ -22,7 +23,7 @@ impl State {
/// Mock an abstract ID representing the stack.
fn mock_stack_id() -> AbstractIdentifier {
AbstractIdentifier::from_var(Tid::new("mock_fn"), &Variable::mock("sp", 4))
AbstractIdentifier::from_var(Tid::new("mock_fn"), &variable!("sp:4"))
}
/// Mock an abstract ID of a stack parameter
......@@ -46,11 +47,8 @@ fn test_new() {
// Assert that the register values are as expected
assert_eq!(state.register.len(), 7); // 6 parameter register plus stack pointer
assert_eq!(
state.get_register(&Variable::mock("sp", 4)),
DataDomain::from_target(
mock_stack_id(),
Bitvector::zero(ByteSize::new(4).into()).into()
)
state.get_register(&variable!("sp:4")),
DataDomain::from_target(mock_stack_id(), bitvec!("0x0:4").into())
);
// Check the generated tracked IDs
assert_eq!(state.tracked_ids.len(), 6);
......@@ -59,7 +57,7 @@ fn test_new() {
state.get_register(id.unwrap_register()),
DataDomain::from_target(
id.clone(),
Bitvector::zero(id.unwrap_register().size.into()).into()
bitvec!(format!("0:{}", id.unwrap_register().size)).into()
)
);
assert_eq!(access_pattern, &AccessPattern::new());
......@@ -69,21 +67,20 @@ fn test_new() {
#[test]
fn test_store_and_load_from_stack() {
let mut state = State::mock_arm32();
let address = DataDomain::from_target(mock_stack_id(), Bitvector::from_i32(-4).into());
let value: DataDomain<BitvectorDomain> = Bitvector::from_i32(0).into();
let address = DataDomain::from_target(mock_stack_id(), bitvec!("-4:4").into());
let value: DataDomain<BitvectorDomain> = bitvec!("0x0:4").into();
// write and load a value to the current stack frame
state.write_value(address.clone(), value.clone());
assert_eq!(state.stack.iter().len(), 1);
assert_eq!(
state.stack.get(Bitvector::from_i32(-4), ByteSize::new(4)),
state.stack.get(bitvec!("-4:4"), ByteSize::new(4)),
value.clone()
);
assert_eq!(state.load_value(address, ByteSize::new(4), None), value);
// Load a parameter register and check that the parameter gets generated
let address = DataDomain::from_target(mock_stack_id(), Bitvector::from_i32(4).into());
let address = DataDomain::from_target(mock_stack_id(), bitvec!("0x4:4").into());
let stack_param_id = mock_stack_param_id(4, 4);
let stack_param =
DataDomain::from_target(stack_param_id.clone(), Bitvector::from_i32(0).into());
let stack_param = DataDomain::from_target(stack_param_id.clone(), bitvec!("0x0:4").into());
assert_eq!(state.tracked_ids.iter().len(), 6);
assert_eq!(
state.load_value(address.clone(), ByteSize::new(4), None),
......@@ -104,22 +101,21 @@ fn test_store_and_load_from_stack() {
fn test_load_unsized_from_stack() {
let mut state = State::mock_arm32();
// Load an existing stack param (generated by a sized load at the same address)
let address = DataDomain::from_target(mock_stack_id(), Bitvector::from_i32(0).into());
let address = DataDomain::from_target(mock_stack_id(), bitvec!("0x0:4").into());
let stack_param_id = mock_stack_param_id(0, 4);
let stack_param =
DataDomain::from_target(stack_param_id.clone(), Bitvector::from_i32(0).into());
let stack_param = DataDomain::from_target(stack_param_id.clone(), bitvec!("0x0:4").into());
state.load_value(address, ByteSize::new(4), None);
let unsized_load = state.load_unsized_value_from_stack(Bitvector::from_i32(0));
let unsized_load = state.load_unsized_value_from_stack(bitvec!("0x0:4").into());
assert_eq!(unsized_load, stack_param);
assert!(state.tracked_ids.get(&stack_param_id).is_some());
// Load a non-existing stack param
let stack_param_id = mock_stack_param_id(4, 1);
let stack_param = DataDomain::from_target(stack_param_id.clone(), Bitvector::from_i8(0).into());
let unsized_load = state.load_unsized_value_from_stack(Bitvector::from_i32(4));
let stack_param = DataDomain::from_target(stack_param_id.clone(), bitvec!("0x0:1").into());
let unsized_load = state.load_unsized_value_from_stack(bitvec!("0x4:4"));
assert_eq!(unsized_load, stack_param);
assert!(state.tracked_ids.get(&stack_param_id).is_some());
// Unsized load from the current stack frame
let unsized_load = state.load_unsized_value_from_stack(Bitvector::from_i32(-4));
let unsized_load = state.load_unsized_value_from_stack(bitvec!("-4:4"));
assert_eq!(unsized_load, DataDomain::new_top(ByteSize::new(1)));
}
......@@ -127,16 +123,16 @@ fn test_load_unsized_from_stack() {
fn test_eval() {
let mut state = State::mock_arm32();
// Test the eval method
let expr = Expression::Var(Variable::mock("sp", 4)).plus_const(42);
let expr = expr!("sp:4 + 42:4");
assert_eq!(
state.eval(&expr),
DataDomain::from_target(mock_stack_id(), Bitvector::from_i32(42).into())
DataDomain::from_target(mock_stack_id(), bitvec!("42:4").into())
);
// Test the eval_parameter_arg method
let arg = Arg::from_var(Variable::mock("sp", 4), None);
let arg = Arg::from_var(variable!("sp:4"), None);
assert_eq!(
state.eval_parameter_arg(&arg),
DataDomain::from_target(mock_stack_id(), Bitvector::from_i32(0).into())
DataDomain::from_target(mock_stack_id(), bitvec!("0x0:4").into())
);
}
......@@ -146,9 +142,8 @@ fn test_extern_symbol_handling() {
let extern_symbol = ExternSymbol::mock_arm32("mock_symbol");
let cconv = CallingConvention::mock_arm32();
let call_tid = Tid::new("call_tid");
let param_id = AbstractIdentifier::from_var(Tid::new("mock_fn"), &Variable::mock("r0", 4));
let return_val_id =
AbstractIdentifier::from_var(Tid::new("call_tid"), &Variable::mock("r0", 4));
let param_id = AbstractIdentifier::from_var(Tid::new("mock_fn"), &variable!("r0:4"));
let return_val_id = AbstractIdentifier::from_var(Tid::new("call_tid"), &variable!("r0:4"));
// Test extern symbol handling.
state.handle_generic_extern_symbol(
&call_tid,
......@@ -164,7 +159,7 @@ fn test_extern_symbol_handling() {
.is_mutably_dereferenced(),
true
);
let return_val = state.get_register(&Variable::mock("r0", 4));
let return_val = state.get_register(&variable!("r0:4"));
assert_eq!(return_val.get_relative_values().iter().len(), 2);
assert_eq!(
return_val.get_relative_values().get(&param_id).unwrap(),
......@@ -179,7 +174,7 @@ fn test_extern_symbol_handling() {
.get_relative_values()
.get(&return_val_id)
.unwrap(),
&Bitvector::from_i32(0).into()
&bitvec!("0:4").into()
);
}
......@@ -189,16 +184,16 @@ fn test_substitute_global_mem_address() {
let global_memory = RuntimeMemoryImage::mock();
// Test that addresses into non-writeable memory do not get substituted.
let global_address: DataDomain<BitvectorDomain> = Bitvector::from_i32(0x1000).into();
let global_address: DataDomain<BitvectorDomain> = bitvec!("0x1000:4").into();
let substituted_address =
state.substitute_global_mem_address(global_address.clone(), &global_memory);
assert_eq!(global_address, substituted_address);
// Test substitution for addresses into writeable global memory.
let global_address: DataDomain<BitvectorDomain> = Bitvector::from_i32(0x2000).into();
let global_address: DataDomain<BitvectorDomain> = bitvec!("0x2000:4").into();
let substituted_address = state.substitute_global_mem_address(global_address, &global_memory);
let expected_global_id = AbstractIdentifier::from_global_address(
state.get_current_function_tid(),
&Bitvector::from_i32(0x2000),
&bitvec!("0x2000:4"),
);
assert_eq!(
state.tracked_ids.get(&expected_global_id),
......@@ -206,6 +201,6 @@ fn test_substitute_global_mem_address() {
);
assert_eq!(
substituted_address,
DataDomain::from_target(expected_global_id, Bitvector::from_i32(0).into())
DataDomain::from_target(expected_global_id, bitvec!("0x0:4").into())
);
}
......@@ -89,7 +89,7 @@ impl<'a> Context<'a> {
pub fn log_debug(&self, result: Result<(), Error>, location: Option<&Tid>) {
if let Err(err) = result {
let mut log_message =
LogMessage::new_debug(format!("{}", err)).source("Pointer Inference");
LogMessage::new_debug(format!("{err}")).source("Pointer Inference");
if let Some(loc) = location {
log_message = log_message.location(loc.clone());
};
......@@ -286,7 +286,7 @@ impl<'a> Context<'a> {
name: "CWE476".to_string(),
version: VERSION.to_string(),
addresses: vec![tid.address.clone()],
tids: vec![format!("{}", tid)],
tids: vec![format!("{tid}")],
symbols: Vec::new(),
other: Vec::new(),
description: format!(
......
......@@ -157,8 +157,7 @@ impl<'a> PointerInference<'a> {
if !self.computation.has_stabilized() {
let worklist_size = self.computation.get_worklist().len();
self.log_info(format!(
"Fixpoint did not stabilize. Remaining worklist size: {}",
worklist_size,
"Fixpoint did not stabilize. Remaining worklist size: {worklist_size}"
));
}
if print_stats {
......@@ -172,11 +171,10 @@ impl<'a> PointerInference<'a> {
for (node_index, value) in self.computation.node_values().iter() {
let node = graph.node_weight(*node_index).unwrap();
if let Ok(string) = serde_yaml::to_string(&(node, value)) {
println!("{}", string);
println!("{string}");
} else {
println!(
"Serializing failed at {:?} with {:?}",
node_index,
"Serializing failed at {node_index:?} with {:?}",
serde_yaml::to_string(value)
);
}
......@@ -192,7 +190,7 @@ impl<'a> PointerInference<'a> {
for (node_index, node_value) in self.computation.node_values().iter() {
let node = graph.node_weight(*node_index).unwrap();
if let NodeValue::Value(value) = node_value {
json_nodes.insert(format!("{}", node), value.to_json_compact());
json_nodes.insert(format!("{node}"), value.to_json_compact());
}
}
serde_json::Value::Object(json_nodes)
......@@ -237,8 +235,7 @@ impl<'a> PointerInference<'a> {
}
}
self.log_info(format!(
"Blocks with state: {} / {}",
stateful_blocks, all_blocks
"Blocks with state: {stateful_blocks} / {all_blocks}"
));
}
......
......@@ -216,7 +216,7 @@ impl AbstractObject {
.inner
.memory
.iter()
.map(|(index, value)| (format!("{}", index), value.to_json_compact()));
.map(|(index, value)| (format!("{index}"), value.to_json_compact()));
elements.push((
"memory".to_string(),
serde_json::Value::Object(memory.collect()),
......
......@@ -174,7 +174,7 @@ impl AbstractObjectList {
use serde_json::*;
let mut object_map = Map::new();
for (id, object) in self.objects.iter() {
object_map.insert(format!("{}", id), object.to_json_compact());
object_map.insert(format!("{id}"), object.to_json_compact());
}
Value::Object(object_map)
}
......
......@@ -7,12 +7,11 @@ use crate::{
analysis::pointer_inference::PointerInference as PointerInferenceComputation,
analysis::{
forward_interprocedural_fixpoint::Context,
string_abstraction::{
context::symbol_calls::tests::Setup,
tests::mock_project_with_intraprocedural_control_flow, tests::Setup as ProjectSetup,
},
string_abstraction::{context::symbol_calls::tests::Setup, tests::*},
},
intermediate_representation::{Bitvector, Blk, ByteSize, ExternSymbol, Jmp, Tid, Variable},
bitvec, def,
intermediate_representation::*,
variable,
};
#[test]
......@@ -28,29 +27,28 @@ fn test_update_def() {
let mut setup: Setup<CharacterInclusionDomain> = Setup::new(&pi_results);
setup.context.block_first_def_set = HashSet::new();
let project_setup = ProjectSetup::new();
let assign_def = project_setup.string_input_constant("assign_def", "r1", 0x7000);
let load_def = project_setup.load_var_content_from_temp_var("load_def", "r5", "r2");
let store_def = project_setup.store_var_content_at_temp_var("store_def", "r0", "r5");
let assign_def = def!["assign_def: r1:4 = 0x7000:4"];
let load_def = load_var_content_from_temp_var("load_def", "r5", "r2");
let store_def = store_var_content_at_temp_var("store_def", "r0", "r5");
let new_state = setup
.context
.update_def(&setup.state_before_call, &assign_def)
.unwrap();
let absolute_target = DataDomain::from(Bitvector::from_i32(0x7000));
let absolute_target = DataDomain::from(bitvec!("0x7000:4"));
assert_eq!(
absolute_target,
*new_state
.get_variable_to_pointer_map()
.get(&Variable::mock("r1", 4))
.get(&variable!("r1:4"))
.unwrap()
);
let stack_id = AbstractIdentifier::new(
Tid::new("func"),
AbstractLocation::from_var(&Variable::mock("sp", 4)).unwrap(),
AbstractLocation::from_var(&variable!("sp:4")).unwrap(),
);
let loaded_pointer = DataDomain::from_target(stack_id.clone(), IntervalDomain::mock_i32(4, 4));
......@@ -64,7 +62,7 @@ fn test_update_def() {
);
let r2_reg = Variable {
name: String::from("r2"),
name: "r2".into(),
size: ByteSize::new(4),
is_temp: true,
};
......@@ -79,7 +77,7 @@ fn test_update_def() {
setup
.state_before_call
.add_new_variable_to_pointer_entry(Variable::mock("r3", 4), loaded_pointer.clone());
.add_new_variable_to_pointer_entry(variable!("r3:4"), loaded_pointer.clone());
let new_state = setup
.context
......@@ -90,14 +88,14 @@ fn test_update_def() {
loaded_pointer,
*new_state
.get_variable_to_pointer_map()
.get(&Variable::mock("r5", 4))
.get(&variable!("r5:4"))
.unwrap()
);
let store_target = DataDomain::from_target(stack_id, IntervalDomain::mock_i32(12, 12));
let r0_reg = Variable {
name: String::from("r0"),
name: "r0".into(),
size: ByteSize::new(4),
is_temp: true,
};
......@@ -108,7 +106,7 @@ fn test_update_def() {
setup
.pi_state_before_symbol_call
.set_register(&Variable::mock("r5", 4), absolute_target.clone());
.set_register(&variable!("r5:4"), absolute_target.clone());
setup
.state_before_call
......@@ -165,9 +163,9 @@ fn test_update_return() {
let mut setup: Setup<CharacterInclusionDomain> = Setup::new(&pi_results);
let pointer = DataDomain::from(Bitvector::from_i32(0x6000));
let callee_saved_reg = Variable::mock("r11", 4);
let non_callee_saved_reg = Variable::mock("r0", 4);
let pointer = DataDomain::from(bitvec!("0x6000:4"));
let callee_saved_reg = variable!("r11:4");
let non_callee_saved_reg = variable!("r0:4");
setup
.state_before_call
......
......@@ -171,6 +171,7 @@ impl<'a> Context<'a> {
pub mod tests {
use super::*;
use crate::analysis::pointer_inference::Data;
use crate::{bitvec, intermediate_representation::parsing};
use std::collections::{HashMap, HashSet};
#[test]
......@@ -183,9 +184,8 @@ pub mod tests {
let malloc_call_id = AbstractIdentifier::mock("malloc_call", "RAX", 8);
let main_stack_id = AbstractIdentifier::mock("main", "RSP", 8);
let param_value = Data::from_target(malloc_call_id.clone(), Bitvector::from_i64(2).into());
let param_value_2 =
Data::from_target(main_stack_id.clone(), Bitvector::from_i64(-10).into());
let param_value = Data::from_target(malloc_call_id.clone(), bitvec!("2:8").into());
let param_value_2 = Data::from_target(main_stack_id.clone(), bitvec!("-10:8").into());
let param_replacement_map = HashMap::from([
(callsite_id, param_value.clone()),
(callsite_id_2, param_value_2.clone()),
......@@ -196,7 +196,7 @@ pub mod tests {
context.callee_to_callsites_map = callee_to_callsites_map;
context
.malloc_tid_to_object_size_map
.insert(Tid::new("malloc_call"), Data::from(Bitvector::from_i64(42)));
.insert(Tid::new("malloc_call"), Data::from(bitvec!("42:8")));
context.call_to_caller_fn_map = HashMap::from([
(Tid::new("malloc_call"), Tid::new("main")),
(Tid::new("callsite_id"), Tid::new("main")),
......
......@@ -166,7 +166,7 @@ impl<'a> Context<'a> {
};
let mut cwe_warning =
CweWarning::new("CWE119", super::CWE_MODULE.version, description);
cwe_warning.tids = vec![format!("{}", call_tid)];
cwe_warning.tids = vec![format!("{call_tid}")];
cwe_warning.addresses = vec![call_tid.address.to_string()];
cwe_warning.other = vec![warnings];
self.log_collector.send(cwe_warning.into()).unwrap();
......
......@@ -218,6 +218,7 @@ fn add_param_replacements_for_call(
#[cfg(test)]
pub mod tests {
use super::*;
use crate::bitvec;
#[test]
fn test_substitute_param_values_context_sensitive() {
......@@ -228,9 +229,8 @@ pub mod tests {
let recursive_param_id = AbstractIdentifier::mock("main", "RSI", 8);
let recursive_callsite_id = AbstractIdentifier::mock("recursive_callsite_id", "RSI", 8);
let param_value =
Data::from_target(recursive_param_id.clone(), Bitvector::from_i64(1).into());
let recursive_param_value = Data::from(Bitvector::from_i64(41));
let param_value = Data::from_target(recursive_param_id.clone(), bitvec!("1:8").into());
let recursive_param_value = Data::from(bitvec!("41:8"));
let param_replacement_map = HashMap::from([
(callsite_id, param_value.clone()),
(recursive_callsite_id.clone(), recursive_param_value),
......@@ -254,7 +254,7 @@ pub mod tests {
context.call_to_caller_fn_map = call_to_caller_map;
// non-recursive substitution
let result = context.substitute_param_values_context_sensitive(
&Data::from_target(param_id.clone(), Bitvector::from_i64(5).into()),
&Data::from_target(param_id.clone(), bitvec!("5:8").into()),
&Tid::new("callsite_id"),
&Tid::new("func"),
);
......@@ -264,12 +264,12 @@ pub mod tests {
);
// recursive substitution
let result = context.recursively_substitute_param_values_context_sensitive(
&Data::from_target(param_id, Bitvector::from_i64(5).into()),
&Data::from_target(param_id, bitvec!("5:8").into()),
&Tid::new("func"),
&[Tid::new("callsite_id"), Tid::new("recursive_callsite_id")],
);
println!("{:#}", result.to_json_compact());
assert_eq!(result, Bitvector::from_i64(47).into());
assert_eq!(result, bitvec!("47:8").into());
}
#[test]
......@@ -281,9 +281,8 @@ pub mod tests {
let recursive_param_id = AbstractIdentifier::mock("main", "RSI", 8);
let recursive_callsite_id = AbstractIdentifier::mock("recursive_callsite_id", "RSI", 8);
let param_value =
Data::from_target(recursive_param_id.clone(), Bitvector::from_i64(1).into());
let recursive_param_value = Data::from(Bitvector::from_i64(39));
let param_value = Data::from_target(recursive_param_id.clone(), bitvec!("1:8").into());
let recursive_param_value = Data::from(bitvec!("39:8"));
let param_replacement_map = HashMap::from([
(callsite_id, param_value.clone()),
(recursive_callsite_id.clone(), recursive_param_value),
......@@ -304,8 +303,8 @@ pub mod tests {
// recursive substitution
let result = context.recursively_substitute_param_values(&Data::from_target(
param_id,
Bitvector::from_i64(5).into(),
bitvec!("5:8").into(),
));
assert_eq!(result, Bitvector::from_i64(45).into());
assert_eq!(result, bitvec!("45:8").into());
}
}
use super::*;
use crate::{bitvec, variable};
use std::collections::BTreeSet;
impl<'a> Context<'a> {
......@@ -28,9 +29,8 @@ fn test_compute_size_value_of_malloc_like_call() {
use crate::analysis::pointer_inference::State as PiState;
let project = Project::mock_x64();
let mut pi_results = PointerInference::mock(&project);
let mut malloc_state =
PiState::new(&Variable::mock("RSP", 8), Tid::new("func"), BTreeSet::new());
malloc_state.set_register(&Variable::mock("RDI", 8), Bitvector::from_i64(3).into());
let mut malloc_state = PiState::new(&variable!("RSP:8"), Tid::new("func"), BTreeSet::new());
malloc_state.set_register(&variable!("RDI:8"), bitvec!("3:8").into());
*pi_results.get_mut_states_at_tids() = HashMap::from([(Tid::new("malloc_call"), malloc_state)]);
let malloc_symbol = ExternSymbol::mock_x64("malloc");
......@@ -41,7 +41,7 @@ fn test_compute_size_value_of_malloc_like_call() {
&pi_results
)
.unwrap(),
Bitvector::from_i64(3).into()
bitvec!("3:8").into()
);
assert!(compute_size_value_of_malloc_like_call(
&Tid::new("other"),
......
......@@ -73,11 +73,7 @@ impl State {
if let Ok((lower_offset, upper_offset)) = offset.try_to_offset_interval() {
if let Ok(lower_bound) = self.object_lower_bounds.get(id).unwrap().try_to_offset() {
if lower_bound > lower_offset {
out_of_bounds_access_warnings.push(format!("For the object ID {} access to the offset {} may be smaller than the lower object bound of {}.",
id,
lower_offset,
lower_bound,
));
out_of_bounds_access_warnings.push(format!("For the object ID {id} access to the offset {lower_offset} may be smaller than the lower object bound of {lower_bound}."));
if let (
Some(BoundsMetadata {
source: Some(source),
......@@ -93,7 +89,7 @@ impl State {
context,
);
out_of_bounds_access_warnings
.push(format!("Relevant callgraph TIDs: [{}]", call_sequence_tids));
.push(format!("Relevant callgraph TIDs: [{call_sequence_tids}]"));
} else {
out_of_bounds_access_warnings.push(format!(
"Relevant callgraph TIDs: [{}]",
......@@ -128,7 +124,7 @@ impl State {
context,
);
out_of_bounds_access_warnings
.push(format!("Relevant callgraph TIDs: [{}]", call_sequence_tids));
.push(format!("Relevant callgraph TIDs: [{call_sequence_tids}]"));
} else {
out_of_bounds_access_warnings.push(format!(
"Relevant callgraph TIDs: [{}]",
......@@ -204,13 +200,13 @@ impl State {
let lower_bounds: Vec<_> = self
.object_lower_bounds
.iter()
.map(|(id, bound)| Value::String(format!("{}: {}", id, bound)))
.map(|(id, bound)| Value::String(format!("{id}: {bound}")))
.collect();
state_map.insert("lower_bounds".to_string(), Value::Array(lower_bounds));
let upper_bounds: Vec<_> = self
.object_upper_bounds
.iter()
.map(|(id, bound)| Value::String(format!("{}: {}", id, bound)))
.map(|(id, bound)| Value::String(format!("{id}: {bound}")))
.collect();
state_map.insert("upper_bounds".to_string(), Value::Array(upper_bounds));
......@@ -265,8 +261,8 @@ fn collect_tids_for_cwe_warning(
}
// Build a string out of the TID list
tids.iter()
.map(|tid| format!("{}", tid))
.reduce(|accum, elem| format!("{}, {}", accum, elem))
.map(|tid| format!("{tid}"))
.reduce(|accum, elem| format!("{accum}, {elem}"))
.unwrap()
}
......
......@@ -169,7 +169,7 @@ fn generate_cwe_warning(
_ => panic!("Invalid String Location."),
};
CweWarning::new(CWE_MODULE.name, CWE_MODULE.version, description)
.tids(vec![format!("{}", callsite)])
.tids(vec![format!("{callsite}")])
.addresses(vec![callsite.address.clone()])
.symbols(vec![called_symbol.name.clone()])
}
......@@ -179,7 +179,7 @@ pub mod tests {
use std::collections::HashSet;
use crate::analysis::pointer_inference::PointerInference as PointerInferenceComputation;
use crate::intermediate_representation::*;
use crate::{defs, intermediate_representation::*};
use super::*;
......@@ -189,21 +189,10 @@ pub mod tests {
let mut block1 = Blk::mock_with_tid("block1");
let block2 = Blk::mock_with_tid("block2");
let def1 = Def::assign(
"def2",
Variable::mock("RDI", 8 as u64),
Expression::var("RBP", 8).plus_const(8),
);
let def2 = Def::assign(
"def3",
Variable::mock("RSI", 8 as u64),
Expression::Const(Bitvector::from_str_radix(16, "3002").unwrap()),
);
let mut defs = defs!["def2: RDI:8 = RBP:8 + 8:8", "def3: RSI:8 = 0x3002:8"];
let jump = Jmp::call("call_string", "sprintf", Some("block2"));
block1.term.defs.push(def1);
block1.term.defs.push(def2);
block1.term.defs.append(&mut defs);
block1.term.jmps.push(jump);
sub.term.blocks.push(block1);
sub.term.blocks.push(block2);
......
......@@ -98,7 +98,7 @@ fn generate_cwe_warning(callsite: &Tid, called_symbol: &ExternSymbol) -> CweWarn
"(Integer Overflow or Wraparound) Potential overflow due to multiplication before call to {} at {}",
called_symbol.name, callsite.address
))
.tids(vec![format!("{}", callsite)])
.tids(vec![format!("{callsite}")])
.addresses(vec![callsite.address.clone()])
.symbols(vec![called_symbol.name.clone()])
}
......
......@@ -63,7 +63,7 @@ pub fn check_cwe(
(vec![info_log], Vec::new())
}
Err(err) => {
let err_log = LogMessage::new_error(format!("Error while parsing binary: {}", err))
let err_log = LogMessage::new_error(format!("Error while parsing binary: {err}"))
.source(CWE_MODULE.name);
(vec![err_log], Vec::new())
}
......
......@@ -99,7 +99,7 @@ fn generate_cwe_warning(sub: &Term<Sub>, callsite: &Tid) -> CweWarning {
"(The program utilizes chroot without dropping privileges and/or changing the directory) at {} ({})",
callsite.address, sub.term.name
))
.tids(vec![format!("{}", callsite)])
.tids(vec![format!("{callsite}")])
.addresses(vec![callsite.address.clone()])
.symbols(vec![sub.term.name.clone()])
}
......
......@@ -48,9 +48,7 @@ fn generate_cwe_warning(secure_initializer_func: &str, rand_func: &str) -> CweWa
CWE_MODULE.name,
CWE_MODULE.version,
format!(
"(Insufficient Entropy in PRNG) program uses {} without calling {} before",
rand_func, secure_initializer_func
),
"(Insufficient Entropy in PRNG) program uses {rand_func} without calling {secure_initializer_func} before"),
)
}
......
......@@ -61,7 +61,7 @@ fn generate_cwe_warning(
"(Time-of-check Time-of-use Race Condition) '{}' is reachable from '{}' at {} ({}). This could lead to a TOCTOU.",
sink, source, sink_callsite.address, sub_name
))
.tids(vec![format!("{}", source_callsite), format!("{}", sink_callsite)])
.tids(vec![format!("{source_callsite}"), format!("{sink_callsite}")])
.addresses(vec![source_callsite.address, sink_callsite.address])
.symbols(vec![source.into(), sink.into()])
}
......
......@@ -117,7 +117,7 @@ impl<'a> Context<'a> {
name: "CWE416".to_string(),
version: CWE_MODULE.version.to_string(),
addresses: vec![call_tid.address.clone()],
tids: vec![format!("{}", call_tid)],
tids: vec![format!("{call_tid}")],
symbols: Vec::new(),
other: vec![warnings],
description: format!(
......@@ -151,7 +151,7 @@ impl<'a> Context<'a> {
name: "CWE415".to_string(),
version: CWE_MODULE.version.to_string(),
addresses: vec![call_tid.address.clone()],
tids: vec![format!("{}", call_tid)],
tids: vec![format!("{call_tid}")],
symbols: Vec::new(),
other: vec![warning_causes],
description: format!(
......
......@@ -63,8 +63,7 @@ impl State {
for id in address.get_relative_values().keys() {
if let Some(ObjectState::Dangling(free_id)) = self.dangling_objects.get(id) {
free_ids_of_dangling_pointers.push(format!(
"Accessed ID {} may have been already freed at {}",
id, free_id
"Accessed ID {id} may have been already freed at {free_id}"
));
self.dangling_objects
......@@ -101,8 +100,7 @@ impl State {
.insert(id.clone(), ObjectState::Dangling(call_tid.clone()))
{
warnings.push(format!(
"Object {} may have been freed before at {}.",
id, old_free_id
"Object {id} may have been freed before at {old_free_id}."
));
}
}
......@@ -169,7 +167,7 @@ impl AbstractDomain for State {
#[cfg(test)]
pub mod tests {
use super::*;
use crate::intermediate_representation::Variable;
use crate::{bitvec, intermediate_representation::parsing, variable};
use std::collections::BTreeSet;
#[test]
......@@ -223,9 +221,9 @@ pub mod tests {
let mut state = State::new(Tid::new("current_fn"));
let param = Data::from_target(
AbstractIdentifier::mock("obj_id", "RAX", 8),
Bitvector::from_i64(0).into(),
bitvec!("0:8").into(),
);
let pi_state = PiState::new(&Variable::mock("RSP", 8), Tid::new("call"), BTreeSet::new());
let pi_state = PiState::new(&variable!("RSP:8"), Tid::new("call"), BTreeSet::new());
// Check that the parameter is correctly marked as freed in the state.
assert!(state
.handle_param_of_free_call(&Tid::new("free_call"), &param, &pi_state)
......@@ -251,12 +249,12 @@ pub mod tests {
AbstractIdentifier::mock("callee_obj_tid", "RAX", 8),
ObjectState::Dangling(Tid::new("free_tid")),
);
let pi_state = PiState::new(&Variable::mock("RSP", 8), Tid::new("call"), BTreeSet::new());
let pi_state = PiState::new(&variable!("RSP:8"), Tid::new("call"), BTreeSet::new());
let id_replacement_map = BTreeMap::from([(
AbstractIdentifier::mock("callee_obj_tid", "RAX", 8),
Data::from_target(
AbstractIdentifier::mock("caller_tid", "RBX", 8),
Bitvector::from_i64(42).into(),
bitvec!("42:8").into(),
),
)]);
// Check that the callee object ID is correctly translated to a caller object ID
......
......@@ -156,7 +156,7 @@ impl<'a> Context<'a> {
format!("(NULL Pointer Dereference) There is no check if the return value is NULL at {} ({}).",
taint_source.tid.address, taint_source_name))
.addresses(vec![taint_source.tid.address.clone(), taint_access_location.address.clone()])
.tids(vec![format!("{}", taint_source.tid), format!("{}", taint_access_location)])
.tids(vec![format!("{}", taint_source.tid), format!("{taint_access_location}")])
.symbols(vec![taint_source_name]);
let _ = self.cwe_collector.send(cwe_warning);
}
......@@ -412,6 +412,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
#[cfg(test)]
mod tests {
use super::*;
use crate::{def, expr, variable};
impl<'a> Context<'a> {
pub fn mock(
......@@ -451,10 +452,7 @@ mod tests {
false
);
state.set_register_taint(
&Variable::mock("RDI", ByteSize::new(8)),
Taint::Tainted(ByteSize::new(8)),
);
state.set_register_taint(&variable!("RDI:8"), Taint::Tainted(ByteSize::new(8)));
assert_eq!(
context.check_parameters_for_taint(
&state,
......@@ -476,10 +474,7 @@ mod tests {
.handle_generic_call(&state, &Tid::new("call_tid"))
.is_some());
state.set_register_taint(
&Variable::mock("RDX", 8u64),
Taint::Tainted(ByteSize::new(8)),
);
state.set_register_taint(&variable!("RDX:8"), Taint::Tainted(ByteSize::new(8)));
assert!(context
.handle_generic_call(&state, &Tid::new("call_tid"))
.is_none());
......@@ -493,48 +488,21 @@ mod tests {
let (mut state, pi_state) = State::mock_with_pi_state();
state.set_pointer_inference_state(Some(pi_state));
let assign_def = Term {
tid: Tid::new("def"),
term: Def::Assign {
var: Variable::mock("RCX", 8u64),
value: Expression::Var(Variable::mock("RAX", 8u64)),
},
};
let assign_def = def!["def: RCX:8 = RAX:8"];
let result = context.update_def(&state, &assign_def).unwrap();
assert!(result
.eval(&Expression::Var(Variable::mock("RCX", 8u64)))
.is_tainted());
assert!(result
.eval(&Expression::Var(Variable::mock("RSP", 8u64)))
.is_top());
let load_def = Term {
tid: Tid::new("def"),
term: Def::Load {
var: Variable::mock("RCX", 8u64),
address: Expression::Var(Variable::mock("RSP", 8u64)),
},
};
assert!(result.eval(&expr!("RCX:8")).is_tainted());
assert!(result.eval(&expr!("RSP:8")).is_top());
let load_def = def!["def: RCX:8 := Load from RSP:8"];
let result = context.update_def(&state, &load_def).unwrap();
assert!(result
.eval(&Expression::Var(Variable::mock("RCX", 8u64)))
.is_tainted());
assert!(result
.eval(&Expression::Var(Variable::mock("RSP", 8u64)))
.is_top());
let store_def = Term {
tid: Tid::new("def"),
term: Def::Store {
value: Expression::Var(Variable::mock("RCX", 8u64)),
address: Expression::Var(Variable::mock("RSP", 8u64)),
},
};
assert!(result.eval(&expr!("RCX:8")).is_tainted());
assert!(result.eval(&expr!("RSP:8")).is_top());
let store_def = def!["def: Store at RSP:8 := RCX:8"];
let result = context.update_def(&state, &store_def).unwrap();
let result = context.update_def(&result, &load_def).unwrap();
assert!(result
.eval(&Expression::Var(Variable::mock("RCX", 8u64)))
.is_top());
assert!(result.eval(&expr!("RCX:8")).is_top());
}
#[test]
......@@ -548,7 +516,7 @@ mod tests {
tid: Tid::new("jmp"),
term: Jmp::CBranch {
target: Tid::new("target"),
condition: Expression::Var(Variable::mock("RAX", 8u64)),
condition: expr!("RAX:8"),
},
};
assert!(context
......@@ -558,7 +526,7 @@ mod tests {
tid: Tid::new("jmp"),
term: Jmp::CBranch {
target: Tid::new("target"),
condition: Expression::Var(Variable::mock("RBX", 8u64)),
condition: expr!("RBX:8"),
},
};
assert!(context
......
......@@ -349,7 +349,7 @@ impl State {
let register: Vec<(String, Value)> = self
.register_taint
.iter()
.map(|(var, data)| (var.name.clone(), json!(format!("{}", data))))
.map(|(var, data)| (var.name.clone(), json!(format!("{data}"))))
.collect();
let mut memory = Vec::new();
for (tid, mem_region) in self.memory_taint.iter() {
......@@ -357,7 +357,7 @@ impl State {
for (offset, elem) in mem_region.iter() {
elements.push((offset.to_string(), json!(elem.to_string())));
}
memory.push((format!("{}", tid), Value::Object(Map::from_iter(elements))));
memory.push((format!("{tid}"), Value::Object(Map::from_iter(elements))));
}
let state_map = vec![
(
......@@ -374,8 +374,8 @@ impl State {
#[cfg(test)]
mod tests {
use super::*;
use crate::abstract_domain::*;
use crate::analysis::pointer_inference::ValueDomain;
use crate::{abstract_domain::*, expr, variable};
use std::collections::BTreeSet;
impl State {
......@@ -389,16 +389,16 @@ mod tests {
pub fn mock_with_pi_state() -> (State, PointerInferenceState) {
let arg1 = Arg::Register {
expr: Expression::Var(register("RAX")),
expr: expr!("RAX:8"),
data_type: None,
};
let arg2 = Arg::Stack {
address: Expression::Var(register("RSP")),
address: expr!("RSP:8"),
size: ByteSize::new(8),
data_type: None,
};
let pi_state =
PointerInferenceState::new(&register("RSP"), Tid::new("func"), BTreeSet::new());
PointerInferenceState::new(&variable!("RSP:8"), Tid::new("func"), BTreeSet::new());
let symbol = ExternSymbol {
tid: Tid::new("extern_symbol".to_string()),
addresses: vec![],
......@@ -414,14 +414,6 @@ mod tests {
}
}
fn register(name: &str) -> Variable {
Variable {
name: name.into(),
size: ByteSize::new(8),
is_temp: false,
}
}
fn bv(value: i64) -> ValueDomain {
ValueDomain::from(Bitvector::from_i64(value))
}
......@@ -429,7 +421,7 @@ mod tests {
fn new_id(name: &str) -> AbstractIdentifier {
AbstractIdentifier::new(
Tid::new("time0"),
AbstractLocation::Register(Variable::mock(name, ByteSize::new(8))),
AbstractLocation::Register(variable!(format!("{}:8", name))),
)
}
......@@ -444,7 +436,7 @@ mod tests {
let top = Taint::Top(ByteSize::new(8));
let mut state = State::mock();
state.set_register_taint(&register("RAX"), taint.clone());
state.set_register_taint(&variable!("RAX:8"), taint.clone());
let mut other_state = State::mock();
let address = new_pointer("mem", 10);
......@@ -452,10 +444,10 @@ mod tests {
let merged_state = state.merge(&other_state);
assert_eq!(
merged_state.register_taint.get(&register("RAX")),
merged_state.register_taint.get(&variable!("RAX:8")),
Some(&taint)
);
assert_eq!(merged_state.register_taint.get(&register("RBX")), None);
assert_eq!(merged_state.register_taint.get(&variable!("RBX:8")), None);
assert_eq!(
merged_state.load_taint_from_memory(&address, ByteSize::new(8)),
taint.clone()
......@@ -471,9 +463,9 @@ mod tests {
fn new_state() {
let (state, pi_state) = State::mock_with_pi_state();
let taint = Taint::Tainted(ByteSize::new(8));
assert_eq!(state.register_taint.get(&register("RAX")), Some(&taint));
assert_eq!(state.register_taint.get(&register("RSP")), None);
let address = Expression::Var(register("RSP"));
assert_eq!(state.register_taint.get(&variable!("RAX:8")), Some(&taint));
assert_eq!(state.register_taint.get(&variable!("RSP:8")), None);
let address = Expression::Var(variable!("RSP:8"));
assert_eq!(
state.load_taint_from_memory(&pi_state.eval(&address), ByteSize::new(8)),
taint
......@@ -484,12 +476,12 @@ mod tests {
fn eval_expression() {
let (state, _pi_state) = State::mock_with_pi_state();
let expr = Expression::Var(register("RAX")).plus(Expression::Var(register("RBX")));
let expr = expr!("RAX:8 + RBX:8");
assert!(state.eval(&expr).is_tainted());
let expr = Expression::UnOp {
op: UnOpType::Int2Comp,
arg: Box::new(Expression::Var(register("RSP"))),
arg: Box::new(Expression::Var(variable!("RSP:8"))),
};
assert!(state.eval(&expr).is_top());
}
......
......@@ -23,8 +23,8 @@ impl Display for Taint {
/// Print the value of a `Taint` object.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Tainted(size) => write!(f, "Tainted:{}", size),
Self::Top(size) => write!(f, "Top:{}", size),
Self::Tainted(size) => write!(f, "Tainted:{size}"),
Self::Top(size) => write!(f, "Top:{size}"),
}
}
}
......
......@@ -92,7 +92,7 @@ fn generate_cwe_warning(sub: &Term<Sub>, jmp: &Term<Jmp>, permission_const: u64)
.addresses(vec![jmp.tid.address.clone()])
.other(vec![vec![
"umask_arg".to_string(),
format!("{:#o}", permission_const),
format!("{permission_const:#o}"),
]])
}
......@@ -122,8 +122,7 @@ pub fn check_cwe(
}
Err(err) => {
let log = LogMessage::new_info(format!(
"Could not determine umask argument: {}",
err
"Could not determine umask argument: {err}"
))
.location(jmp.tid.clone())
.source(CWE_MODULE.name);
......
......@@ -66,8 +66,7 @@ pub fn generate_cwe_warnings<'a>(
for (sub_name, jmp_tid, target_name) in dangerous_calls.iter() {
let address: &String = &jmp_tid.address;
let description: String = format!(
"(Use of Potentially Dangerous Function) {} ({}) -> {}",
sub_name, address, target_name
"(Use of Potentially Dangerous Function) {sub_name} ({address}) -> {target_name}"
);
let cwe_warning = CweWarning::new(
String::from(CWE_MODULE.name),
......@@ -75,7 +74,7 @@ pub fn generate_cwe_warnings<'a>(
description,
)
.addresses(vec![address.clone()])
.tids(vec![format!("{}", jmp_tid)])
.tids(vec![format!("{jmp_tid}")])
.symbols(vec![String::from(*sub_name)])
.other(vec![vec![
String::from("dangerous_function"),
......
......@@ -247,7 +247,7 @@ pub fn generate_cwe_warning(sub_name: &str, jmp_tid: &Tid, symbol_name: &str) ->
description,
)
.addresses(vec![jmp_tid.address.clone()])
.tids(vec![format!("{}", jmp_tid)])
.tids(vec![format!("{jmp_tid}")])
.symbols(vec![String::from(sub_name)])
.other(vec![vec![
String::from("OS Command Injection"),
......
......@@ -50,16 +50,14 @@ pub fn generate_cwe_warning(calls: &[(&str, &Tid, &str)]) -> Vec<CweWarning> {
for (sub_name, jmp_tid, _) in calls.iter() {
let address: &String = &jmp_tid.address;
let description = format!(
"(Exposed IOCTL with Insufficient Access Control) Program uses ioctl at {} ({}). Be sure to double check the program and the corresponding driver.",
sub_name, address
);
"(Exposed IOCTL with Insufficient Access Control) Program uses ioctl at {sub_name} ({address}). Be sure to double check the program and the corresponding driver.");
let cwe_warning = CweWarning::new(
String::from(CWE_MODULE.name),
String::from(CWE_MODULE.version),
description,
)
.addresses(vec![address.clone()])
.tids(vec![format!("{}", jmp_tid)])
.tids(vec![format!("{jmp_tid}")])
.symbols(vec![String::from(*sub_name)]);
cwe_warnings.push(cwe_warning);
......
......@@ -120,7 +120,7 @@ fn generate_cwe_warning(allocation: &Tid, is_stack_allocation: bool) -> CweWarni
allocation.address
),
)
.tids(vec![format!("{}", allocation)])
.tids(vec![format!("{allocation}")])
.addresses(vec![allocation.address.clone()])
.symbols(vec![])
}
......
......@@ -91,9 +91,9 @@ impl Term<Def> {
impl fmt::Display for Def {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Def::Load { var, address } => write!(f, "{} := Load from {}", var, address),
Def::Store { address, value } => write!(f, "Store at {} := {}", address, value),
Def::Assign { var, value } => write!(f, "{} = {}", var, value),
Def::Load { var, address } => write!(f, "{var} := Load from {address}"),
Def::Store { address, value } => write!(f, "Store at {address} := {value}"),
Def::Assign { var, value } => write!(f, "{var} = {value}"),
}
}
}
......
......@@ -213,24 +213,24 @@ impl Expression {
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expression::Var(var) => write!(f, "{}", var),
Expression::Var(var) => write!(f, "{var}"),
Expression::Const(c) => {
write!(f, "0x{:016x}:i{}", c, c.bytesize().as_bit_length())
write!(f, "0x{:016x}:{}", c, c.bytesize())
}
Expression::BinOp { op, lhs, rhs } => match op {
BinOpType::IntMult
| BinOpType::IntDiv
| BinOpType::IntRem
| BinOpType::FloatMult
| BinOpType::FloatDiv => write!(f, "{} {} {}", lhs, op, rhs),
_ => write!(f, "({} {} {})", lhs, op, rhs),
| BinOpType::FloatDiv => write!(f, "{lhs} {op} {rhs}"),
_ => write!(f, "({lhs} {op} {rhs})"),
},
Expression::UnOp { op, arg } => write!(f, "{}({})", op, arg),
Expression::Cast { op, size: _, arg } => write!(f, "{}({})", op, arg),
Expression::UnOp { op, arg } => write!(f, "{op}({arg})"),
Expression::Cast { op, size: _, arg } => write!(f, "{op}({arg})"),
Expression::Unknown {
description,
size: _,
} => write!(f, "{}", description),
} => write!(f, "{description}"),
Expression::Subpiece {
low_byte,
size,
......@@ -263,7 +263,7 @@ impl fmt::Display for BinOpType {
BinOpType::IntRem => write!(f, "%"),
BinOpType::BoolAnd => write!(f, "&&"),
BinOpType::BoolOr => write!(f, "||"),
_ => write!(f, "{:?}", self),
_ => write!(f, "{self:?}"),
}
}
}
......@@ -272,14 +272,15 @@ impl fmt::Display for UnOpType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnOpType::BoolNegate => write!(f, "¬"),
_ => write!(f, "{:?}", self),
UnOpType::IntNegate => write!(f, "-"),
_ => write!(f, "{self:?}"),
}
}
}
impl fmt::Display for CastOpType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
write!(f, "{self:?}")
}
}
#[cfg(test)]
......
......@@ -232,7 +232,7 @@ fn display() {
.subpiece(ByteSize(0), ByteSize(20));
assert_eq!(
"(FloatCeil(IntSExt(IntNegate((0x2:i32 + RAX:64 * RBP:64)))))[0-19]",
"(FloatCeil(IntSExt(-((0x2:4 + RAX:8 * RBP:8)))))[0-19]",
format!("{}", expr)
);
}
......@@ -64,9 +64,9 @@ pub enum Jmp {
impl fmt::Display for Jmp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Jmp::Branch(tid) => write!(f, "Jump to {}", tid),
Jmp::BranchInd(expr) => write!(f, "Jump to {}", expr),
Jmp::CBranch { target, condition } => write!(f, "If {} jump to {}", condition, target),
Jmp::Branch(tid) => write!(f, "Jump to {tid}"),
Jmp::BranchInd(expr) => write!(f, "Jump to {expr}"),
Jmp::CBranch { target, condition } => write!(f, "If {condition} jump to {target}"),
Jmp::Call { target, return_ } => write!(
f,
"call {} ret {}",
......@@ -79,7 +79,7 @@ impl fmt::Display for Jmp {
target,
return_.as_ref().unwrap_or(&Tid::new("?"))
),
Jmp::Return(expr) => write!(f, "ret {}", expr),
Jmp::Return(expr) => write!(f, "ret {expr}"),
Jmp::CallOther {
description,
return_,
......
use crate::intermediate_representation::*;
#[test]
fn test_var() {
assert_eq!(
variable!("RAX:8"),
Variable {
name: "RAX".to_string(),
size: ByteSize(8),
is_temp: false
}
);
}
#[test]
#[should_panic]
fn var_empty_panics() {
variable!("");
}
#[test]
#[should_panic]
fn var_no_colon_panics() {
variable!("RAX8");
}
#[test]
#[should_panic]
fn var_no_size_panics() {
variable!("RAX:");
}
#[test]
fn test_bitvec() {
assert_eq!(bitvec!("0x42:1"), Bitvector::from_u8(0x42));
assert_eq!(bitvec!("0xFF:2"), Bitvector::from_u16(0xFF));
assert_eq!(bitvec!("0xAAFF:1"), Bitvector::from_u8(0xFF));
assert_eq!(bitvec!("0x-01:1"), Bitvector::from_i8(-1));
assert_eq!(bitvec!("123:4"), Bitvector::from_u32(123));
assert_eq!(bitvec!("-42:8"), Bitvector::from_i64(-42));
}
#[test]
fn test_expr_var() {
assert_eq!(
expr!("RAX:8"),
Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
})
);
}
#[test]
fn test_expr_const() {
assert_eq!(
expr!("0x42:8"),
Expression::Const(Bitvector::from_u64(0x42))
);
assert_eq!(
expr!("0xFFFF:1"),
Expression::Const(Bitvector::from_u8(255))
);
assert_eq!(expr!("42:4"), Expression::Const(Bitvector::from_u32(42)));
}
#[test]
fn test_expr_plus() {
assert_eq!(
expr!("RAX:8 + 0x42:8"),
Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::Const(Bitvector::from_u64(0x42)))
}
);
}
#[test]
fn test_expr_minus() {
assert_eq!(
expr!("RAX:8 - 0x42:8"),
Expression::BinOp {
op: BinOpType::IntSub,
lhs: Box::new(Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::Const(Bitvector::from_u64(0x42)))
}
);
}
#[test]
fn test_expr_int_negate() {
assert_eq!(
expr!("-(RAX:8)"),
Expression::UnOp {
op: UnOpType::IntNegate,
arg: Box::new(Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
}))
}
);
}
#[test]
fn test_expr_bool_negate() {
assert_eq!(
expr!("¬(RAX:8)"),
Expression::UnOp {
op: UnOpType::BoolNegate,
arg: Box::new(Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
}))
}
);
}
#[test]
fn test_def_tid() {
let defs = defs![
"RDI:8 = RAX:8 + RBP:8",
"A: RAX:8 = 0x42:1",
"RDX:8 = RAX:8 + RBP:8"
];
assert_eq!(
defs.into_iter()
.map(|x| x.tid.to_string())
.collect::<Vec<String>>(),
["tid_0", "A", "tid_2"]
)
}
#[test]
fn test_defs_assign() {
assert_eq!(
defs!["tid_0: RAX:8 = 0x42:1", "tid_1: RDI:8 = RAX:8 + RBP:8"],
vec![
Term {
tid: Tid::new("tid_0"),
term: Def::Assign {
var: Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
},
value: Expression::Const(Bitvector::from_i8(0x42))
}
},
Term {
tid: Tid::new("tid_1"),
term: Def::Assign {
var: Variable {
name: "RDI".into(),
size: ByteSize(8),
is_temp: false
},
value: Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::Var(Variable {
name: "RBP".into(),
size: ByteSize(8),
is_temp: false
}))
}
}
}
]
);
}
#[test]
fn test_defs_store() {
assert_eq!(
defs!["tid: Store at RSP:8 - 0x8:1 := 0x42:1"],
vec![Term {
tid: Tid::new("tid"),
term: Def::Store {
address: Expression::BinOp {
op: BinOpType::IntSub,
lhs: Box::new(Expression::Var(Variable {
name: "RSP".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::Const(Bitvector::from_u8(0x8)))
},
value: Expression::Const(Bitvector::from_u8(0x42))
}
}]
)
}
#[test]
fn test_defs_load() {
assert_eq!(
defs!["tid_a: RAX:8 := Load from 0xFF00:4 + 0x08:4"],
vec![Term {
tid: Tid::new("tid_a"),
term: Def::Load {
var: Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
},
address: Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Const(Bitvector::from_u32(0xFF00))),
rhs: Box::new(Expression::Const(Bitvector::from_u32(0x08)))
}
}
}]
)
}
#[test]
fn test_defs_composition() {
assert_eq!(
defs![
"tid_a: Store at RSP:8 + -(0x8:1) := RAX:8",
"tid_b: RSP:8 = RSP:8 + ¬(0x8:1)",
"tid_c: RDI:8 := Load from RSP:8"
],
vec![
Term {
tid: Tid::new("tid_a"),
term: Def::Store {
address: Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Var(Variable {
name: "RSP".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::UnOp {
op: UnOpType::IntNegate,
arg: Box::new(Expression::Const(Bitvector::from_u8(0x08)))
})
},
value: Expression::Var(Variable {
name: "RAX".into(),
size: ByteSize(8),
is_temp: false
})
}
},
Term {
tid: Tid::new("tid_b"),
term: Def::Assign {
var: Variable {
name: "RSP".into(),
size: ByteSize(8),
is_temp: false
},
value: Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Var(Variable {
name: "RSP".into(),
size: ByteSize(8),
is_temp: false
})),
rhs: Box::new(Expression::UnOp {
op: UnOpType::BoolNegate,
arg: Box::new(Expression::Const(Bitvector::from_u8(0x08)))
})
}
}
},
Term {
tid: Tid::new("tid_c"),
term: Def::Load {
var: Variable {
name: "RDI".into(),
size: ByteSize(8),
is_temp: false
},
address: Expression::Var(Variable {
name: "RSP".into(),
size: ByteSize(8),
is_temp: false
})
}
}
]
)
}
......@@ -32,6 +32,11 @@ mod project;
pub use project::*;
mod runtime_memory_image;
pub use runtime_memory_image::*;
#[cfg(test)]
#[macro_use]
mod macros;
#[cfg(test)]
pub use macros::*;
/// An unsigned number of bytes.
///
......
......@@ -37,7 +37,7 @@ impl Tid {
/// the returned block ID is the one that would be executed first if a jump to the given address happened.
pub fn blk_id_at_address(address: &str) -> Tid {
Tid {
id: format!("blk_{}", address),
id: format!("blk_{address}"),
address: address.to_string(),
}
}
......
......@@ -22,7 +22,7 @@ pub struct Variable {
impl Display for Variable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.name, self.size.as_bit_length())?;
write!(f, "{}:{}", self.name, self.size)?;
if self.is_temp {
write!(f, "(temp)")?;
}
......
......@@ -42,7 +42,7 @@ impl From<Variable> for IrExpression {
match (&pcode_var.name, &pcode_var.value) {
(Some(_name), None) => IrExpression::Var(pcode_var.into()),
(None, Some(_hex_value)) => IrExpression::Const(pcode_var.parse_const_to_bitvector()),
_ => panic!("Conversion failed:\n{:?}", pcode_var),
_ => panic!("Conversion failed:\n{pcode_var:?}"),
}
}
}
......
......@@ -312,7 +312,7 @@ fn piecing_or_zero_extending() {
replace_subregister_in_block(&mut block, &register_map);
assert!(check_defs_of_block(
&block,
vec!["zext_eax_to_rax: RAX:64 = IntZExt(0x0:i32)"]
vec!["zext_eax_to_rax: RAX:8 = IntZExt(0x0:4)"]
));
// Test whether zero extension to base register is still recognized
......@@ -328,7 +328,7 @@ fn piecing_or_zero_extending() {
replace_subregister_in_block(&mut block, &register_map);
assert!(check_defs_of_block(
&block,
vec!["zext_ah_to_rax: RAX:64 = IntZExt(0x0:i8)"]
vec!["zext_ah_to_rax: RAX:8 = IntZExt(0x0:1)"]
));
// Test when the next register is a zero extension to a different register.
......@@ -344,8 +344,8 @@ fn piecing_or_zero_extending() {
assert!(check_defs_of_block(
&block,
vec![
"eax_assign: RAX:64 = ((RAX:64)[4-7] Piece 0x0:i32)",
"zext_eax_to_rcx: RCX:64 = IntZExt((RAX:64)[0-3])"
"eax_assign: RAX:8 = ((RAX:8)[4-7] Piece 0x0:4)",
"zext_eax_to_rcx: RCX:8 = IntZExt((RAX:8)[0-3])"
]
));
......@@ -362,8 +362,8 @@ fn piecing_or_zero_extending() {
assert!(check_defs_of_block(
&block,
vec![
"ah_assign: RAX:64 = (((RAX:64)[2-7] Piece 0x0:i8) Piece (RAX:64)[0-0])",
"zext_ah_to_eax: RAX:64 = ((RAX:64)[4-7] Piece IntZExt((RAX:64)[1-1]))",
"ah_assign: RAX:8 = (((RAX:8)[2-7] Piece 0x0:1) Piece (RAX:8)[0-0])",
"zext_ah_to_eax: RAX:8 = ((RAX:8)[4-7] Piece IntZExt((RAX:8)[1-1]))",
]
));
......@@ -380,8 +380,8 @@ fn piecing_or_zero_extending() {
assert!(check_defs_of_block(
&block,
vec![
"load_to_eax: loaded_value:32(temp) := Load from 0x0:i64",
"zext_eax_to_rax: RAX:64 = IntZExt(loaded_value:32(temp))",
"load_to_eax: loaded_value:4(temp) := Load from 0x0:8",
"zext_eax_to_rax: RAX:8 = IntZExt(loaded_value:4(temp))",
]
));
......@@ -398,9 +398,9 @@ fn piecing_or_zero_extending() {
assert!(check_defs_of_block(
&block,
vec![
"load_to_eax: loaded_value:32(temp) := Load from 0x0:i64",
"load_to_eax_cast_to_base: RAX:64 = ((RAX:64)[4-7] Piece loaded_value:32(temp))",
"zext_eax_to_rcx: RCX:64 = IntZExt((RAX:64)[0-3])"
"load_to_eax: loaded_value:4(temp) := Load from 0x0:8",
"load_to_eax_cast_to_base: RAX:8 = ((RAX:8)[4-7] Piece loaded_value:4(temp))",
"zext_eax_to_rcx: RCX:8 = IntZExt((RAX:8)[0-3])"
]
));
}
......@@ -293,7 +293,7 @@ impl Blk {
_ => panic!(),
};
if input.address.is_some() {
let temp_register_name = format!("$load_temp{}", index);
let temp_register_name = format!("$load_temp{index}");
let load_def = input.to_load_def(temp_register_name, generic_pointer_size);
*input = load_def.lhs.clone().unwrap();
refactored_defs.push(Term {
......
......@@ -792,28 +792,28 @@ fn from_project_to_ir_project() {
// Checks if the other definitions and the jump were correctly casted.
assert_eq!(
format!("{}", ir_block.defs[0].term),
"loaded_value:32(temp) := Load from (RDI:64)[0-3]".to_string()
"loaded_value:4(temp) := Load from (RDI:8)[0-3]".to_string()
);
assert_eq!(
format!("{}", ir_block.defs[1].term),
"RDI:64 = ((RDI:64)[4-7] Piece loaded_value:32(temp))".to_string()
"RDI:8 = ((RDI:8)[4-7] Piece loaded_value:4(temp))".to_string()
);
assert_eq!(
format!("{}", ir_block.defs[2].term),
"RAX:64 = (((RAX:64)[2-7] Piece ((RAX:64)[1-1] ^ (RAX:64)[1-1])) Piece (RAX:64)[0-0])"
"RAX:8 = (((RAX:8)[2-7] Piece ((RAX:8)[1-1] ^ (RAX:8)[1-1])) Piece (RAX:8)[0-0])"
.to_string()
);
assert_eq!(
format!("{}", ir_block.defs[3].term),
"RAX:64 = IntZExt((RDI:64)[0-3])".to_string()
"RAX:8 = IntZExt((RDI:8)[0-3])".to_string()
);
assert_eq!(
format!("{}", ir_block.defs[4].term),
"RAX:64 = ((RAX:64)[4-7] Piece (0x0:i16 Piece (RAX:64)[0-1]))".to_string()
"RAX:8 = ((RAX:8)[4-7] Piece (0x0:2 Piece (RAX:8)[0-1]))".to_string()
);
assert_eq!(
format!("{}", ir_block.defs[5].term),
"RAX:64 = ((RAX:64)[2-7] Piece ((RDI:64)[0-3])[1-2])".to_string()
"RAX:8 = ((RAX:8)[2-7] Piece ((RDI:8)[0-3])[1-2])".to_string()
);
assert_eq!(ir_block.jmps[0].term, expected_jmp);
}
......@@ -31,7 +31,7 @@ pub fn get_project_from_ghidra(
.as_millis()
);
// Create a unique name for the pipe
let fifo_path = tmp_folder.join(format!("pcode_{}.pipe", timestamp_suffix));
let fifo_path = tmp_folder.join(format!("pcode_{timestamp_suffix}.pipe"));
let ghidra_command = generate_ghidra_call_command(
file_path,
&fifo_path,
......@@ -93,7 +93,7 @@ fn execute_ghidra(
let output = match ghidra_command.output() {
Ok(output) => output,
Err(err) => {
eprintln!("Ghidra could not be executed: {}", err);
eprintln!("Ghidra could not be executed: {err}");
std::process::exit(101);
}
};
......@@ -107,7 +107,7 @@ fn execute_ghidra(
eprintln!("{}", String::from_utf8(output.stdout).unwrap());
eprintln!("{}", String::from_utf8(output.stderr).unwrap());
if let Some(code) = output.status.code() {
eprintln!("Ghidra plugin failed with exit code {}", code);
eprintln!("Ghidra plugin failed with exit code {code}");
}
eprintln!("Execution of Ghidra plugin failed.");
} else {
......@@ -150,7 +150,7 @@ fn generate_ghidra_call_command(
let mut ghidra_command = Command::new(headless_path);
ghidra_command
.arg(&tmp_folder) // The folder where temporary files should be stored
.arg(format!("PcodeExtractor_{}_{}", filename, timestamp_suffix)) // The name of the temporary Ghidra Project.
.arg(format!("PcodeExtractor_{filename}_{timestamp_suffix}")) // The name of the temporary Ghidra Project.
.arg("-import") // Import a file into the Ghidra project
.arg(file_path) // File import path
.arg("-postScript") // Execute a script after standard analysis by Ghidra finished
......
......@@ -155,9 +155,9 @@ impl std::fmt::Display for LogMessage {
LogLevel::Info => write!(formatter, "INFO: ")?,
};
match (&self.source, &self.location) {
(Some(source), Some(location)) => write!(formatter, "{} @ {}: ", source, location)?,
(Some(source), None) => write!(formatter, "{}: ", source)?,
(None, Some(location)) => write!(formatter, "{}: ", location)?,
(Some(source), Some(location)) => write!(formatter, "{source} @ {location}: ")?,
(Some(source), None) => write!(formatter, "{source}: ")?,
(None, Some(location)) => write!(formatter, "{location}: ")?,
(None, None) => (),
};
write!(formatter, "{}", self.text)
......@@ -177,23 +177,22 @@ pub fn print_all_messages(
emit_json: bool,
) {
for log in logs {
println!("{}", log);
println!("{log}");
}
let output: String = if emit_json {
serde_json::to_string_pretty(&cwes).unwrap()
} else {
cwes.iter()
.map(|cwe| format!("{}", cwe))
.map(|cwe| format!("{cwe}"))
.collect::<Vec<String>>()
.join("\n")
+ "\n"
};
if let Some(file_path) = out_path {
std::fs::write(file_path, output).unwrap_or_else(|error| {
panic!("Writing to output path {} failed: {}", file_path, error)
});
std::fs::write(file_path, output)
.unwrap_or_else(|error| panic!("Writing to output path {file_path} failed: {error}"));
} else {
print!("{}", output);
print!("{output}",);
}
}
......@@ -215,7 +214,7 @@ pub fn add_debug_log_statistics(all_logs: &mut Vec<LogMessage>) {
}
for (analysis, count) in analysis_debug_log_count {
all_logs.push(LogMessage {
text: format!("Logged {} debug log messages.", count),
text: format!("Logged {count} debug log messages."),
level: LogLevel::Info,
location: None,
source: Some(analysis),
......@@ -223,10 +222,7 @@ pub fn add_debug_log_statistics(all_logs: &mut Vec<LogMessage>) {
}
if general_debug_log_count > 0 {
all_logs.push(LogMessage {
text: format!(
"Logged {} general debug log messages.",
general_debug_log_count
),
text: format!("Logged {general_debug_log_count} general debug log messages."),
level: LogLevel::Info,
location: None,
source: None,
......
......@@ -70,8 +70,7 @@ impl CweTestCase {
} else {
println!("{} \t {}", filepath, "[FAILED]".red());
Err(format!(
"Expected occurrences: {}. Found: {}",
num_expected_occurences, num_cwes
"Expected occurrences: {num_expected_occurences}. Found: {num_cwes}"
))
}
} else {
......@@ -79,7 +78,7 @@ impl CweTestCase {
match output.status.code() {
Some(_code) => Err(String::from_utf8(output.stdout).unwrap()
+ &String::from_utf8(output.stderr).unwrap()),
None => Err(format!("Execution failed for file {}", filepath)),
None => Err(format!("Execution failed for file {filepath}")),
}
}
}
......@@ -160,8 +159,8 @@ pub fn all_test_cases(cwe: &'static str, check_name: &'static str) -> Vec<CweTes
/// The `error_log` tuples are of the form `(check_filename, error_message)`.
pub fn print_errors(error_log: Vec<(String, String)>) {
for (filepath, error) in error_log {
println!("{}", format!("+++ Error for {} +++", filepath).red());
println!("{}", error);
println!("{}", format!("+++ Error for {filepath} +++").red());
println!("{error}");
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment