use crate::{
cilassembly::{AssemblyChanges, CilAssembly, Operation, TableModifications, TableOperation},
metadata::{
tables::{CodedIndex, CodedIndexType, TableDataOwned, TableId, TypeDefRaw},
token::Token,
},
test::{get_testfile_wb, TestAssembly},
Error, Result,
};
pub fn raw_operation_validator_file_factory() -> Result<Vec<TestAssembly>> {
let mut assemblies = Vec::new();
if let Some(clean_path) = get_testfile_wb() {
assemblies.push(TestAssembly::new(clean_path, true));
}
Ok(assemblies)
}
pub fn create_dummy_typedef(rid: u32, flags: u32) -> TypeDefRaw {
TypeDefRaw {
rid,
token: Token::new(0x02000000 | rid),
offset: 0,
flags,
type_name: 1,
type_namespace: 0,
extends: CodedIndex {
tag: TableId::TypeDef,
row: 0,
token: Token::new(0),
ci_type: CodedIndexType::TypeDefOrRef,
},
field_list: 1,
method_list: 1,
}
}
pub fn create_corrupted_changes_with_invalid_rid_zero() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Insert(0, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_excessive_rid() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Insert(0x1000000, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_nonexistent_target() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Update(999, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_update_after_delete() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(2);
let typedef_data = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(typedef_data);
let delete_op = TableOperation::new_with_timestamp(Operation::Delete(1), 1000);
let update_op = TableOperation::new_with_timestamp(Operation::Update(1, table_data), 2000);
if let TableModifications::Sparse {
operations,
deleted_rows,
..
} = &mut table_mods
{
operations.push(delete_op);
operations.push(update_op);
deleted_rows.insert(1); }
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_excessive_updates() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(2);
let typedef_data = create_dummy_typedef(1, 0);
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
for i in 0..12 {
let table_data = TableDataOwned::TypeDef(typedef_data.clone());
let update_op = TableOperation::new_with_timestamp(
Operation::Update(1, table_data),
1000 + i as u64,
);
operations.push(update_op);
}
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_unordered_operations() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let typedef_data1 = create_dummy_typedef(1, 0);
let typedef_data2 = create_dummy_typedef(2, 1);
let op1 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data1)),
2000, );
let op2 = TableOperation::new_with_timestamp(
Operation::Insert(2, TableDataOwned::TypeDef(typedef_data2)),
1000, );
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(op1);
operations.push(op2);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_corrupted_changes_with_conflicting_inserts() -> AssemblyChanges {
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let typedef_data1 = create_dummy_typedef(1, 0);
let typedef_data2 = create_dummy_typedef(2, 1);
let op1 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data1)),
1000,
);
let op2 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data2)),
2000,
);
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(op1);
operations.push(op2);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
corrupted_changes
}
pub fn create_assembly_with_invalid_rid_zero() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Insert(0, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_excessive_rid() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Insert(0x1000000, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_nonexistent_target() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let invalid_typedef = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(invalid_typedef);
let invalid_op = TableOperation::new(Operation::Update(999, table_data));
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(invalid_op);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_update_after_delete() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(2);
let typedef_data = create_dummy_typedef(1, 0);
let table_data = TableDataOwned::TypeDef(typedef_data);
let delete_op = TableOperation::new_with_timestamp(Operation::Delete(1), 1000);
let update_op = TableOperation::new_with_timestamp(Operation::Update(1, table_data), 2000);
if let TableModifications::Sparse {
operations,
deleted_rows,
..
} = &mut table_mods
{
operations.push(delete_op);
operations.push(update_op);
deleted_rows.insert(1); }
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_excessive_updates() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(2);
let typedef_data = create_dummy_typedef(1, 0);
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
for i in 0..12 {
let table_data = TableDataOwned::TypeDef(typedef_data.clone());
let update_op = TableOperation::new_with_timestamp(
Operation::Update(1, table_data),
1000 + i as u64,
);
operations.push(update_op);
}
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_unordered_operations() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let typedef_data1 = create_dummy_typedef(1, 0);
let typedef_data2 = create_dummy_typedef(2, 1);
let op1 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data1)),
2000, );
let op2 = TableOperation::new_with_timestamp(
Operation::Insert(2, TableDataOwned::TypeDef(typedef_data2)),
1000, );
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(op1);
operations.push(op2);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_assembly_with_conflicting_inserts() -> Result<tempfile::NamedTempFile> {
let Some(clean_testfile) = get_testfile_wb() else {
return Err(Error::Other("WindowsBase.dll not available".to_string()));
};
let assembly = CilAssembly::from_path(&clean_testfile)?;
let mut corrupted_changes = AssemblyChanges::empty();
let mut table_mods = TableModifications::new_sparse(1);
let typedef_data1 = create_dummy_typedef(1, 0);
let typedef_data2 = create_dummy_typedef(2, 1);
let op1 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data1)),
1000,
);
let op2 = TableOperation::new_with_timestamp(
Operation::Insert(1, TableDataOwned::TypeDef(typedef_data2)),
2000,
);
if let TableModifications::Sparse { operations, .. } = &mut table_mods {
operations.push(op1);
operations.push(op2);
}
corrupted_changes
.table_changes
.insert(TableId::TypeDef, table_mods);
create_temp_assembly_with_changes(assembly, corrupted_changes)
}
pub fn create_temp_assembly_with_changes(
_assembly: CilAssembly,
_corrupted_changes: AssemblyChanges,
) -> Result<tempfile::NamedTempFile> {
let temp_file = tempfile::NamedTempFile::new()?;
let temp_path = temp_file.path();
use std::fs;
if let Some(clean_testfile) = get_testfile_wb() {
fs::copy(clean_testfile, temp_path)?;
}
Ok(temp_file)
}