Patch: use checked sum for locals counter (#40)

follow-up patch to #38

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
This commit is contained in:
Sasha Gryaznov
2022-12-08 12:58:02 +02:00
committed by GitHub
parent 6a79d1d4b8
commit 54c4f8f878
3 changed files with 35 additions and 31 deletions
+5 -4
View File
@@ -112,8 +112,8 @@ pub mod mutable_global {
]; ];
// calculate gas used for the gas charging func execution itself // calculate gas used for the gas charging func execution itself
let mut gas_fn_cost = func_instructions.iter().fold(0, |cost, instruction| { let mut gas_fn_cost = func_instructions.iter().fold(0, |cost: u64, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64) 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 // don't charge for the instructions used to fail when out of gas
let fail_cost = vec![ let fail_cost = vec![
@@ -122,10 +122,11 @@ pub mod mutable_global {
Instruction::Unreachable, // non-charged instruction Instruction::Unreachable, // non-charged instruction
] ]
.iter() .iter()
.fold(0, |cost, instruction| { .fold(0, |cost: u64, instruction| {
cost + (rules.instruction_cost(instruction).unwrap_or(0) as u64) 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; gas_fn_cost -= fail_cost;
GasMeter::Internal { GasMeter::Internal {
+23 -23
View File
@@ -166,7 +166,7 @@ pub fn inject<R: Rules, B: Backend>(
let functions_space = module.functions_space() as u32; let functions_space = module.functions_space() as u32;
let gas_global_idx = module.globals_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, // Calculate the indexes and gas function cost,
// for external gas function the cost is counted on the host side // for external gas function the cost is counted on the host side
@@ -224,15 +224,14 @@ pub fn inject<R: Rules, B: Backend>(
}; };
// We need the built the module for making injections to its blocks // 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 need_grow_counter = false;
let mut error = false; let mut result = Ok(());
// Iterate over module sections and perform needed transformations. // Iterate over module sections and perform needed transformations.
// Indexes are needed to be fixed up in `GasMeter::External` case, as it adds an imported // 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. // 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 { match section {
elements::Section::Code(code_section) => { elements::Section::Code(code_section) => {
let injection_targets = match gas_meter { let injection_targets = match gas_meter {
@@ -257,19 +256,22 @@ pub fn inject<R: Rules, B: Backend>(
} }
} }
} }
let locals_count = result = func_body
func_body.locals().iter().map(|val_type| val_type.count()).sum(); .locals()
if inject_counter( .iter()
func_body.code_mut(), .try_fold(0u32, |count, val_type| count.checked_add(val_type.count()))
gas_fn_cost, .ok_or(())
locals_count, .and_then(|locals_count| {
rules, inject_counter(
gas_func_idx, func_body.code_mut(),
) gas_fn_cost,
.is_err() locals_count,
{ rules,
error = true; gas_func_idx,
break )
});
if result.is_err() {
break 'outer
} }
if rules.memory_grow_cost().enabled() && if rules.memory_grow_cost().enabled() &&
inject_grow_counter(func_body.code_mut(), total_func) > 0 inject_grow_counter(func_body.code_mut(), total_func) > 0
@@ -325,14 +327,12 @@ pub fn inject<R: Rules, B: Backend>(
} }
} }
if error { result.map_err(|_| module)?;
return Err(module)
}
if need_grow_counter { if need_grow_counter {
Ok(add_grow_counter(module, rules, gas_func_idx)) Ok(add_grow_counter(resulting_module, rules, gas_func_idx))
} else { } else {
Ok(module) Ok(resulting_module)
} }
} }
+7 -4
View File
@@ -135,8 +135,12 @@ fn build_control_flow_graph(
let mut stack = vec![ControlFrame::new(entry_node_id, terminal_node_id, false)]; let mut stack = vec![ControlFrame::new(entry_node_id, terminal_node_id, false)];
let mut metered_blocks_iter = blocks.iter().peekable(); 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_count = body
let locals_init_cost = (rules.call_per_local_cost()).checked_mul(locals_count).ok_or(())?; .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() { for (cursor, instruction) in body.code().elements().iter().enumerate() {
let active_node_id = stack let active_node_id = stack
@@ -350,8 +354,7 @@ mod tests {
for func_body in module.code_section().iter().flat_map(|section| section.bodies()) { for func_body in module.code_section().iter().flat_map(|section| section.bodies()) {
let rules = ConstantCostRules::default(); let rules = ConstantCostRules::default();
let locals_count = let locals_count = func_body.locals().iter().map(|val_type| val_type.count()).sum();
func_body.locals().iter().fold(0, |count, val_type| count + val_type.count());
let metered_blocks = let metered_blocks =
determine_metered_blocks(func_body.code(), &rules, locals_count).unwrap(); determine_metered_blocks(func_body.code(), &rules, locals_count).unwrap();