diff --git a/contracts/test_api/test_api.cpp b/contracts/test_api/test_api.cpp index fbe6688dc2e62238baa0fd668e5b32a6f4c00600..904d030a8f72976697d2666c0a1d7e09d800b8c7 100644 --- a/contracts/test_api/test_api.cpp +++ b/contracts/test_api/test_api.cpp @@ -62,10 +62,13 @@ extern "C" { //test transaction WASM_TEST_HANDLER(test_transaction, send_message); + WASM_TEST_HANDLER(test_transaction, send_message_empty); WASM_TEST_HANDLER(test_transaction, send_message_max); WASM_TEST_HANDLER(test_transaction, send_message_large); WASM_TEST_HANDLER(test_transaction, send_message_recurse); + WASM_TEST_HANDLER(test_transaction, send_message_inline_fail); WASM_TEST_HANDLER(test_transaction, send_transaction); + WASM_TEST_HANDLER(test_transaction, send_transaction_empty); WASM_TEST_HANDLER(test_transaction, send_transaction_max); WASM_TEST_HANDLER(test_transaction, send_transaction_large); diff --git a/contracts/test_api/test_api.hpp b/contracts/test_api/test_api.hpp index de0bcd65a59cb743c897611a48e8f07fb5d42fe0..0b4355d2aecc55433c39ec94c90fa33dff3bca7b 100644 --- a/contracts/test_api/test_api.hpp +++ b/contracts/test_api/test_api.hpp @@ -108,10 +108,13 @@ struct test_crypto { struct test_transaction { static unsigned int send_message(); + static unsigned int send_message_empty(); static unsigned int send_message_max(); static unsigned int send_message_large(); static unsigned int send_message_recurse(); + static unsigned int send_message_inline_fail(); static unsigned int send_transaction(); + static unsigned int send_transaction_empty(); static unsigned int send_transaction_max(); static unsigned int send_transaction_large(); }; diff --git a/contracts/test_api/test_transaction.cpp b/contracts/test_api/test_transaction.cpp index da7f1eadcae0810e7a04351b307946209f6e7eba..15092c2f086f6d66fa1515e49125f8049f06c399 100644 --- a/contracts/test_api/test_transaction.cpp +++ b/contracts/test_api/test_transaction.cpp @@ -10,15 +10,9 @@ unsigned int test_transaction::send_message() { return WASM_TEST_PASS; } -unsigned int test_transaction::send_transaction() { - dummy_message payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; - auto msg = messageCreate(N(testapi), WASM_TEST_ACTION("test_message", "read_message"), &payload, sizeof(dummy_message)); - - - auto trx = transactionCreate(); - transactionRequireScope(trx, N(testapi)); - transactionAddMessage(trx, msg); - transactionSend(trx); +unsigned int test_transaction::send_message_empty() { + auto msg = messageCreate(N(testapi), WASM_TEST_ACTION("test_message", "assert_true"), nullptr, 0); + messageSend(msg); return WASM_TEST_PASS; } @@ -54,6 +48,34 @@ unsigned int test_transaction::send_message_recurse() { return WASM_TEST_PASS; } +/** + * cause failure due to inline TX failure + */ +unsigned int test_transaction::send_message_inline_fail() { + auto msg = messageCreate(N(testapi), WASM_TEST_ACTION("test_message", "assert_false"), nullptr, 0); + messageSend(msg); + return WASM_TEST_PASS; +} + +unsigned int test_transaction::send_transaction() { + dummy_message payload = {DUMMY_MESSAGE_DEFAULT_A, DUMMY_MESSAGE_DEFAULT_B, DUMMY_MESSAGE_DEFAULT_C}; + auto msg = messageCreate(N(testapi), WASM_TEST_ACTION("test_message", "read_message"), &payload, sizeof(dummy_message)); + + + auto trx = transactionCreate(); + transactionRequireScope(trx, N(testapi)); + transactionAddMessage(trx, msg); + transactionSend(trx); + return WASM_TEST_PASS; +} + +unsigned int test_transaction::send_transaction_empty() { + auto trx = transactionCreate(); + transactionRequireScope(trx, N(testapi)); + transactionSend(trx); + return WASM_TEST_FAIL; +} + /** * cause failure due to too many pending deferred transactions */ diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 884c283fa1c32c741af713a12fcab0c4828ced83..278705472075b69aa2b837802da4114e7a07943f 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -290,18 +290,20 @@ DEFINE_INTRINSIC_FUNCTION4(env,messageCreate,messageCreate,i32,i64,code,i64,type auto& wasm = wasm_interface::get(); auto mem = wasm.current_memory; - EOS_ASSERT( length > 0, tx_unknown_argument, - "Attempting to push an empty message" ); + EOS_ASSERT( length >= 0, tx_unknown_argument, + "Pushing a message with a negative length" ); Bytes payload; - try { - // memoryArrayPtr checks that the entire array of bytes is valid and - // within the bounds of the memory segment so that transactions cannot pass - // bad values in attempts to read improper memory - const char* buffer = memoryArrayPtr( mem, uint32_t(data), uint32_t(length) ); - payload.insert(payload.end(), buffer, buffer + length); - } catch( const Runtime::Exception& e ) { - FC_THROW_EXCEPTION(tx_unknown_argument, "Message data is not a valid memory range"); + if (length > 0) { + try { + // memoryArrayPtr checks that the entire array of bytes is valid and + // within the bounds of the memory segment so that transactions cannot pass + // bad values in attempts to read improper memory + const char* buffer = memoryArrayPtr( mem, uint32_t(data), uint32_t(length) ); + payload.insert(payload.end(), buffer, buffer + length); + } catch( const Runtime::Exception& e ) { + FC_THROW_EXCEPTION(tx_unknown_argument, "Message data is not a valid memory range"); + } } auto& pmsg = wasm.current_apply_context->create_pending_message(Name(code), Name(type), payload); diff --git a/tests/api_tests/api_tests.cpp b/tests/api_tests/api_tests.cpp index 252bd01e9f832b3591727d9fbe81c9b4f826c93a..9b801526705b78f7374c9e916e637b844916e5ff 100644 --- a/tests/api_tests/api_tests.cpp +++ b/tests/api_tests/api_tests.cpp @@ -384,13 +384,18 @@ BOOST_FIXTURE_TEST_CASE(test_all, testing_fixture) //Test transaction BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message()"); + BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_empty"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message_empty()"); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_large"), {}, {} ), tx_resource_exhausted, is_tx_resource_exhausted ); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_max"), {}, {} ), tx_resource_exhausted, is_tx_resource_exhausted ); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_recurse"), {}, fc::raw::pack(dummy13) ), tx_resource_exhausted, is_tx_resource_exhausted ); + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_message_inline_fail"), {}, {} ), + fc::assert_exception, is_assert_exception ); BOOST_CHECK_MESSAGE( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction"), {}, {}) == WASM_TEST_PASS, "test_transaction::send_message()"); + BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_empty"), {}, {} ), + tx_unknown_argument, is_tx_unknown_argument ); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_large"), {}, {} ), tx_resource_exhausted, is_tx_resource_exhausted ); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( TEST_METHOD("test_transaction", "send_transaction_max"), {}, {} ),