Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

properly align all fields in vm offsets #9063

Merged
2 changes: 1 addition & 1 deletion runtime/near-vm-runner/src/near_vm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl NearVmConfig {
// major version << 6
// minor version
const VM_CONFIG: NearVmConfig = NearVmConfig {
seed: (2 << 10) | (1 << 6) | 0,
seed: (2 << 10) | (1 << 6) | 1,
engine: NearVmEngine::Universal,
compiler: NearVmCompiler::Singlepass,
};
Expand Down
1 change: 1 addition & 0 deletions runtime/near-vm-runner/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod cache;
mod compile_errors;
mod fuzzers;
mod regression_tests;
mod rs_contract;
mod runtime_errors;
pub(crate) mod test_builder;
Expand Down
26 changes: 26 additions & 0 deletions runtime/near-vm-runner/src/tests/regression_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::tests::test_builder::test_builder;
use expect_test::expect;

#[test]
fn memory_size_alignment_issue() {
test_builder()
.wat(
r#"
(module
(type (;0;) (func))
(func (;0;) (type 0)
memory.size
drop
)
(memory (;0;) 1 1024)
(export "foo" (func 0))
)
"#,
)
.method("foo")
.expects(&[
expect![[r#"
VMOutcome: balance 4 storage_usage 12 return data None burnt gas 46411725 used gas 46411725
"#]],
]);
}
8 changes: 7 additions & 1 deletion runtime/near-vm/vm/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,13 @@ impl Instance {
/// Return the indexed `VMMemoryImport`.
fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { &*self.imported_memories_ptr().add(index) }
let addr = unsafe { self.imported_memories_ptr().add(index) };
let align = std::mem::align_of::<VMMemoryImport>();
debug_assert!(
addr as usize % align == 0,
"VMMemoryImport addr is not aligned to {align}: {addr:p}"
);
unsafe { &*addr }
}

/// Return a pointer to the `VMMemoryImport`s.
Expand Down
43 changes: 32 additions & 11 deletions runtime/near-vm/vm/src/vmoffsets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,67 +159,88 @@ impl VMOffsets {
}

fn precompute(&mut self) {
use std::mem::align_of;

/// Offset base by num_items items of size item_size, panicking on overflow
fn offset_by(base: u32, num_items: u32, item_size: u32) -> u32 {
base.checked_add(num_items.checked_mul(item_size).unwrap()).unwrap()
fn offset_by(
base: u32,
num_items: u32,
prev_item_size: u32,
next_item_align: usize,
) -> u32 {
align(
base.checked_add(num_items.checked_mul(prev_item_size).unwrap()).unwrap(),
next_item_align as u32,
)
}

self.vmctx_signature_ids_begin = 0;
self.vmctx_imported_functions_begin = offset_by(
self.vmctx_signature_ids_begin,
self.num_signature_ids,
u32::from(self.size_of_vmshared_signature_index()),
align_of::<crate::VMFunctionImport>(),
);
self.vmctx_imported_tables_begin = offset_by(
self.vmctx_imported_functions_begin,
self.num_imported_functions,
u32::from(self.size_of_vmfunction_import()),
align_of::<crate::VMTableImport>(),
);
self.vmctx_imported_memories_begin = offset_by(
self.vmctx_imported_tables_begin,
self.num_imported_tables,
u32::from(self.size_of_vmtable_import()),
align_of::<crate::VMMemoryImport>(),
);
self.vmctx_imported_globals_begin = offset_by(
self.vmctx_imported_memories_begin,
self.num_imported_memories,
u32::from(self.size_of_vmmemory_import()),
align_of::<crate::VMGlobalImport>(),
);
self.vmctx_tables_begin = offset_by(
self.vmctx_imported_globals_begin,
self.num_imported_globals,
u32::from(self.size_of_vmglobal_import()),
align_of::<crate::VMTableImport>(),
);
self.vmctx_memories_begin = offset_by(
self.vmctx_tables_begin,
self.num_local_tables,
u32::from(self.size_of_vmtable_definition()),
align_of::<crate::VMMemoryDefinition>(),
);
self.vmctx_globals_begin = align(
offset_by(
self.vmctx_memories_begin,
self.num_local_memories,
u32::from(self.size_of_vmmemory_definition()),
),
16,
self.vmctx_globals_begin = offset_by(
self.vmctx_memories_begin,
self.num_local_memories,
u32::from(self.size_of_vmmemory_definition()),
align_of::<crate::VMGlobalDefinition>(),
);
self.vmctx_builtin_functions_begin = offset_by(
self.vmctx_globals_begin,
self.num_local_globals,
u32::from(self.size_of_vmglobal_local()),
align_of::<crate::vmcontext::VMBuiltinFunctionsArray>(),
);
self.vmctx_trap_handler_begin = offset_by(
self.vmctx_builtin_functions_begin,
VMBuiltinFunctionIndex::builtin_functions_total_number(),
u32::from(self.pointer_size),
align_of::<fn()>(),
);
self.vmctx_gas_limiter_pointer = offset_by(
self.vmctx_trap_handler_begin,
if self.has_trap_handlers { 1 } else { 0 },
u32::from(self.pointer_size),
align_of::<*mut near_vm_types::FastGasCounter>(),
);
self.vmctx_stack_limit_begin = offset_by(
self.vmctx_gas_limiter_pointer,
1,
u32::from(self.pointer_size),
align_of::<u32>(),
);
self.vmctx_stack_limit_begin =
offset_by(self.vmctx_gas_limiter_pointer, 1, u32::from(self.pointer_size));
self.vmctx_stack_limit_initial_begin = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
self.size_of_vmctx = self.vmctx_stack_limit_begin.checked_add(4).unwrap();
}
Expand Down