Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

grab bag of misc WASM unit tests for old defects #11076

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions unittests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2483,6 +2483,31 @@ BOOST_FIXTURE_TEST_CASE(memory_tests, TESTER) {
pushit("memset"_n, name());
}

static const char cstr_wast[] = R"======(
(module
(import "env" "eosio_assert" (func $eosio_assert (param i32 i32)))
(memory 1)
(func (export "apply") (param i64 i64 i64)
(call $eosio_assert (i32.const 1) (i32.const 65534))
)
(data (i32.const 65535) "x")
)
)======";

BOOST_FIXTURE_TEST_CASE(cstr_tests, TESTER) {
produce_block();
create_accounts( { "cstr"_n } );
set_code( "cstr"_n, cstr_wast );
auto pushit = [&](name acct, name act) {
signed_transaction trx;
trx.actions.push_back({ { {acct, config::active_name} }, acct, act, bytes()});
set_transaction_headers(trx);
trx.sign(get_private_key(acct, "active"), control->get_chain_id());
push_transaction(trx);
};
pushit("cstr"_n, name());
}

/*************************************************************************************
* print_tests test case
*************************************************************************************/
Expand Down
115 changes: 115 additions & 0 deletions unittests/contracts/test_wasts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,3 +876,118 @@ static const std::vector<uint8_t> varuint_memory_flags{
0x07, 0x09, 0x01, 0x05, 'a', 'p', 'p', 'l', 'y', 0x00, 0x00, // exports
0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b // code
};

static const char zero_memory_do_nothing[] = R"=====(
(module
(export "apply" (func $apply))
(memory $0 0)
(func $apply (param i64) (param i64) (param i64)
)
)
)=====";

static const char zero_memory_load[] = R"=====(
(module
(export "apply" (func $apply))
(memory $0 0)
(func $apply (param i64) (param i64) (param i64)
(drop (i64.load (i32.const 0)))
)
)
)=====";

static const char zero_memory_intrinsic[] = R"=====(
(module
(export "apply" (func $apply))
(import "env" "read_transaction" (func $read_transaction (param i32 i32) (result i32)))
(memory $0 0)
(func $apply (param i64) (param i64) (param i64)
(drop (call $read_transaction (i32.const 16) (i32.const 0)))
)
)
)=====";

static const char zero_memory_grow[] = R"=====(
(module
(export "apply" (func $apply))
(memory $0 0)
(func $apply (param i64) (param i64) (param i64)
(drop (grow_memory (i32.const 1)))
(drop (i64.load (i32.const 0)))
)
)
)=====";

static const char zero_memory_grow_hi[] = R"=====(
(module
(export "apply" (func $apply))
(memory $0 0)
(func $apply (param i64) (param i64) (param i64)
(drop (grow_memory (i32.const 1)))
(drop (i64.load (i32.const 70000)))
)
)
)=====";

static const char exit_in_start_wast[] = R"=====(
(module
(import "env" "abort" (func $abort))
(import "env" "eosio_exit" (func $eosio_exit (param i32)))
(export "apply" (func $apply))
(start $dothedew)
(func $dothedew
(call $eosio_exit (i32.const 0))
)
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $abort)
)
)
)=====";

static const char negative_memory_grow_wast[] = R"=====(
(module
(memory 1)
(func (export "apply") (param i64 i64 i64)
(block
(drop (grow_memory (i32.const 1)))
(i32.eq (grow_memory (i32.const -1)) (i32.const 2))
(br_if 0)
(unreachable)
)
(block
(drop (grow_memory (i32.const 2)))
(i32.eq (grow_memory (i32.const -3)) (i32.const 3))
(br_if 0)
(unreachable)
)
(block
(drop (grow_memory (i32.const 1)))
(i32.store (i32.const 0) (i32.const -1))
(i32.store (i32.const 65532) (i32.const -1))
(grow_memory (i32.const -1))
(grow_memory (i32.const 1))
(i32.and (i32.eq (i32.load (i32.const 0)) (i32.const 0))
(i32.eq (i32.load (i32.const 65532)) (i32.const 0)))
(br_if 0)
(unreachable)
)
(block
(i32.eq (grow_memory (i32.const -2)) (i32.const -1))
(br_if 0)
(unreachable)
)
)
)
)=====";

static const char negative_memory_grow_trap_wast[] = R"=====(
(module
(memory 1)
(func (export "apply") (param i64 i64 i64)
(block
(drop (grow_memory (i32.const -1)))
(drop (i32.load (i32.const 0)))
)
)
)
)=====";
108 changes: 108 additions & 0 deletions unittests/wasm_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,115 @@ BOOST_AUTO_TEST_CASE( billed_cpu_test ) try {

} FC_LOG_AND_RETHROW()

/**
* various tests with wasm & 0 pages worth of memory
*/
BOOST_FIXTURE_TEST_CASE( zero_memory_pages, TESTER ) try {
produce_blocks(2);

create_accounts( {"zero"_n} );
produce_block();

signed_transaction trx;
trx.actions.emplace_back(vector<permission_level>{{"zero"_n,config::active_name}}, "zero"_n, name(), bytes{});
trx.actions[0].authorization = vector<permission_level>{{"zero"_n,config::active_name}};

auto pushit = [&]() {
produce_block();
trx.signatures.clear();
set_transaction_headers(trx);
trx.sign(get_private_key("zero"_n, "active"), control->get_chain_id());
push_transaction(trx);
};

//first, let's run another large memory contract just to prime the pump so to catch any
//memory reinit faults.
set_code("zero"_n, misaligned_ref_wast);
pushit();

//contract w/ 0 pages that does nothing
set_code("zero"_n, zero_memory_do_nothing);
pushit();

//memory load with 0 pages of memory
set_code("zero"_n, zero_memory_load);
BOOST_CHECK_THROW(pushit(), wasm_execution_error);

//do an intrinsic with 0 pages of memory
set_code("zero"_n, zero_memory_intrinsic);
BOOST_CHECK_THROW(pushit(), wasm_execution_error);

//grow memory from 0 -> 1, should be able to access byte 0 now
set_code("zero"_n, zero_memory_grow);
pushit();

//grow memory from 0 -> 1, should be unable to access byte 70K
set_code("zero"_n, zero_memory_grow_hi);
BOOST_CHECK_THROW(pushit(), wasm_execution_error);

} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE( eosio_exit_in_start, TESTER ) try {
produce_blocks(2);
create_accounts( {"startexit"_n} );
produce_block();

set_code("startexit"_n, exit_in_start_wast);
produce_blocks(1);

signed_transaction trx;
action act;
act.account = "startexit"_n;
act.name = name();
act.authorization = vector<permission_level>{{"startexit"_n,config::active_name}};
trx.actions.push_back(act);
set_transaction_headers(trx);
trx.sign(get_private_key( "startexit"_n, "active" ), control->get_chain_id());
push_transaction(trx);
produce_blocks(1);
} FC_LOG_AND_RETHROW()

// memory.grow with a negative argument can shrink the available memory.
BOOST_FIXTURE_TEST_CASE( negative_memory_grow, TESTER ) try {
produce_blocks(2);


create_accounts( {"negmemgrow"_n} );
produce_block();

set_code("negmemgrow"_n, negative_memory_grow_wast);
produce_blocks(1);

{
signed_transaction trx;
action act;
act.account = "negmemgrow"_n;
act.name = name();
act.authorization = vector<permission_level>{{"negmemgrow"_n,config::active_name}};
trx.actions.push_back(act);

set_transaction_headers(trx);
trx.sign(get_private_key( "negmemgrow"_n, "active" ), control->get_chain_id());
push_transaction(trx);
produce_blocks(1);
}

set_code("negmemgrow"_n, negative_memory_grow_trap_wast);
produce_block();
{
signed_transaction trx;
action act;
act.account = "negmemgrow"_n;
act.name = name();
act.authorization = vector<permission_level>{{"negmemgrow"_n,config::active_name}};
trx.actions.push_back(act);

set_transaction_headers(trx);
trx.sign(get_private_key( "negmemgrow"_n, "active" ), control->get_chain_id());
BOOST_CHECK_THROW(push_transaction(trx), eosio::chain::wasm_execution_error);
}

} FC_LOG_AND_RETHROW()

// TODO: restore net_usage_tests
#if 0
Expand Down