use super::*;
impl<'a> Context<'a> {
pub fn handle_params_of_sscanf_call(
&self,
state: &State,
new_state: &mut State,
sscanf_symbol: &ExternSymbol,
call_tid: &Tid,
) -> Result<(), Error> {
use crate::utils::arguments;
let format_string_address = state
.eval_parameter_arg(
&sscanf_symbol.parameters[1],
&self.project.runtime_memory_image,
)?
.get_if_absolute_value()
.ok_or_else(|| anyhow!("Format string may not be a constant string"))?
.try_to_bitvec()?;
let format_string = arguments::parse_format_string_destination_and_return_content(
format_string_address,
&self.project.runtime_memory_image,
)?;
let format_string_param_types = arguments::parse_format_string_parameters(
&format_string,
&self.project.datatype_properties,
)?;
let format_string_params =
vec![
(Datatype::Pointer, self.project.stack_pointer_register.size);
format_string_param_types.len()
];
let format_string_args = arguments::calculate_parameter_locations(
format_string_params,
sscanf_symbol,
self.project,
);
for (arg, (datatype, size)) in format_string_args
.iter()
.zip(format_string_param_types.iter())
{
if let Ok(param) = state.eval_parameter_arg(arg, &self.project.runtime_memory_image) {
if *datatype != Datatype::Pointer {
self.log_debug(
new_state.store_value(
¶m,
&Data::new_top(*size),
&self.project.runtime_memory_image,
),
Some(call_tid),
);
} else {
for id in param.referenced_ids() {
new_state
.memory
.assume_arbitrary_writes_to_object(id, &BTreeSet::new());
}
}
}
}
Ok(())
}
pub fn handle_parameter_access_for_stubbed_functions(
&self,
state: &State,
new_state: &mut State,
extern_symbol: &ExternSymbol,
) {
let access_patterns = self
.extern_fn_param_access_patterns
.get(extern_symbol.name.as_str())
.unwrap();
for (arg, access_pattern) in extern_symbol.parameters.iter().zip(access_patterns.iter()) {
if access_pattern.is_mutably_dereferenced() {
if let Ok(param) = state.eval_parameter_arg(arg, &self.project.runtime_memory_image)
{
for id in param.referenced_ids() {
new_state
.memory
.assume_arbitrary_writes_to_object(id, &BTreeSet::new());
}
}
}
}
}
pub fn compute_return_value_for_stubbed_function(
&self,
state: &State,
extern_symbol: &ExternSymbol,
) -> Data {
use return_value_stubs::*;
match extern_symbol.name.as_str() {
"memcpy" | "memmove" | "memset" | "strcat" | "strcpy" | "strncat" | "strncpy" => {
copy_param(state, extern_symbol, 0, &self.project.runtime_memory_image)
}
"fgets" => or_null(copy_param(
state,
extern_symbol,
0,
&self.project.runtime_memory_image,
)),
"strchr" | "strrchr" | "strstr" => or_null(param_plus_unknown_offset(
state,
extern_symbol,
0,
&self.project.runtime_memory_image,
)),
_ => untracked(self.project.stack_pointer_register.size),
}
}
}
pub mod return_value_stubs {
use super::*;
pub fn untracked(register_size: ByteSize) -> Data {
Data::new_top(register_size)
}
pub fn copy_param(
state: &State,
extern_symbol: &ExternSymbol,
param_index: usize,
global_memory: &RuntimeMemoryImage,
) -> Data {
state
.eval_parameter_arg(&extern_symbol.parameters[param_index], global_memory)
.unwrap_or_else(|_| Data::new_top(extern_symbol.parameters[param_index].bytesize()))
}
pub fn param_plus_unknown_offset(
state: &State,
extern_symbol: &ExternSymbol,
param_index: usize,
global_memory: &RuntimeMemoryImage,
) -> Data {
let param = state
.eval_parameter_arg(&extern_symbol.parameters[param_index], global_memory)
.unwrap_or_else(|_| Data::new_top(extern_symbol.parameters[param_index].bytesize()));
param.add_offset(&IntervalDomain::new_top(param.bytesize()))
}
pub fn or_null(data: Data) -> Data {
data.merge(&Bitvector::zero(data.bytesize().into()).into())
}
}