diff --git a/Cargo.lock b/Cargo.lock index 4dbbda5098..febfdf99a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3703,6 +3703,7 @@ name = "move-vm-integration-tests" version = "0.1.0" dependencies = [ "anyhow", + "bcs", "memory-stats", "move-binary-format", "move-bytecode-verifier", @@ -3713,6 +3714,7 @@ dependencies = [ "move-vm-runtime", "move-vm-test-utils", "move-vm-types", + "once_cell", "tempfile", ] diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/signature_tests.rs b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/signature_tests.rs index 8ca82bd08a..30ebd02d48 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/signature_tests.rs +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/signature_tests.rs @@ -230,6 +230,8 @@ fn big_signature_test() { max_fields_in_struct: Some(30), max_function_definitions: Some(1000), max_constant_vector_len: MAX_CONSTANT_VECTOR_LEN, + max_type_instantiation_size: Some(128), + max_function_instantiation_size: Some(128), }, &module, ) diff --git a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/vec_pack_tests.rs b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/vec_pack_tests.rs index 419f62b411..f9a19be5dd 100644 --- a/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/vec_pack_tests.rs +++ b/language/move-bytecode-verifier/bytecode-verifier-tests/src/unit_tests/vec_pack_tests.rs @@ -73,6 +73,7 @@ fn test_vec_pack() { max_fields_in_struct: Some(30), max_function_definitions: Some(1000), max_constant_vector_len: MAX_CONSTANT_VECTOR_LEN, + ..Default::default() }, &m, ) diff --git a/language/move-bytecode-verifier/src/verifier.rs b/language/move-bytecode-verifier/src/verifier.rs index b34e579b21..6998457d9a 100644 --- a/language/move-bytecode-verifier/src/verifier.rs +++ b/language/move-bytecode-verifier/src/verifier.rs @@ -34,6 +34,11 @@ pub struct VerifierConfig { pub max_fields_in_struct: Option, pub max_function_definitions: Option, pub max_constant_vector_len: u64, + // Max number of nodes which are allowed when instantiating a generic type. + // This does not include field types of structs. + pub max_type_instantiation_size: Option, + // Max number of nodes which are allowed when instantiating a generic function. + pub max_function_instantiation_size: Option, } /// Helper for a "canonical" verification of a module. @@ -144,6 +149,8 @@ impl Default for VerifierConfig { max_function_definitions: None, // Max len of vector constant max_constant_vector_len: MAX_CONSTANT_VECTOR_LEN, + max_type_instantiation_size: None, + max_function_instantiation_size: None, } } } diff --git a/language/move-vm/integration-tests/Cargo.toml b/language/move-vm/integration-tests/Cargo.toml index 343e4e15de..7aa89664bc 100644 --- a/language/move-vm/integration-tests/Cargo.toml +++ b/language/move-vm/integration-tests/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" [dependencies] anyhow = "1.0.52" +once_cell = "1.7.2" tempfile = "3.2.0" memory-stats = "1.0.0" @@ -26,6 +27,8 @@ move-vm-test-utils = { path = "../test-utils" } move-stdlib = { path = "../../move-stdlib" } move-table-extension = { path = "../../extensions/move-table-extension", optional = true } +bcs.workspace = true + [features] default = [] table-extension = [ diff --git a/language/move-vm/integration-tests/src/tests/limits_tests.rs b/language/move-vm/integration-tests/src/tests/limits_tests.rs new file mode 100644 index 0000000000..ce284c7933 --- /dev/null +++ b/language/move-vm/integration-tests/src/tests/limits_tests.rs @@ -0,0 +1,2788 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +#![allow(dead_code)] +#![allow(unused_must_use)] +#![allow(unused_imports)] + +use move_binary_format::{ + errors::VMResult, + file_format::{ + AbilitySet, AddressIdentifierIndex, Bytecode, Bytecode::*, CodeUnit, CompiledModule, + Constant, ConstantPoolIndex, FieldDefinition, FunctionDefinition, FunctionHandle, + FunctionHandleIndex, FunctionInstantiation, FunctionInstantiationIndex, IdentifierIndex, + ModuleHandle, ModuleHandleIndex, Signature, SignatureIndex, SignatureToken, + SignatureToken::*, StructDefInstantiation, StructDefInstantiationIndex, StructDefinition, + StructDefinitionIndex, StructFieldInformation, StructHandle, StructHandleIndex, + StructTypeParameter, TypeSignature, Visibility::*, + }, +}; +use move_bytecode_verifier::{verify_module, VerifierConfig}; +use move_core_types::{ + account_address::AccountAddress, + identifier::{IdentStr, Identifier}, + language_storage::{ModuleId, StructTag, TypeTag}, + vm_status::StatusCode, +}; +use move_vm_runtime::{ + config::VMConfig, + move_vm::MoveVM, + session::{SerializedReturnValues, Session}, +}; +use move_vm_test_utils::{ + gas_schedule::{Gas, GasStatus, INITIAL_COST_SCHEDULE}, + InMemoryStorage, +}; +use move_vm_types::loaded_data::runtime_types::Type; +use once_cell::sync::Lazy; +use std::time::Instant; + +const MODULE_NAME: &str = "Mod"; +const OUTER_NAME: &str = "Outer"; +const INNER_NAME: &str = "Inner"; +const FIELD_NAME: &str = "inner"; +const ENTRY_POINT_NAME_1: &str = "entry_point"; +const ENTRY_POINT_NAME_2: &str = "entry_point_one_ty_arg"; +const ENTRY_POINT_NAME_3: &str = "entry_point_mul_ty_args"; + +const RECURSIVE_NAME: &str = "recursive"; +const EMPTY_NAME: &str = "empty"; + +static DEFAULT_SIGNATURES: Lazy> = + Lazy::new(|| vec![Signature(vec![]), Signature(vec![TypeParameter(0)])]); + +#[test] +fn test_limit_vector() { + let verifier = VerifierConfig { + max_type_instantiation_size: Some(128), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_2_nodes); + res.expect("max_type_instantiation_size(128) vector_instantiated_2_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_4_nodes); + res.expect("max_type_instantiation_size(128) vector_instantiated_4_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_6_nodes); + res.expect("max_type_instantiation_size(128) vector_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + res.expect("max_type_instantiation_size(128) vector_instantiated_51_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_2_nodes); + res.expect("max_type_instantiation_size(128) vector_single_type_arg_2_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_4_nodes); + res.expect("max_type_instantiation_size(128) vector_single_type_arg_4_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(128) vector_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(128) vector_single_type_arg_51_nodes failed"); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_6_nodes); + res.expect("max_type_instantiation_size(128) vector_mul_type_args_6_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(128) vector_mul_type_args_51_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + res.expect("max_type_instantiation_size(128) vector_mul_type_args_51_nodes_mix failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(60), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_2_nodes); + res.expect("max_type_instantiation_size(60) vector_instantiated_2_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_4_nodes); + res.expect("max_type_instantiation_size(60) vector_instantiated_4_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_6_nodes); + res.expect("max_type_instantiation_size(60) vector_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + res.expect("max_type_instantiation_size(60) vector_instantiated_51_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_2_nodes); + res.expect("max_type_instantiation_size(60) vector_single_type_arg_2_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_4_nodes); + res.expect("max_type_instantiation_size(60) vector_single_type_arg_4_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(60) vector_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(60) vector_single_type_arg_51_nodes failed"); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_6_nodes); + res.expect("max_type_instantiation_size(60) vector_mul_type_args_6_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(60) vector_mul_type_args_51_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + res.expect("max_type_instantiation_size(60) vector_mul_type_args_51_nodes_mix failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(52), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + res.expect("max_type_instantiation_size(52) vector_instantiated_51_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(52) vector_single_type_arg_51_nodes failed"); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(52) vector_mul_type_args_51_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + res.expect("max_type_instantiation_size(52) vector_mul_type_args_51_nodes_mix failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(51), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + res.expect("max_type_instantiation_size(51) vector_instantiated_51_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(51) vector_single_type_arg_51_nodes failed"); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(51) vector_mul_type_args_51_nodes failed"); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + res.expect("max_type_instantiation_size(51) vector_mul_type_args_51_nodes_mix failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(50), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) vector_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) vector_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) vector_mul_type_args_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + let err = res + .expect_err("max_type_instantiation_size(50) vector_mul_type_args_51_nodes_mix must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(4), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, vector_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(4) vector_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(4) vector_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_instantiated_4_nodes); + res.expect("max_type_instantiation_size(4) vector_instantiated_4_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, vector_single_type_arg_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(4) vector_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_single_type_arg_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(4) vector_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_single_type_arg_4_nodes); + res.expect("max_type_instantiation_size(4) vector_single_type_arg_4_nodes failed"); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, vector_mul_type_args_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(4) vector_mul_type_args_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_mul_type_args_51_nodes_mix); + let err = res + .expect_err("max_type_instantiation_size(50) vector_mul_type_args_51_nodes_mix must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(2), + ..Default::default() + }; + let res = run_with_module(&verifier, vector_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(2) vector_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, vector_instantiated_4_nodes); + let err = + res.expect_err("max_type_instantiation_size(2) vector_instantiated_4_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(6), + ..Default::default() + }; + let res = run_with_module(&verifier, vector_mul_type_args_6_nodes); + res.expect("max_type_instantiation_size(5) vector_mul_type_args_6_nodes failed"); +} + +#[test] +fn test_limit_global_ops() { + let verifier = VerifierConfig { + max_type_instantiation_size: Some(1000), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, mut_borrow_instantiated_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) mut_borrow_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_instantiated_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) imm_borrow_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_2_nodes); + res.expect("max_type_instantiation_size(1000) exists_instantiated_2_nodes failed"); + let res = run_with_module(&verifier, move_from_instantiated_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) move_from_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_instantiated_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) mut_borrow_instantiated_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_instantiated_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) imm_borrow_instantiated_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_6_nodes); + res.expect("max_type_instantiation_size(1000) exists_instantiated_6_node failed"); + let res = run_with_module(&verifier, move_from_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(1000) move_from_instantiated_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) mut_borrow_instantiated_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) imm_borrow_instantiated_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_51_nodes); + res.expect("max_type_instantiation_size(1000) exists_instantiated_51_node failed"); + let res = run_with_module(&verifier, move_from_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) move_from_instantiated_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, mut_borrow_single_type_arg_2_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) mut_borrow_single_type_arg_2_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_2_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) imm_borrow_single_type_arg_2_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_single_type_arg_2_nodes); + res.expect("max_type_instantiation_size(1000) exists_single_type_arg_2_nodes failed"); + let res = run_with_module(&verifier, move_from_single_type_arg_2_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) move_from_single_type_arg_2_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_single_type_arg_6_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) mut_borrow_single_type_arg_6_node must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_6_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) imm_borrow_single_type_arg_6_node must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(1000) exists_single_type_arg_6_node failed"); + let res = run_with_module(&verifier, move_from_single_type_arg_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) move_from_single_type_arg_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) mut_borrow_single_type_arg_51_node must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) imm_borrow_single_type_arg_51_node must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(1000) exists_single_type_arg_51_node failed"); + let res = run_with_module(&verifier, move_from_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(1000) move_from_single_type_arg_51_node must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + // instantiated via complex/rich function type parameter + let res = run_with_module(&verifier, mut_borrow_mul_type_args_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) mut_borrow_mul_type_args_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) imm_borrow_mul_type_args_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_mul_type_args_6_nodes); + res.expect("max_type_instantiation_size(1000) exists_mul_type_args_6_node failed"); + let res = run_with_module(&verifier, move_from_mul_type_args_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) move_from_mul_type_args_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_mul_type_args_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) mut_borrow_mul_type_args_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) imm_borrow_mul_type_args_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(1000) exists_mul_type_args_51_node failed"); + let res = run_with_module(&verifier, move_from_mul_type_args_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(1000) move_from_mul_type_args_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(1000) mut_borrow_mul_type_args_51_node_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(1000) imm_borrow_mul_type_args_51_node_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_mul_type_args_51_nodes_mix); + res.expect("max_type_instantiation_size(1000) exists_mul_type_args_51_node_mix failed"); + let res = run_with_module(&verifier, move_from_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(1000) move_from_mul_type_args_51_node_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(60), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, exists_instantiated_2_nodes); + res.expect("max_type_instantiation_size(60) exists_instantiated_2_nodes failed"); + let res = run_with_module(&verifier, imm_borrow_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(60) imm_borrow_instantiated_6_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, move_from_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(60) move_from_instantiated_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, move_from_single_type_arg_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(60) move_from_single_type_arg_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(60) exists_single_type_arg_6_node failed"); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(60) imm_borrow_single_type_arg_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_single_type_arg_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(60) imm_borrow_single_type_arg_51_node must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_mul_type_args_6_nodes); + res.expect("max_type_instantiation_size(60) exists_mul_type_args_6_nodes failed"); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(60) imm_borrow_mul_type_args_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, move_from_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(60) move_from_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(52), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, mut_borrow_instantiated_2_nodes); + let err = + res.expect_err("max_type_instantiation_size(52) mut_borrow_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, move_from_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(52) move_from_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_51_nodes); + res.expect("max_type_instantiation_size(52) exists_instantiated_51_nodes failed"); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, move_from_single_type_arg_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(52) move_from_single_type_arg_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(52) imm_borrow_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(52) exists_single_type_arg_51_nodes failed"); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(52) imm_borrow_mul_type_args_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, move_from_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(52) move_from_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(51), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, mut_borrow_instantiated_2_nodes); + let err = + res.expect_err("max_type_instantiation_size(51) mut_borrow_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_51_nodes); + res.expect("max_type_instantiation_size(51) exists_instantiated_51_nodes failed"); + let res = run_with_module(&verifier, move_from_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(51) move_from_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, imm_borrow_single_type_arg_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(51) imm_borrow_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, move_from_single_type_arg_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(51) move_from_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(51) imm_borrow_single_type_arg_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_mul_type_args_51_nodes); + res.expect("max_type_instantiation_size(51) exists_mul_type_args_51_nodes failed"); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(51) imm_borrow_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(50), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, move_from_instantiated_2_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) move_from_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, exists_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) exists_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, move_from_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) move_from_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, mut_borrow_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(50) mut_borrow_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, mut_borrow_single_type_arg_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(50) mut_borrow_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) imm_borrow_single_type_arg_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, mut_borrow_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) mut_borrow_single_type_arg_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_single_type_arg_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) exists_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_mul_type_args_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(50) exists_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, mut_borrow_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(51) mut_borrow_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, move_from_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(51) move_from_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(5), + ..Default::default() + }; + let res = run_with_module(&verifier, exists_instantiated_2_nodes); + res.expect("max_type_instantiation_size(51) exists_instantiated_2_nodes failed"); + let res = run_with_module(&verifier, imm_borrow_instantiated_2_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) imm_borrow_instantiated_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, mut_borrow_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) mut_borrow_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, move_from_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) move_from_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_instantiated_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) exists_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_instantiated_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) exists_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + // instantiated over simple function type parameter + let res = run_with_module(&verifier, move_from_single_type_arg_2_nodes); + let err = res + .expect_err("max_type_instantiation_size(5) move_from_single_type_arg_2_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::MISSING_DATA); + let res = run_with_module(&verifier, imm_borrow_single_type_arg_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(5) imm_borrow_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_single_type_arg_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) exists_single_type_arg_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, exists_single_type_arg_51_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) exists_single_type_arg_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, mut_borrow_mul_type_args_6_nodes); + let err = + res.expect_err("max_type_instantiation_size(5) mut_borrow_mul_type_args_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, imm_borrow_mul_type_args_51_nodes_mix); + let err = res.expect_err( + "max_type_instantiation_size(5) imm_borrow_mul_type_args_51_nodes_mix must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); +} + +#[test] +fn test_pack_generic() { + let verifier = VerifierConfig { + max_type_instantiation_size: Some(80), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, pack_generic_instantiated_6_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_instantiated_51_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_instantiated_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_single_type_arg_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_6_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_multi_type_args_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_51_nodes); + res.expect("max_type_instantiation_size(80) pack_generic_multi_type_args_51_nodes failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(52), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, pack_generic_instantiated_6_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_instantiated_51_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_instantiated_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_single_type_arg_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_6_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_multi_type_args_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_51_nodes); + res.expect("max_type_instantiation_size(52) pack_generic_multi_type_args_51_nodes failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(51), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, pack_generic_instantiated_6_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_instantiated_51_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_instantiated_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_51_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_single_type_arg_51_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_6_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_multi_type_args_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_51_nodes); + res.expect("max_type_instantiation_size(51) pack_generic_multi_type_args_51_nodes failed"); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(50), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, pack_generic_instantiated_6_nodes); + res.expect("max_type_instantiation_size(50) pack_generic_instantiated_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(50) pack_generic_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_single_type_arg_6_nodes); + res.expect("max_type_instantiation_size(50) pack_generic_single_type_arg_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) pack_generic_single_type_arg_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_multi_type_args_6_nodes); + res.expect("max_type_instantiation_size(50) pack_generic_multi_type_args_6_nodes failed"); + let res = run_with_module(&verifier, pack_generic_multi_type_args_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) pack_generic_multi_type_args_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + + let verifier = VerifierConfig { + max_type_instantiation_size: Some(5), + ..Default::default() + }; + // instantiated tests + let res = run_with_module(&verifier, pack_generic_instantiated_6_nodes); + let err = res + .expect_err("max_type_instantiation_size(5) pack_generic_instantiated_6_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_instantiated_51_nodes); + let err = res + .expect_err("max_type_instantiation_size(5) pack_generic_instantiated_51_nodes must fail"); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_single_type_arg_6_nodes); + let err = res.expect_err( + "max_type_instantiation_size(5) pack_generic_single_type_arg_6_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_single_type_arg_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(5) pack_generic_single_type_arg_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_multi_type_args_6_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) pack_generic_multi_type_args_6_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); + let res = run_with_module(&verifier, pack_generic_multi_type_args_51_nodes); + let err = res.expect_err( + "max_type_instantiation_size(50) pack_generic_multi_type_args_51_nodes must fail", + ); + assert_eq!(err.major_status(), StatusCode::VERIFICATION_ERROR); +} + +#[test] +fn test_call_generic() { + let verifier = VerifierConfig { + max_function_instantiation_size: Some(50), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_1_2); + res.expect("max_function_instantiation_size(50) call_instantiated_1_2 failed"); + let res = run_with_module(&verifier, call_instantiated_6_6); + res.expect("max_function_instantiation_size(50) call_instantiated_6_6 failed"); + let res = run_with_module(&verifier, call_instantiated_11_31); + res.expect("max_function_instantiation_size(50) call_instantiated_11_31 failed"); + let res = run_with_module(&verifier, call_single_type_arg_11_31); + res.expect("max_function_instantiation_size(50) call_single_tye_arg_11_31 failed"); + let res = run_with_module(&verifier, call_multi_type_args_11_31); + res.expect("max_function_instantiation_size(50) call_multi_type_args_11_31 failed"); + + let verifier = VerifierConfig { + max_function_instantiation_size: Some(42), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_1_2); + res.expect("max_function_instantiation_size(42) call_instantiated_1_2 failed"); + let res = run_with_module(&verifier, call_instantiated_11_31); + res.expect("max_function_instantiation_size(42) call_instantiated_11_31 failed"); + let res = run_with_module(&verifier, call_single_type_arg_11_31); + res.expect("max_function_instantiation_size(42) call_single_tye_arg_11_31 failed"); + let res = run_with_module(&verifier, call_multi_type_args_11_31); + res.expect("max_function_instantiation_size(42) call_multi_type_args_11_31 failed"); + + let verifier = VerifierConfig { + max_function_instantiation_size: Some(41), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_6_6); + res.expect("max_function_instantiation_size(41) call_instantiated_6_6 failed"); + let res = run_with_module(&verifier, call_instantiated_11_31); + let err = res.expect_err("max_type_instantiation_size(41) call_instantiated_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + + let verifier = VerifierConfig { + max_function_instantiation_size: Some(40), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_11_31); + let err = res.expect_err("max_type_instantiation_size(40) call_instantiated_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_single_type_arg_11_31); + let err = res.expect_err("max_type_instantiation_size(40) call_single_tye_arg_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_multi_type_args_11_31); + let err = + res.expect_err("max_type_instantiation_size(40) call_multi_type_args_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + + let verifier = VerifierConfig { + max_function_instantiation_size: Some(30), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_11_31); + let err = res.expect_err("max_type_instantiation_size(40) call_instantiated_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_single_type_arg_11_31); + let err = res.expect_err("max_type_instantiation_size(40) call_single_tye_arg_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_multi_type_args_11_31); + let err = + res.expect_err("max_type_instantiation_size(40) call_multi_type_args_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + + let verifier = VerifierConfig { + max_function_instantiation_size: Some(10), + ..Default::default() + }; + let res = run_with_module(&verifier, call_instantiated_11_31); + let err = res.expect_err("max_type_instantiation_size(10) call_instantiated_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_single_type_arg_11_31); + let err = res.expect_err("max_type_instantiation_size(10) call_single_tye_arg_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = run_with_module(&verifier, call_multi_type_args_11_31); + let err = + res.expect_err("max_type_instantiation_size(10) call_multi_type_args_11_31 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); +} + +#[test] +fn test_call_generic_type_error() { + let verifier = VerifierConfig { + max_type_instantiation_size: Some(10), + ..Default::default() + }; + let res = call_vector_arg_9(&verifier); + res.expect("max_function_instantiation_size(10) call_vector_arg_9 failed"); + let res = call_vector_arg_10(&verifier); + res.expect("max_function_instantiation_size(10) call_vector_arg_10 failed"); + let res = call_vector_arg_11(&verifier); + let err = res.expect_err("max_type_instantiation_size(10) call_vector_arg_11 must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); + let res = call_generic_arg(&verifier, 8); + res.expect("max_function_instantiation_size(10) call_generic_arg 9 args failed"); + let res = call_generic_arg(&verifier, 9); + res.expect("max_function_instantiation_size(10) call_generic_arg 10 args failed"); + let res = call_generic_arg(&verifier, 10); + let err = res.expect_err("max_type_instantiation_size(10) call_generic_arg 11 args must fail"); + assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); +} + +// Generate a verifiable module with code that can be used to test instantiations. +// The code is generated by the different tests. +// Provide 2 structs and 3 functions and allow customization of structs and functions +// to test instantiations. +// The 2 structs have the following shape +// struct Outer { inner: vector } +// struct Inner { field1: X, field2: Y, ..., field(n): Z } +// so that an instance of the Outer struct can be created with an empty vector +// and tests for complex instantiation can be built. +// The number of type parameters for Inner is defined by `struct_type_args_count`. +// The 3 functions have the following signature +// fun entry_point() { ... } +// fun entry_point_one_ty_arg() { ... } +// fun entry_point_mul_ty_args() { ... } +// The number of type parameters for entry_point_mul_ty_args is defined by `fun_type_args_count`. +// Definitions for the 3 functions is provided via `acquires` and `code`, where the content +// of each function is provided in inverse order, so +// [entry_point_mul_ty_args, entry_point_one_ty_arg, entry_point]. +// Other aspects of the module are defined in the arguments following `code`. +// +// Please see usage in test to familiarize with how this function is used. +fn make_module( + session: &mut Session, + addr: AccountAddress, + struct_type_args_count: usize, + fun_type_args_count: usize, + mut acquires: Vec>, + mut code: Vec>, + mut parameters: Vec, + mut locals: Vec, + signatures: Vec, + struct_def_instantiations: Vec, + function_instantiations: Vec, +) -> ModuleId { + // default identifiers + let mut identifiers = vec![ + Identifier::new(MODULE_NAME).unwrap(), + Identifier::new(OUTER_NAME).unwrap(), + Identifier::new(INNER_NAME).unwrap(), + Identifier::new(FIELD_NAME).unwrap(), + Identifier::new(ENTRY_POINT_NAME_1).unwrap(), + Identifier::new(ENTRY_POINT_NAME_2).unwrap(), + Identifier::new(ENTRY_POINT_NAME_3).unwrap(), + ]; + + // define one field for each generic parameter, e.g. + // struct S { field_0: T, field_1: W } + let mut field_defs = vec![]; + for idx in 0..struct_type_args_count { + identifiers.push(Identifier::new(format!("field_{}", idx).as_str()).unwrap()); + let id_idx = identifiers.len() - 1; + field_defs.push(FieldDefinition { + name: IdentifierIndex(id_idx as u16), + signature: TypeSignature(TypeParameter(idx as u16)), + }); + } + let fields = StructFieldInformation::Declared(field_defs); + + let module = CompiledModule { + version: 6, + // Module definition + self_module_handle_idx: ModuleHandleIndex(0), + module_handles: vec![ModuleHandle { + address: AddressIdentifierIndex(0), + name: IdentifierIndex(0), + }], + // struct definition + struct_handles: vec![ + StructHandle { + module: ModuleHandleIndex(0), + name: IdentifierIndex(1), + abilities: AbilitySet::ALL, + type_parameters: vec![StructTypeParameter { + constraints: AbilitySet::EMPTY, + is_phantom: false, + }], + }, + StructHandle { + module: ModuleHandleIndex(0), + name: IdentifierIndex(2), + abilities: AbilitySet::ALL, + type_parameters: vec![ + StructTypeParameter { + constraints: AbilitySet::EMPTY, + is_phantom: false, + }; + struct_type_args_count + ], + }, + ], + struct_defs: vec![ + // struct Outer { inner: vector; } + // defines a struct that mimics an `Option` field. + // It allows for the easy creation of complex generic instance without + // having to build the instance. E.g. + // struct Outer>> and so + // let outer = Outer { inner: vector[], }; + // move_to<...>(addr, outer); // or other bytecodes + // which results in the ability to test different instantiations at runtime + StructDefinition { + struct_handle: StructHandleIndex(0), + field_information: StructFieldInformation::Declared(vec![FieldDefinition { + name: IdentifierIndex(3), + signature: TypeSignature(Vector(Box::new(TypeParameter(0)))), + }]), + }, + // struct Inner { field1: T field2: W, ..., field3: Z; } + // allows checks of field instantiations instructions + StructDefinition { + struct_handle: StructHandleIndex(1), + field_information: fields, + }, + ], + // function definition + function_handles: vec![ + // fun entry_point() + FunctionHandle { + module: ModuleHandleIndex(0), + name: IdentifierIndex(4), + parameters: parameters.pop().unwrap(), + return_: SignatureIndex(0), + type_parameters: vec![], + }, + // fun entry_point_one_ty_arg() + FunctionHandle { + module: ModuleHandleIndex(0), + name: IdentifierIndex(5), + parameters: parameters.pop().unwrap(), + return_: SignatureIndex(0), + type_parameters: vec![AbilitySet::VECTOR], + }, + // fun entry_point_mul_ty_args() + // for `fun_type_args_count` args + FunctionHandle { + module: ModuleHandleIndex(0), + name: IdentifierIndex(6), + parameters: parameters.pop().unwrap(), + return_: SignatureIndex(0), + type_parameters: vec![AbilitySet::VECTOR; fun_type_args_count], + }, + ], + function_defs: vec![ + FunctionDefinition { + function: FunctionHandleIndex(0), + visibility: Public, + is_entry: true, + acquires_global_resources: acquires.pop().unwrap(), + code: Some(CodeUnit { + locals: locals.pop().unwrap(), + code: code.pop().unwrap(), + }), + }, + FunctionDefinition { + function: FunctionHandleIndex(1), + visibility: Public, + is_entry: true, + acquires_global_resources: acquires.pop().unwrap(), + code: Some(CodeUnit { + locals: locals.pop().unwrap(), + code: code.pop().unwrap(), + }), + }, + FunctionDefinition { + function: FunctionHandleIndex(2), + visibility: Public, + is_entry: true, + acquires_global_resources: acquires.pop().unwrap(), + code: Some(CodeUnit { + locals: locals.pop().unwrap(), + code: code.pop().unwrap(), + }), + }, + ], + // addresses + address_identifiers: vec![addr], + // identifiers + identifiers, + // constants + constant_pool: vec![Constant { + type_: Address, + data: addr.to_vec(), + }], + // signatures + signatures, + // struct instantiations + struct_def_instantiations, + // function instantiations + function_instantiations, + // unused... + field_handles: vec![], + friend_decls: vec![], + field_instantiations: vec![], + metadata: vec![], + }; + // uncomment to see the module generated + // println!("Module: {:#?}", module); + let res = verify_module(&module); + if let Err(err) = res { + println!("Error {:?}", err); + println!("{:#?}", module); + panic!("Verification Error"); + } + + let mut mod_bytes = vec![]; + module + .serialize(&mut mod_bytes) + .expect("Module must serialize"); + session + .publish_module(mod_bytes, addr, &mut GasStatus::new_unmetered()) + .expect("Module must publish"); + module.self_id() +} + +// Generic function to run some code. Take few arguments and a closure +// that can return an entry point to call. +// This function creates a VM, invokes the closure, and on return it builds the call +// for the entry point. +fn run_with_module( + verifier: &VerifierConfig, + entry_spec: fn( + AccountAddress, + &mut Session, + ) -> (ModuleId, Identifier, Vec), +) -> VMResult { + let addr = AccountAddress::from_hex_literal("0xcafe").unwrap(); + + let vm = MoveVM::new_with_config( + vec![], + VMConfig { + verifier: verifier.clone(), + ..Default::default() + }, + ) + .unwrap(); + let storage: InMemoryStorage = InMemoryStorage::new(); + let mut session = vm.new_session(&storage); + + let (module_id, entry_name, type_args) = entry_spec(addr, &mut session); + + let mut gas = GasStatus::new_unmetered(); + session.execute_entry_function( + &module_id, + entry_name.as_ref(), + type_args, + Vec::>::new(), + &mut gas, + ) +} + +// +// Vector tests +// + +fn get_vector_ops(sig_idx: usize) -> Vec { + let vec = SignatureIndex(sig_idx as u16); + let vec_of_vec = SignatureIndex((sig_idx + 1) as u16); + let code = vec![ + VecPack(vec_of_vec, 0), + StLoc(0), + ImmBorrowLoc(0), + VecLen(vec_of_vec), + Pop, + MutBorrowLoc(0), + VecPack(vec, 0), + VecPushBack(vec_of_vec), + MutBorrowLoc(0), + VecPack(vec, 0), + VecPushBack(vec_of_vec), + MutBorrowLoc(0), + LdU64(0), + LdU64(1), + VecSwap(vec_of_vec), + MutBorrowLoc(0), + VecPopBack(vec_of_vec), + Pop, + MutBorrowLoc(0), + VecPopBack(vec_of_vec), + Pop, + MoveLoc(0), + VecUnpack(vec_of_vec, 0), + Ret, + ]; + code +} + +// +// Tests with instantiated types as in Outer>, Inner, vector +// + +fn vector_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = U128; + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + vector_instantiated(addr, session, code_inst_signatures) +} + +fn vector_instantiated_4_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation(StructHandleIndex(1), vec![U128]); + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + vector_instantiated(addr, session, code_inst_signatures) +} + +fn vector_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(1), + vec![Vector(Box::new(StructInstantiation( + StructHandleIndex(1), + vec![Bool], + )))], + ); + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + vector_instantiated(addr, session, code_inst_signatures) +} + +fn vector_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig = Bool; + for _ in 0..48 { + sig = StructInstantiation(StructHandleIndex(1), vec![sig]); + } + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + vector_instantiated(addr, session, code_inst_signatures) +} + +fn vector_instantiated( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier, Vec) { + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 0; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![]; + let function_instantiations = vec![]; + let code = get_vector_ops(sig_start); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![vec![Ret], vec![Ret], code]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![ + SignatureIndex(0), + SignatureIndex(0), + SignatureIndex((sig_start + code_inst_signatures.len() - 1) as u16), + ]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + ( + self_id, + Identifier::new(ENTRY_POINT_NAME_1).unwrap(), + vec![], + ) +} + +// +// Tests with types instantiated via single function type parameter +// as in Outer, Inner, vector +// + +fn vector_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![ + Signature(vec![Vector(Box::new(TypeParameter(0)))]), + Signature(vec![Vector(Box::new(Vector(Box::new(TypeParameter(0)))))]), + ]; + let (module_id, entry_fn) = vector_single_type_arg(addr, session, code_inst_signatures); + (module_id, entry_fn, vec![TypeTag::U128]) +} + +fn vector_single_type_arg_4_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![ + Signature(vec![Vector(Box::new(TypeParameter(0)))]), + Signature(vec![Vector(Box::new(Vector(Box::new(TypeParameter(0)))))]), + ]; + let (module_id, entry_fn) = vector_single_type_arg(addr, session, code_inst_signatures); + let ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::Address], + })); + (module_id, entry_fn, vec![ty_arg]) +} + +fn vector_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![ + Signature(vec![Vector(Box::new(TypeParameter(0)))]), + Signature(vec![Vector(Box::new(Vector(Box::new(TypeParameter(0)))))]), + ]; + let (module_id, entry_fn) = vector_single_type_arg(addr, session, code_inst_signatures); + let ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::Vector(Box::new(TypeTag::Struct(Box::new( + StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::U64], + }, + ))))], + })); + (module_id, entry_fn, vec![ty_arg]) +} + +fn vector_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![ + Signature(vec![Vector(Box::new(TypeParameter(0)))]), + Signature(vec![Vector(Box::new(Vector(Box::new(TypeParameter(0)))))]), + ]; + let (module_id, entry_fn) = vector_single_type_arg(addr, session, code_inst_signatures); + let mut ty_arg = TypeTag::U128; + for _ in 0..48 { + ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg], + })); + } + (module_id, entry_fn, vec![ty_arg]) +} + +fn vector_single_type_arg( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 1; + let struct_def_instantiations = vec![]; + let function_instantiations = vec![]; + let code = get_vector_ops(1); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![vec![Ret], code, vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![ + SignatureIndex(0), + SignatureIndex((DEFAULT_SIGNATURES.len() + code_inst_signatures.len() - 1) as u16), + SignatureIndex(0), + ]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_2).unwrap()) +} + +// +// Tests with types instantiated via multiple function type parameters +// as in Outer> +// + +fn vector_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(1), + vec![TypeParameter(0), TypeParameter(1), TypeParameter(2)], + ); + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + let (module_id, entry_fn) = vector_mul_type_args(addr, session, code_inst_signatures); + ( + module_id, + entry_fn, + vec![TypeTag::U64, TypeTag::Bool, TypeTag::Address], + ) +} + +fn vector_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(1), + vec![TypeParameter(0), TypeParameter(1), TypeParameter(2)], + ); + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + let (module_id, entry_fn) = vector_mul_type_args(addr, session, code_inst_signatures); + let mut ty_arg_long = TypeTag::U128; + for _ in 0..2 { + ty_arg_long = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg_long.clone(), ty_arg_long.clone(), ty_arg_long], + })); + } + let mut ty_arg_short = TypeTag::Address; + for _ in 0..21 { + ty_arg_short = TypeTag::Vector(Box::new(ty_arg_short)); + } + ( + module_id, + entry_fn, + vec![ty_arg_long.clone(), ty_arg_long, ty_arg_short], + ) +} + +fn vector_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let struct_sig = StructInstantiation( + StructHandleIndex(1), + vec![TypeParameter(0), TypeParameter(0), TypeParameter(0)], + ); + let sig = StructInstantiation( + StructHandleIndex(1), + vec![struct_sig.clone(), struct_sig, TypeParameter(2)], + ); + let code_inst_signatures = vec![ + Signature(vec![sig.clone()]), + Signature(vec![Vector(Box::new(sig.clone()))]), + Signature(vec![Vector(Box::new(Vector(Box::new(sig))))]), + ]; + let (module_id, entry_fn) = vector_mul_type_args(addr, session, code_inst_signatures); + let ty_arg_long = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::Bool, TypeTag::U8, TypeTag::Address], + })); + let mut ty_arg_vec = TypeTag::Address; + for _ in 0..21 { + ty_arg_vec = TypeTag::Vector(Box::new(ty_arg_vec)); + } + ( + module_id, + entry_fn, + vec![ty_arg_long.clone(), ty_arg_long, ty_arg_vec], + ) +} + +fn vector_mul_type_args( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 3; + let fun_type_args_count = 3; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![]; + let function_instantiations = vec![]; + + let code = get_vector_ops(sig_start); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![code, vec![Ret], vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![ + SignatureIndex((DEFAULT_SIGNATURES.len() + code_inst_signatures.len() - 1) as u16), + SignatureIndex(0), + SignatureIndex(0), + ]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_3).unwrap()) +} + +// +// Global data tests +// + +fn get_mut_borrow_global_ops() -> Vec { + let code = vec![ + LdConst(ConstantPoolIndex(0)), + MutBorrowGlobalGeneric(StructDefInstantiationIndex(0)), + Pop, + Ret, + ]; + code +} + +fn get_imm_borrow_global_ops() -> Vec { + let code = vec![ + LdConst(ConstantPoolIndex(0)), + ImmBorrowGlobalGeneric(StructDefInstantiationIndex(0)), + Pop, + Ret, + ]; + code +} + +fn get_exist_global_ops() -> Vec { + let code = vec![ + LdConst(ConstantPoolIndex(0)), + ExistsGeneric(StructDefInstantiationIndex(0)), + Pop, + Ret, + ]; + code +} + +fn get_move_from_global_ops() -> Vec { + let code = vec![ + LdConst(ConstantPoolIndex(0)), + MoveFromGeneric(StructDefInstantiationIndex(0)), + Pop, + Ret, + ]; + code +} + +// TODO: setting up the args to call MoveToGeneric in a "customizable fashion" +// is not done yet +fn get_move_to_global_ops() -> Vec { + let code = vec![ + CopyLoc(0), + CopyLoc(1), + MoveToGeneric(StructDefInstantiationIndex(0)), + Ret, + ]; + code +} + +enum LoadCodeForGlobal { + MutBorrow, + ImmBorrow, + Exists, + MoveFrom, + MoveTo, +} + +impl LoadCodeForGlobal { + fn get_code(&self) -> Vec { + use LoadCodeForGlobal::*; + + match self { + MutBorrow => get_mut_borrow_global_ops(), + ImmBorrow => get_imm_borrow_global_ops(), + Exists => get_exist_global_ops(), + MoveFrom => get_move_from_global_ops(), + MoveTo => get_move_to_global_ops(), + } + } + + fn get_acquire(&self, idx: u16) -> Vec { + use LoadCodeForGlobal::*; + + match self { + MutBorrow => vec![StructDefinitionIndex(idx)], + ImmBorrow => vec![StructDefinitionIndex(idx)], + Exists => vec![], + MoveFrom => vec![StructDefinitionIndex(idx)], + MoveTo => vec![], + } + } +} + +// +// Tests with instantiated types as in Outer>, Inner, vector +// + +fn mut_borrow_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_2_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_2_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_2_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_2_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_instantiated_2_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![Signature(vec![U128])]; + global_instantiated(addr, session, code_inst_signatures, code) +} + +fn mut_borrow_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_6_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_6_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_6_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_6_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(0), + vec![Vector(Box::new(StructInstantiation( + StructHandleIndex(1), + vec![Vector(Box::new(U16))], + )))], + ); + let code_inst_signatures = vec![Signature(vec![sig])]; + global_instantiated(addr, session, code_inst_signatures, code) +} + +fn mut_borrow_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_51_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_51_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_51_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_instantiated_51_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let mut sig = Vector(Box::new(U32)); + for i in 0u16..48 { + sig = StructInstantiation(StructHandleIndex(i % 2), vec![sig]); + } + let code_inst_signatures = vec![Signature(vec![sig])]; + global_instantiated(addr, session, code_inst_signatures, code) +} + +fn global_instantiated( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, + op: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 0; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = op.get_code(); + let acquire = op.get_acquire(1); + let acquires = vec![vec![], vec![], acquire]; + let code = vec![vec![Ret], vec![Ret], code]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + ( + self_id, + Identifier::new(ENTRY_POINT_NAME_1).unwrap(), + vec![], + ) +} + +// +// Tests with types instantiated via single function type parameter +// as in Outer, Inner, vector +// + +fn mut_borrow_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_2_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_2_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_2_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_2_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_single_type_arg_2_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![]; + let (module_id, entry_fn) = global_single_type_arg(addr, session, code_inst_signatures, code); + (module_id, entry_fn, vec![TypeTag::U128]) +} + +fn mut_borrow_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_6_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_6_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_6_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_6_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(1), + vec![StructInstantiation( + StructHandleIndex(1), + vec![TypeParameter(0)], + )], + ); + let code_inst_signatures = vec![Signature(vec![sig])]; + let (module_id, entry_fn) = global_single_type_arg(addr, session, code_inst_signatures, code); + let ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::U64], + }))], + })); + (module_id, entry_fn, vec![ty_arg]) +} + +fn mut_borrow_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_51_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_51_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_51_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_single_type_arg_51_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation( + StructHandleIndex(0), + vec![Vector(Box::new(TypeParameter(0)))], + ); + let code_inst_signatures = vec![Signature(vec![sig])]; + let (module_id, entry_fn) = global_single_type_arg(addr, session, code_inst_signatures, code); + let mut ty_arg = TypeTag::U128; + for _ in 0..47 { + ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg], + })); + } + (module_id, entry_fn, vec![ty_arg]) +} + +fn global_single_type_arg( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, + op: LoadCodeForGlobal, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 1; + let sig_start = if code_inst_signatures.is_empty() { + DEFAULT_SIGNATURES.len() - 1 + } else { + DEFAULT_SIGNATURES.len() + }; + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = op.get_code(); + let acquire = op.get_acquire(1); + let acquires = vec![vec![], acquire, vec![]]; + let code = vec![vec![Ret], code, vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + locals, + parameters, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_2).unwrap()) +} + +// +// Tests with types instantiated via multiple function type parameters +// as in Outer> +// + +fn mut_borrow_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_6_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_6_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_6_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_6_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_mul_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = Signature(vec![ + TypeParameter(0), + Vector(Box::new(TypeParameter(1))), + StructInstantiation(StructHandleIndex(0), vec![TypeParameter(2)]), + ]); + let code_inst_signatures = vec![sig]; + let (module_id, entry_fn) = global_mul_type_args(addr, session, code_inst_signatures, code); + ( + module_id, + entry_fn, + vec![TypeTag::U64, TypeTag::Bool, TypeTag::Address], + ) +} + +fn mut_borrow_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_mul_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = Signature(vec![ + Vector(Box::new(TypeParameter(1))), + TypeParameter(0), + StructInstantiation(StructHandleIndex(0), vec![TypeParameter(2)]), + ]); + let code_inst_signatures = vec![sig]; + let (module_id, entry_fn) = global_mul_type_args(addr, session, code_inst_signatures, code); + let mut ty_arg_long = TypeTag::U128; + for _ in 0..2 { + ty_arg_long = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg_long.clone(), ty_arg_long.clone(), ty_arg_long], + })); + } + let mut ty_arg_short = TypeTag::Address; + for _ in 0..21 { + ty_arg_short = TypeTag::Vector(Box::new(ty_arg_short)); + } + ( + module_id, + entry_fn, + vec![ty_arg_long.clone(), ty_arg_long, ty_arg_short], + ) +} + +fn mut_borrow_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes_mix(addr, session, LoadCodeForGlobal::MutBorrow) +} + +fn imm_borrow_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes_mix(addr, session, LoadCodeForGlobal::ImmBorrow) +} + +fn exists_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes_mix(addr, session, LoadCodeForGlobal::Exists) +} + +fn move_from_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + global_mul_type_args_51_nodes_mix(addr, session, LoadCodeForGlobal::MoveFrom) +} + +fn global_mul_type_args_51_nodes_mix( + addr: AccountAddress, + session: &mut Session, + code: LoadCodeForGlobal, +) -> (ModuleId, Identifier, Vec) { + let sig = Signature(vec![ + Vector(Box::new(TypeParameter(1))), + StructInstantiation( + StructHandleIndex(1), + vec![ + TypeParameter(0), + Vector(Box::new(TypeParameter(2))), + TypeParameter(2), + ], + ), + Vector(Box::new(TypeParameter(0))), + ]); + let code_inst_signatures = vec![sig]; + let (module_id, entry_fn) = global_mul_type_args(addr, session, code_inst_signatures, code); + let ty_arg_long = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![TypeTag::Bool, TypeTag::U8, TypeTag::Address], + })); + let mut ty_arg_vec = TypeTag::Address; + for _ in 0..16 { + ty_arg_vec = TypeTag::Vector(Box::new(ty_arg_vec)); + } + ( + module_id, + entry_fn, + vec![ty_arg_long.clone(), ty_arg_long, ty_arg_vec], + ) +} + +fn global_mul_type_args( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, + op: LoadCodeForGlobal, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 3; + let fun_type_args_count = 3; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = op.get_code(); + let acquire = op.get_acquire(1); + let acquires = vec![acquire, vec![], vec![]]; + let code = vec![code, vec![Ret], vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_3).unwrap()) +} + +// +// Pack generic tests +// + +fn get_pack_generic(idx: u16, vector_count: u16) -> Vec { + let mut code = vec![]; + for idx in idx..idx + vector_count { + code.push(VecPack(SignatureIndex(idx), 0)); + } + code.push(PackGeneric(StructDefInstantiationIndex(0))); + code.push(UnpackGeneric(StructDefInstantiationIndex(0))); + for _ in 0..vector_count { + code.push(Pop); + } + code.push(Ret); + code +} + +// +// Tests with instantiated types as in Outer>, Inner, vector +// + +fn pack_generic_instantiated_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig1 = Bool; + let sig2 = StructInstantiation(StructHandleIndex(0), vec![Signer]); + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + pack_generic_instantiated(addr, session, code_inst_signatures) +} + +fn pack_generic_instantiated_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig1 = Bool; + for _ in 0..23 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + let mut sig2 = Address; + for _ in 0..23 { + sig2 = Vector(Box::new(sig2)); + } + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + pack_generic_instantiated(addr, session, code_inst_signatures) +} + +fn pack_generic_instantiated( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier, Vec) { + // + // Module definition and publishing + let struct_type_args_count = 2usize; + let fun_type_args_count = 0; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = get_pack_generic(sig_start as u16 + 1, struct_type_args_count as u16); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![vec![Ret], vec![Ret], code]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + ( + self_id, + Identifier::new(ENTRY_POINT_NAME_1).unwrap(), + vec![], + ) +} + +// +// Tests with types instantiated via single function type parameter +// as in Outer, Inner, vector +// + +fn pack_generic_single_type_arg_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig1 = Vector(Box::new(TypeParameter(0))); + let sig2 = Address; + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + let (module_id, entry_point) = + pack_generic_single_type_arg(addr, session, code_inst_signatures); + (module_id, entry_point, vec![TypeTag::U32]) +} + +fn pack_generic_single_type_arg_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig1 = TypeParameter(0); + for _ in 0..22 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + let mut sig2 = Address; + for _ in 0..23 { + sig2 = Vector(Box::new(sig2)); + } + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + let (module_id, entry_point) = + pack_generic_single_type_arg(addr, session, code_inst_signatures); + ( + module_id, + entry_point, + vec![TypeTag::Vector(Box::new(TypeTag::U32))], + ) +} + +fn pack_generic_single_type_arg( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 2usize; + let fun_type_args_count = 0; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = get_pack_generic(sig_start as u16 + 1, struct_type_args_count as u16); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![vec![Ret], code, vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_2).unwrap()) +} + +// +// Tests with types instantiated via multiple function type parameters +// as in Outer> +// + +fn pack_generic_multi_type_args_6_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig1 = TypeParameter(1); + let sig2 = TypeParameter(2); + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + let (module_id, entry_point) = + pack_generic_multi_type_args(addr, session, code_inst_signatures); + ( + module_id, + entry_point, + vec![ + TypeTag::U32, + TypeTag::Vector(Box::new(TypeTag::Bool)), + TypeTag::Address, + ], + ) +} + +fn pack_generic_multi_type_args_51_nodes( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig1 = TypeParameter(0); + for _ in 0..20 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + let mut sig2 = TypeParameter(1); + for _ in 0..20 { + sig2 = Vector(Box::new(sig2)); + } + let sig0 = vec![ + Vector(Box::new(sig1.clone())), + Vector(Box::new(sig2.clone())), + ]; + let code_inst_signatures = vec![ + Signature(sig0), + Signature(vec![sig1]), + Signature(vec![sig2]), + ]; + let (module_id, entry_point) = + pack_generic_multi_type_args(addr, session, code_inst_signatures); + let mut ty_arg_long = TypeTag::U128; + for _ in 0..2 { + ty_arg_long = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg_long.clone(), ty_arg_long], + })); + } + let mut ty_arg_short = TypeTag::Address; + for _ in 0..21 { + ty_arg_short = TypeTag::Vector(Box::new(ty_arg_short)); + } + ( + module_id, + entry_point, + vec![ty_arg_long, TypeTag::U8, ty_arg_short], + ) +} + +fn pack_generic_multi_type_args( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, +) -> (ModuleId, Identifier) { + // + // Module definition and publishing + let struct_type_args_count = 2usize; + let fun_type_args_count = 3; + let sig_start = DEFAULT_SIGNATURES.len(); + let struct_def_instantiations = vec![StructDefInstantiation { + def: StructDefinitionIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }]; + let function_instantiations = vec![]; + let code = get_pack_generic(sig_start as u16 + 1, struct_type_args_count as u16); + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![code, vec![Ret], vec![Ret]]; + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(ENTRY_POINT_NAME_3).unwrap()) +} + +// +// Pack generic tests +// + +fn get_call_generic() -> Vec> { + let code1 = vec![CallGeneric(FunctionInstantiationIndex(0)), Ret]; + let code2 = vec![CallGeneric(FunctionInstantiationIndex(1)), Ret]; + let code3 = vec![Ret]; + vec![code3, code2, code1] +} + +fn call_instantiated_1_2( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let code_inst_signatures = vec![Signature(vec![U128]), Signature(vec![Address, Bool])]; + let entry_point = ENTRY_POINT_NAME_1; + let ty_args = vec![]; + call_generic(addr, session, code_inst_signatures, entry_point, ty_args) +} + +fn call_instantiated_6_6( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig = Vector(Box::new(Vector(Box::new(U128)))); + for _ in 0..3 { + sig = StructInstantiation(StructHandleIndex(1), vec![sig]); + } + let mut sig1 = Address; + for _ in 0..3 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + for _ in 0..2 { + sig1 = Vector(Box::new(sig1)); + } + let code_inst_signatures = vec![Signature(vec![sig.clone()]), Signature(vec![sig1, sig])]; + let entry_point = ENTRY_POINT_NAME_1; + let ty_args = vec![]; + call_generic(addr, session, code_inst_signatures, entry_point, ty_args) +} + +fn call_instantiated_11_31( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let mut sig = Bool; + for _ in 0..10 { + sig = StructInstantiation(StructHandleIndex(1), vec![sig]); + } + let mut sig1 = Address; + for _ in 0..30 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + let code_inst_signatures = vec![Signature(vec![sig.clone()]), Signature(vec![sig1, sig])]; + let ty_args = vec![]; + call_generic( + addr, + session, + code_inst_signatures, + ENTRY_POINT_NAME_1, + ty_args, + ) +} + +fn call_single_type_arg_11_31( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + let sig = StructInstantiation(StructHandleIndex(1), vec![TypeParameter(0)]); + let mut sig1 = Address; + for _ in 0..29 { + sig1 = StructInstantiation(StructHandleIndex(0), vec![sig1]); + } + let code_inst_signatures = vec![Signature(vec![U128]), Signature(vec![sig1, sig])]; + let mut ty_arg = TypeTag::Bool; + for _ in 0..10 { + ty_arg = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg], + })) + } + let ty_args = vec![ty_arg]; + call_generic( + addr, + session, + code_inst_signatures, + ENTRY_POINT_NAME_2, + ty_args, + ) +} + +fn call_multi_type_args_11_31( + addr: AccountAddress, + session: &mut Session, +) -> (ModuleId, Identifier, Vec) { + // those are only just so the code compiles + let code_inst_signatures = vec![Signature(vec![U128]), Signature(vec![U128, U128])]; + let mut ty_arg1 = TypeTag::Bool; + for _ in 0..10 { + ty_arg1 = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg1], + })); + } + let mut ty_arg2 = TypeTag::Address; + for _ in 0..30 { + ty_arg2 = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(INNER_NAME).unwrap(), + type_params: vec![ty_arg2], + })); + } + + let ty_args = vec![ty_arg1, ty_arg2]; + call_generic( + addr, + session, + code_inst_signatures, + ENTRY_POINT_NAME_3, + ty_args, + ) +} + +fn call_generic( + addr: AccountAddress, + session: &mut Session, + mut code_inst_signatures: Vec, + entry_point: &str, + ty_args: Vec, +) -> (ModuleId, Identifier, Vec) { + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 2; + let struct_def_instantiations = vec![]; + let sig_start = DEFAULT_SIGNATURES.len(); + let function_instantiations = vec![ + FunctionInstantiation { + handle: FunctionHandleIndex(1), + type_parameters: SignatureIndex(sig_start as u16), + }, + FunctionInstantiation { + handle: FunctionHandleIndex(2), + type_parameters: SignatureIndex(sig_start as u16 + 1), + }, + ]; + let acquires = vec![vec![], vec![], vec![]]; + let code = get_call_generic(); + let parameters = vec![SignatureIndex(0); 3]; + let locals = vec![SignatureIndex(0), SignatureIndex(0), SignatureIndex(0)]; + + let mut signatures = DEFAULT_SIGNATURES.clone(); + signatures.append(&mut code_inst_signatures); + let self_id = make_module( + session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + // Entry specification + (self_id, Identifier::new(entry_point).unwrap(), ty_args) +} + +// +// Test call to a function that instantiate a type +// + +fn call_vector_arg_9(verifier: &VerifierConfig) -> VMResult { + let addr = AccountAddress::from_hex_literal("0xcafe").unwrap(); + let mut vector_tag = TypeTag::U8; + for _ in 0..8 { + vector_tag = TypeTag::Vector(Box::new(vector_tag)); + } + let type_args = vec![vector_tag]; + let arg = vec![vec![vec![vec![vec![0u8]]]]]; + call_type_arg( + addr, + verifier, + type_args, + vec![bcs::to_bytes(&arg).unwrap()], + ) +} + +fn call_vector_arg_10(verifier: &VerifierConfig) -> VMResult { + let addr = AccountAddress::from_hex_literal("0xcafe").unwrap(); + let mut vector_tag = TypeTag::U8; + for _ in 0..9 { + vector_tag = TypeTag::Vector(Box::new(vector_tag)); + } + let type_args = vec![vector_tag]; + let arg = vec![vec![vec![vec![vec![vec![vec![vec![vec![0u8]]]]]]]]]; + call_type_arg( + addr, + verifier, + type_args, + vec![bcs::to_bytes(&arg).unwrap()], + ) +} + +fn call_vector_arg_11(verifier: &VerifierConfig) -> VMResult { + let addr = AccountAddress::from_hex_literal("0xcafe").unwrap(); + let mut vector_tag = TypeTag::U8; + for _ in 0..10 { + vector_tag = TypeTag::Vector(Box::new(vector_tag)); + } + let type_args = vec![vector_tag]; + let arg = vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ + vec![vec![vec![0u8]]], + ]]]]]]]]]]]; + call_type_arg( + addr, + verifier, + type_args, + vec![bcs::to_bytes(&arg).unwrap()], + ) +} + +fn call_generic_arg( + verifier: &VerifierConfig, + nest_count: usize, +) -> VMResult { + let addr = AccountAddress::from_hex_literal("0xcafe").unwrap(); + let mut struct_tag_outer = TypeTag::U8; + for _ in 0..nest_count { + struct_tag_outer = TypeTag::Struct(Box::new(StructTag { + address: addr, + module: Identifier::new(MODULE_NAME).unwrap(), + name: Identifier::new(OUTER_NAME).unwrap(), + type_params: vec![struct_tag_outer], + })); + } + let type_args = vec![struct_tag_outer]; + let arg = 0u8; + call_type_arg( + addr, + verifier, + type_args, + vec![bcs::to_bytes(&arg).unwrap()], + ) +} + +fn call_type_arg( + addr: AccountAddress, + verifier: &VerifierConfig, + type_args: Vec, + args: Vec>, +) -> VMResult { + let vm = MoveVM::new_with_config( + vec![], + VMConfig { + verifier: verifier.clone(), + ..Default::default() + }, + ) + .unwrap(); + let storage: InMemoryStorage = InMemoryStorage::new(); + let mut session = vm.new_session(&storage); + + // + // Module definition and publishing + let struct_type_args_count = 1; + let fun_type_args_count = 1; + let acquires = vec![vec![], vec![], vec![]]; + let code = vec![vec![Ret], vec![Ret], vec![Ret]]; + let parameters = vec![SignatureIndex(0), SignatureIndex(1), SignatureIndex(0)]; + let locals = vec![SignatureIndex(0); 3]; + let signatures = DEFAULT_SIGNATURES.clone(); + let struct_def_instantiations = vec![]; + let function_instantiations = vec![]; + + let self_id = make_module( + &mut session, + addr, + struct_type_args_count, + fun_type_args_count, + acquires, + code, + parameters, + locals, + signatures, + struct_def_instantiations, + function_instantiations, + ); + + let mut gas = GasStatus::new_unmetered(); + session.execute_entry_function( + &self_id, + IdentStr::new(ENTRY_POINT_NAME_2).unwrap(), + type_args, + args, + &mut gas, + ) +} diff --git a/language/move-vm/integration-tests/src/tests/mod.rs b/language/move-vm/integration-tests/src/tests/mod.rs index cac687f9d2..a551911f0a 100644 --- a/language/move-vm/integration-tests/src/tests/mod.rs +++ b/language/move-vm/integration-tests/src/tests/mod.rs @@ -10,6 +10,7 @@ mod function_arg_tests; mod instantiation_tests; mod invariant_violation_tests; mod leak_tests; +mod limits_tests; mod loader_tests; mod mutated_accounts_tests; mod nested_loop_tests; diff --git a/language/move-vm/runtime/src/interpreter.rs b/language/move-vm/runtime/src/interpreter.rs index a7feecf3d5..1af33a0d56 100644 --- a/language/move-vm/runtime/src/interpreter.rs +++ b/language/move-vm/runtime/src/interpreter.rs @@ -1293,7 +1293,7 @@ impl Frame { interpreter.operand_stack.push_ty(output_ty)?; } Bytecode::PackGeneric(idx) => { - let field_count = resolver.field_instantiation_count(*idx); + let field_count = resolver.field_instantiation_count(*idx, ty_args)?; let args_ty = resolver.instantiate_generic_struct_fields(*idx, ty_args)?; let output_ty = resolver.instantiate_generic_type(*idx, ty_args)?; let ability = resolver.loader().abilities(&output_ty)?; @@ -1851,7 +1851,8 @@ impl Frame { .push(Value::struct_(Struct::pack(args)))?; } Bytecode::PackGeneric(si_idx) => { - let field_count = resolver.field_instantiation_count(*si_idx); + let field_count = + resolver.field_instantiation_count(*si_idx, self.ty_args())?; gas_meter.charge_pack( true, interpreter.operand_stack.last_n(field_count as usize)?, diff --git a/language/move-vm/runtime/src/loader.rs b/language/move-vm/runtime/src/loader.rs index e4395e3c64..57d7f4e354 100644 --- a/language/move-vm/runtime/src/loader.rs +++ b/language/move-vm/runtime/src/loader.rs @@ -773,6 +773,16 @@ impl Loader { self.verify_ty_args(func.type_parameters(), &type_arguments) .map_err(|e| e.finish(Location::Module(module_id.clone())))?; + if !func.type_parameters.is_empty() { + if let Some(max_count) = self.vm_config.verifier.max_function_instantiation_size { + let type_params = (0..func.type_parameters.len()) + .map(Type::TyParam) + .collect::>(); + self.check_instantiation(&type_params, &type_arguments, max_count) + .map_err(|e| e.finish(Location::Module(module_id.clone())))?; + } + } + let inst = LoadedFunctionInstantiation { type_arguments, parameters, @@ -1331,26 +1341,6 @@ impl Loader { Ok(()) } - // Return an instantiated type given a generic and an instantiation. - // Stopgap to avoid a recursion that is either taking too long or using too - // much memory - fn subst(&self, ty: &Type, ty_args: &[Type]) -> PartialVMResult { - // Before instantiating the type, count the # of nodes of all type arguments plus - // existing type instantiation. - // If that number is larger than MAX_TYPE_INSTANTIATION_NODES, refuse to construct this type. - // This prevents constructing larger and lager types via struct instantiation. - if let Type::StructInstantiation(_, struct_inst) = ty { - let mut sum_nodes: usize = 1; - for ty in ty_args.iter().chain(struct_inst.iter()) { - sum_nodes = sum_nodes.saturating_add(self.count_type_nodes(ty)); - if sum_nodes > MAX_TYPE_INSTANTIATION_NODES { - return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); - } - } - } - ty.subst(ty_args) - } - // Verify the kind (constraints) of an instantiation. // Both function and script invocation use this function to verify correctness // of type arguments provided @@ -1449,6 +1439,58 @@ impl Loader { } } } + + // Check instantiation operation: count the # of nodes in `type_` and instantiate + // over ty_args. In practice, mimics instantiation without perfomring it. + // If that number is larger than `max_count`, refuse to construct this type. + // This prevents constructing larger and lager types via instantiation operations. + pub(crate) fn check_type_instantiation( + &self, + type_: &Type, + ty_args: &[Type], + max_count: usize, + ) -> PartialVMResult { + let mut type_params_count = vec![0; ty_args.len()]; + let mut count_inst = self.count_type_nodes_and_params(type_, &mut type_params_count)?; + if count_inst > max_count { + return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); + } + for (idx, count) in type_params_count.into_iter().enumerate() { + if count > 0 { + let multiplier = match ty_args.get(idx) { + Some(ty) => self.count_type_nodes(ty), + None => { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message(format!("no type param {} for {:?}", idx, type_))); + } + }; + count_inst += count * multiplier; + if count_inst > max_count { + return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); + } + } + } + Ok(count_inst) + } + + // Check instantiation over a list of types. + pub(crate) fn check_instantiation( + &self, + types: &[Type], + ty_args: &[Type], + max_count: usize, + ) -> PartialVMResult<()> { + let mut count = 0; + for type_ in types { + count += self.check_type_instantiation(type_, ty_args, max_count - count)?; + if count > max_count { + return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); + } + } + Ok(()) + } } // @@ -1520,24 +1562,24 @@ impl<'a> Resolver<'a> { pub(crate) fn instantiate_generic_function( &self, idx: FunctionInstantiationIndex, - type_params: &[Type], + ty_args: &[Type], ) -> PartialVMResult> { let func_inst = match &self.binary { BinaryType::Module { loaded, .. } => loaded.function_instantiation_at(idx.0), BinaryType::Script(script) => script.function_instantiation_at(idx.0), }; + if let Some(max_count) = self + .loader + .vm_config + .verifier + .max_function_instantiation_size + { + self.loader + .check_instantiation(&func_inst.instantiation, ty_args, max_count)?; + } let mut instantiation = vec![]; for ty in &func_inst.instantiation { - instantiation.push(self.subst(ty, type_params)?); - } - // Check if the function instantiation over all generics is larger - // than MAX_TYPE_INSTANTIATION_NODES. - let mut sum_nodes: usize = 1; - for ty in type_params.iter().chain(instantiation.iter()) { - sum_nodes = sum_nodes.saturating_add(self.loader.count_type_nodes(ty)); - if sum_nodes > MAX_TYPE_INSTANTIATION_NODES { - return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); - } + instantiation.push(ty.subst(ty_args)?); } Ok(instantiation) } @@ -1572,19 +1614,11 @@ impl<'a> Resolver<'a> { BinaryType::Module { loaded, .. } => loaded.struct_instantiation_at(idx.0), BinaryType::Script(_) => unreachable!("Scripts cannot have type instructions"), }; - - // Before instantiating the type, count the # of nodes of all type arguments plus - // existing type instantiation. - // If that number is larger than MAX_TYPE_INSTANTIATION_NODES, refuse to construct this type. - // This prevents constructing larger and lager types via struct instantiation. - let mut sum_nodes: usize = 1; - for ty in ty_args.iter().chain(struct_inst.instantiation.iter()) { - sum_nodes = sum_nodes.saturating_add(self.loader.count_type_nodes(ty)); - if sum_nodes > MAX_TYPE_INSTANTIATION_NODES { - return Err(PartialVMError::new(StatusCode::TOO_MANY_TYPE_NODES)); - } + if let Some(max_count) = self.loader.vm_config.verifier.max_type_instantiation_size { + // check against max - 1 to account for the type itself + self.loader + .check_instantiation(&struct_inst.instantiation, ty_args, max_count - 1)?; } - Ok(Type::StructInstantiation( struct_inst.def, struct_inst @@ -1679,28 +1713,29 @@ impl<'a> Resolver<'a> { .collect::>>() } - fn single_type_at(&self, idx: SignatureIndex) -> &Type { - match &self.binary { - BinaryType::Module { loaded, .. } => loaded.single_type_at(idx), - BinaryType::Script(script) => script.single_type_at(idx), - } - } - pub(crate) fn instantiate_single_type( &self, idx: SignatureIndex, ty_args: &[Type], ) -> PartialVMResult { - let ty = self.single_type_at(idx); + let type_ = match &self.binary { + BinaryType::Module { loaded, .. } => loaded.single_type_at(idx), + BinaryType::Script(script) => script.single_type_at(idx), + }; + if let Some(max_count) = self.loader.vm_config.verifier.max_type_instantiation_size { + // subtract 1 from the max to account for the vector type + self.loader + .check_type_instantiation(type_, ty_args, max_count - 1)?; + }; if !ty_args.is_empty() { - self.subst(ty, ty_args) + type_.subst(ty_args) } else { - Ok(ty.clone()) + Ok(type_.clone()) } } pub(crate) fn subst(&self, ty: &Type, ty_args: &[Type]) -> PartialVMResult { - self.loader.subst(ty, ty_args) + ty.subst(ty_args) } // @@ -1728,11 +1763,21 @@ impl<'a> Resolver<'a> { } } - pub(crate) fn field_instantiation_count(&self, idx: StructDefInstantiationIndex) -> u16 { - match &self.binary { - BinaryType::Module { loaded, .. } => loaded.field_instantiation_count(idx.0), + pub(crate) fn field_instantiation_count( + &self, + idx: StructDefInstantiationIndex, + ty_args: &[Type], + ) -> PartialVMResult { + let struct_inst = match &self.binary { + BinaryType::Module { loaded, .. } => loaded.struct_instantiation_at(idx.0), BinaryType::Script(_) => unreachable!("Scripts cannot have type instructions"), + }; + if let Some(max_count) = self.loader.vm_config.verifier.max_type_instantiation_size { + // check against max - 1 to account for the type itself + self.loader + .check_instantiation(&struct_inst.instantiation, ty_args, max_count - 1)?; } + Ok(struct_inst.field_count) } pub(crate) fn field_handle_to_struct(&self, idx: FieldHandleIndex) -> Type { @@ -2029,10 +2074,6 @@ impl Module { self.structs[idx as usize].field_count } - fn field_instantiation_count(&self, idx: u16) -> u16 { - self.struct_instantiations[idx as usize].field_count - } - fn field_offset(&self, idx: FieldHandleIndex) -> usize { self.field_handles[idx.0 as usize].offset } @@ -2542,10 +2583,6 @@ const VALUE_DEPTH_MAX: usize = 128; /// fields for struct types. const MAX_TYPE_TO_LAYOUT_NODES: usize = 256; -/// Maximal nodes which are all allowed when instantiating a generic type. This does not include -/// field types of structs. -const MAX_TYPE_INSTANTIATION_NODES: usize = 128; - impl Loader { fn struct_gidx_to_type_tag( &self, @@ -2611,6 +2648,60 @@ impl Loader { }) } + // Count the number of "concrete" types and type parameters over a given type in a + // given context. + // Return the number of concrete types and the count of each type parameter in context. + // The caller is responsible to provide a `type_params` "accumulator" that is + // consistent with `type_`. + // E.g. for `S>` in a `f()` it will return + // 2 for `S` and `vector`, and update `type_params` [+2, +1] for `T` and `W` + // then the caller can perform proper instantiation computation in a given context. + // f, S1>> will properly compute instantiation count + fn count_type_nodes_and_params( + &self, + type_: &Type, + type_params: &mut [usize], + ) -> PartialVMResult { + let mut todo = vec![type_]; + let mut result = 0; + while let Some(ty) = todo.pop() { + match ty { + Type::Vector(ty) | Type::Reference(ty) | Type::MutableReference(ty) => { + result += 1; + todo.push(ty); + } + Type::StructInstantiation(_, ty_args) => { + result += 1; + todo.extend(ty_args.iter()) + } + Type::TyParam(idx) => match type_params.get_mut(*idx) { + Some(value) => *value += 1, + None => { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message(format!("no type param {} for {:?}", idx, type_))); + } + }, + Type::Struct(_) + | Type::Bool + | Type::U8 + | Type::U64 + | Type::U128 + | Type::Address + | Type::Signer + | Type::U16 + | Type::U32 + | Type::U256 => { + result += 1; + } + } + } + Ok(result) + } + + // Count the number of nodes in a type, whether concrete, partially or fully instantiated. + // E.g. S1>> will return 4 fn count_type_nodes(&self, ty: &Type) -> usize { let mut todo = vec![ty]; let mut result = 0; @@ -2624,7 +2715,17 @@ impl Loader { result += 1; todo.extend(ty_args.iter()) } - _ => { + Type::Struct(_) + | Type::TyParam(_) + | Type::Bool + | Type::U8 + | Type::U64 + | Type::U128 + | Type::Address + | Type::Signer + | Type::U16 + | Type::U32 + | Type::U256 => { result += 1; } } @@ -2655,7 +2756,7 @@ impl Loader { let field_tys = struct_type .fields .iter() - .map(|ty| self.subst(ty, ty_args)) + .map(|ty| ty.subst(ty_args)) .collect::>>()?; let field_layouts = field_tys .iter() @@ -2788,7 +2889,7 @@ impl Loader { .iter() .zip(&struct_type.fields) .map(|(n, ty)| { - let ty = self.subst(ty, ty_args)?; + let ty = ty.subst(ty_args)?; let l = self.type_to_fully_annotated_layout_impl(&ty, count, depth + 1)?; Ok(MoveFieldLayout::new(n.clone(), l)) }) diff --git a/language/move-vm/runtime/src/runtime.rs b/language/move-vm/runtime/src/runtime.rs index 12a99251aa..44e736beab 100644 --- a/language/move-vm/runtime/src/runtime.rs +++ b/language/move-vm/runtime/src/runtime.rs @@ -326,6 +326,11 @@ impl VMRuntime { gas_meter: &mut impl GasMeter, extensions: &mut NativeContextExtensions, ) -> VMResult { + if let Some(max_count) = self.loader.vm_config().verifier.max_type_instantiation_size { + self.loader + .check_instantiation(¶m_types, &ty_args, max_count) + .map_err(|err| err.finish(Location::Undefined))?; + } let arg_types = param_types .into_iter() .map(|ty| ty.subst(&ty_args)) diff --git a/language/move-vm/transactional-tests/tests/recursion/runtime_type_deeply_nested.exp b/language/move-vm/transactional-tests/tests/recursion/runtime_type_deeply_nested.exp index b37da7a441..66d5120e78 100644 --- a/language/move-vm/transactional-tests/tests/recursion/runtime_type_deeply_nested.exp +++ b/language/move-vm/transactional-tests/tests/recursion/runtime_type_deeply_nested.exp @@ -1,19 +1,10 @@ processed 3 tasks -task 1 'run'. lines 72-79: -Error: Script execution failed with VMError: { - major_status: TOO_MANY_TYPE_NODES, - sub_status: None, - location: 0x42::M, - indices: [], - offsets: [(FunctionDefinitionIndex(48), 0)], -} - task 2 'run'. lines 81-89: Error: Script execution failed with VMError: { - major_status: TOO_MANY_TYPE_NODES, + major_status: VM_MAX_TYPE_DEPTH_REACHED, sub_status: None, location: 0x42::M, indices: [], - offsets: [(FunctionDefinitionIndex(49), 0)], + offsets: [(FunctionDefinitionIndex(1), 0)], }