Skip to content

Commit

Permalink
Patch: use checked sum for locals counter (#40)
Browse files Browse the repository at this point in the history
follow-up patch to #38

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
  • Loading branch information
agryaznov and athei authored Dec 8, 2022
1 parent 6a79d1d commit 54c4f8f
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 31 deletions.
9 changes: 5 additions & 4 deletions src/gas_metering/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ pub mod mutable_global {
];

// calculate gas used for the gas charging func execution itself
let mut gas_fn_cost = func_instructions.iter().fold(0, |cost, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64)
let mut gas_fn_cost = func_instructions.iter().fold(0, |cost: u64, instruction| {
cost.saturating_add(rules.instruction_cost(instruction).unwrap_or(u32::MAX).into())
});
// don't charge for the instructions used to fail when out of gas
let fail_cost = vec![
Expand All @@ -122,10 +122,11 @@ pub mod mutable_global {
Instruction::Unreachable, // non-charged instruction
]
.iter()
.fold(0, |cost, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64)
.fold(0, |cost: u64, instruction| {
cost.saturating_add(rules.instruction_cost(instruction).unwrap_or(u32::MAX).into())
});

// the fail costs are a subset of the overall costs and hence this never underflows
gas_fn_cost -= fail_cost;

GasMeter::Internal {
Expand Down
46 changes: 23 additions & 23 deletions src/gas_metering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ pub fn inject<R: Rules, B: Backend>(
let functions_space = module.functions_space() as u32;
let gas_global_idx = module.globals_space() as u32;

let mut mbuilder = builder::from_module(module);
let mut mbuilder = builder::from_module(module.clone());

// Calculate the indexes and gas function cost,
// for external gas function the cost is counted on the host side
Expand Down Expand Up @@ -224,15 +224,14 @@ pub fn inject<R: Rules, B: Backend>(
};

// We need the built the module for making injections to its blocks
let mut module = mbuilder.build();
let mut resulting_module = mbuilder.build();

let mut need_grow_counter = false;
let mut error = false;

let mut result = Ok(());
// Iterate over module sections and perform needed transformations.
// Indexes are needed to be fixed up in `GasMeter::External` case, as it adds an imported
// function, which goes to the beginning of the module's functions space.
for section in module.sections_mut() {
'outer: for section in resulting_module.sections_mut() {
match section {
elements::Section::Code(code_section) => {
let injection_targets = match gas_meter {
Expand All @@ -257,19 +256,22 @@ pub fn inject<R: Rules, B: Backend>(
}
}
}
let locals_count =
func_body.locals().iter().map(|val_type| val_type.count()).sum();
if inject_counter(
func_body.code_mut(),
gas_fn_cost,
locals_count,
rules,
gas_func_idx,
)
.is_err()
{
error = true;
break
result = func_body
.locals()
.iter()
.try_fold(0u32, |count, val_type| count.checked_add(val_type.count()))
.ok_or(())
.and_then(|locals_count| {
inject_counter(
func_body.code_mut(),
gas_fn_cost,
locals_count,
rules,
gas_func_idx,
)
});
if result.is_err() {
break 'outer
}
if rules.memory_grow_cost().enabled() &&
inject_grow_counter(func_body.code_mut(), total_func) > 0
Expand Down Expand Up @@ -325,14 +327,12 @@ pub fn inject<R: Rules, B: Backend>(
}
}

if error {
return Err(module)
}
result.map_err(|_| module)?;

if need_grow_counter {
Ok(add_grow_counter(module, rules, gas_func_idx))
Ok(add_grow_counter(resulting_module, rules, gas_func_idx))
} else {
Ok(module)
Ok(resulting_module)
}
}

Expand Down
11 changes: 7 additions & 4 deletions src/gas_metering/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,12 @@ fn build_control_flow_graph(
let mut stack = vec![ControlFrame::new(entry_node_id, terminal_node_id, false)];
let mut metered_blocks_iter = blocks.iter().peekable();

let locals_count = body.locals().iter().fold(0, |count, val_type| count + val_type.count());
let locals_init_cost = (rules.call_per_local_cost()).checked_mul(locals_count).ok_or(())?;
let locals_count = body
.locals()
.iter()
.try_fold(0u32, |count, val_type| count.checked_add(val_type.count()))
.ok_or(())?;
let locals_init_cost = rules.call_per_local_cost().checked_mul(locals_count).ok_or(())?;

for (cursor, instruction) in body.code().elements().iter().enumerate() {
let active_node_id = stack
Expand Down Expand Up @@ -350,8 +354,7 @@ mod tests {

for func_body in module.code_section().iter().flat_map(|section| section.bodies()) {
let rules = ConstantCostRules::default();
let locals_count =
func_body.locals().iter().fold(0, |count, val_type| count + val_type.count());
let locals_count = func_body.locals().iter().map(|val_type| val_type.count()).sum();

let metered_blocks =
determine_metered_blocks(func_body.code(), &rules, locals_count).unwrap();
Expand Down

0 comments on commit 54c4f8f

Please sign in to comment.