diff --git a/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp b/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp index b2d7dbb98e029..a622cfe441e43 100644 --- a/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp +++ b/crates/sui-adapter-transactional-tests/tests/publish/init_public.exp @@ -1,4 +1,4 @@ processed 2 tasks task 1 'publish'. lines 5-25: -Error: Failed to verify the Move module, reason: "_::M1. 'init' function cannot be public". +Error: Failed to verify the Move module, reason: "_::M1. 'init' function must be private". diff --git a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp b/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp new file mode 100644 index 0000000000000..6be642d8e97bc --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.exp @@ -0,0 +1,4 @@ +processed 1 task + +task 0 'publish'. lines 4-17: +Error: Failed to verify the Move module, reason: "_::M::init at offset 1. Cannot call a module's 'init' function from another Move function". diff --git a/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir b/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir new file mode 100644 index 0000000000000..b557791e08862 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/cannot_call_init.mvir @@ -0,0 +1,17 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: &mut TxContext.TxContext) { + label l0: + abort 0; + } + + public(script) init_again(ctx: &mut TxContext.TxContext) { + label l0: + Self.init(move(ctx)); + return; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp b/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp new file mode 100644 index 0000000000000..0958a599cc726 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_generic.exp @@ -0,0 +1,4 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Failed to verify the Move module, reason: "_::M. 'init' function cannot have type parameters". diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir b/crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir new file mode 100644 index 0000000000000..e3de0beaf5e96 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_generic.mvir @@ -0,0 +1,11 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: &mut TxContext.TxContext) { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_private.exp b/crates/sui-verifier-transactional-tests/tests/init/not_private.exp new file mode 100644 index 0000000000000..acc9ad2e9a796 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_private.exp @@ -0,0 +1,10 @@ +processed 3 tasks + +task 0 'publish'. lines 4-11: +Error: Failed to verify the Move module, reason: "_::M. 'init' function must be private". + +task 1 'publish'. lines 13-20: +Error: Failed to verify the Move module, reason: "_::M. 'init' function must be private". + +task 2 'publish'. lines 22-29: +Error: Failed to verify the Move module, reason: "_::M. 'init' function must be private". diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_private.mvir b/crates/sui-verifier-transactional-tests/tests/init/not_private.mvir new file mode 100644 index 0000000000000..d8581b95a87fd --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_private.mvir @@ -0,0 +1,29 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.M { + import 0x2.TxContext; + public init(ctx: &mut TxContext.TxContext) { + label l0: + abort 0; + } +} + +//# publish +module 0x0.M { + import 0x2.TxContext; + public(script) init(ctx: &mut TxContext.TxContext) { + label l0: + abort 0; + } +} + +//# publish +module 0x0.M { + import 0x2.TxContext; + public(friend) init(ctx: &mut TxContext.TxContext) { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp b/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp new file mode 100644 index 0000000000000..f7d82cb031608 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.exp @@ -0,0 +1,13 @@ +processed 4 tasks + +task 0 'publish'. lines 4-11: +Error: Failed to verify the Move module, reason: "Expected parameter for _::M::init to be &mut mut Sui::TxContext::TxContext, but found u64". + +task 1 'publish'. lines 13-20: +Error: Failed to verify the Move module, reason: "Expected parameter for _::TxContext::init to be &mut mut Sui::TxContext::TxContext, but found _::TxContext::TxContext". + +task 2 'publish'. lines 22-29: +Error: Failed to verify the Move module, reason: "Expected parameter for _::M::init to be &mut mut Sui::TxContext::TxContext, but found &Sui::TxContext::TxContext". + +task 3 'publish'. lines 32-39: +Error: Failed to verify the Move module, reason: "Expected parameter for _::M::init to be &mut mut Sui::TxContext::TxContext, but found Sui::TxContext::TxContext". diff --git a/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir b/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir new file mode 100644 index 0000000000000..80321a66a1193 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/not_txn_context.mvir @@ -0,0 +1,39 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: u64) { + label l0: + abort 0; + } +} + +//# publish +module 0x0.TxContext { + struct TxContext { value: u64 } + init(ctx: Self.TxContext) { + label l0: + abort 0; + } +} + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: &TxContext.TxContext) { + label l0: + abort 0; + } +} + + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: TxContext.TxContext) { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier-transactional-tests/tests/init/public.exp b/crates/sui-verifier-transactional-tests/tests/init/public.exp new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/sui-verifier-transactional-tests/tests/init/return_values.exp b/crates/sui-verifier-transactional-tests/tests/init/return_values.exp new file mode 100644 index 0000000000000..9b158dfd5c1b5 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/return_values.exp @@ -0,0 +1,4 @@ +processed 1 task + +task 0 'publish'. lines 4-11: +Error: Failed to verify the Move module, reason: "_::M, 'init' function cannot have return values". diff --git a/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir b/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir new file mode 100644 index 0000000000000..56db67df28372 --- /dev/null +++ b/crates/sui-verifier-transactional-tests/tests/init/return_values.mvir @@ -0,0 +1,11 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//# publish +module 0x0.M { + import 0x2.TxContext; + init(ctx: &mut TxContext.TxContext): u64 { + label l0: + abort 0; + } +} diff --git a/crates/sui-verifier/src/entry_points_verifier.rs b/crates/sui-verifier/src/entry_points_verifier.rs index 9fd3cc536a622..8308f0881a3f3 100644 --- a/crates/sui-verifier/src/entry_points_verifier.rs +++ b/crates/sui-verifier/src/entry_points_verifier.rs @@ -4,7 +4,7 @@ use move_binary_format::{ access::ModuleAccess, binary_views::BinaryIndexedView, - file_format::{AbilitySet, FunctionDefinition, SignatureToken, Visibility}, + file_format::{AbilitySet, Bytecode, FunctionDefinition, SignatureToken, Visibility}, CompiledModule, }; use move_core_types::{account_address::AccountAddress, ident_str, identifier::IdentStr}; @@ -38,6 +38,9 @@ pub const INIT_FN_NAME: &IdentStr = ident_str!("init"); /// - The function cannot have any return values pub fn verify_module(module: &CompiledModule) -> SuiResult { for func_def in &module.function_defs { + verify_init_not_called(module, func_def) + .map_err(|error| SuiError::ModuleVerificationFailure { error })?; + let handle = module.function_handle_at(func_def.function); let name = module.identifier_at(handle.name); if name == INIT_FN_NAME { @@ -59,13 +62,48 @@ pub fn verify_module(module: &CompiledModule) -> SuiResult { Ok(()) } +fn verify_init_not_called( + module: &CompiledModule, + fdef: &FunctionDefinition, +) -> Result<(), String> { + let code = match &fdef.code { + None => return Ok(()), + Some(code) => code, + }; + code.code + .iter() + .enumerate() + .filter_map(|(idx, instr)| match instr { + Bytecode::Call(fhandle_idx) => Some((idx, module.function_handle_at(*fhandle_idx))), + Bytecode::CallGeneric(finst_idx) => { + let finst = module.function_instantiation_at(*finst_idx); + Some((idx, module.function_handle_at(finst.handle))) + } + _ => None, + }) + .try_for_each(|(idx, fhandle)| { + let name = module.identifier_at(fhandle.name); + if name == INIT_FN_NAME { + Err(format!( + "{}::{} at offset {}. Cannot call a module's '{}' function from another Move function", + module.self_id(), + name, + idx, + INIT_FN_NAME + )) + } else { + Ok(()) + } + }) +} + /// Checks if this module has a conformant `init` fn verify_init_function(module: &CompiledModule, fdef: &FunctionDefinition) -> Result<(), String> { let view = &BinaryIndexedView::Module(module); if fdef.visibility != Visibility::Private { return Err(format!( - "{}. '{}' function cannot be public", + "{}. '{}' function must be private", module.self_id(), INIT_FN_NAME ));