未验证 提交 bf0db378 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #2897 from larryk85/fix/eos2818

Fix for eos#2818
...@@ -87,6 +87,8 @@ struct test_db { ...@@ -87,6 +87,8 @@ struct test_db {
static void idx_double_nan_create_fail(uint64_t receiver, uint64_t code, uint64_t action); static void idx_double_nan_create_fail(uint64_t receiver, uint64_t code, uint64_t action);
static void idx_double_nan_modify_fail(uint64_t receiver, uint64_t code, uint64_t action); static void idx_double_nan_modify_fail(uint64_t receiver, uint64_t code, uint64_t action);
static void idx_double_nan_lookup_fail(uint64_t receiver, uint64_t code, uint64_t action); static void idx_double_nan_lookup_fail(uint64_t receiver, uint64_t code, uint64_t action);
static void misaligned_secondary_key256_tests(uint64_t, uint64_t, uint64_t);
}; };
struct test_multi_index { struct test_multi_index {
......
...@@ -20,6 +20,7 @@ extern "C" { ...@@ -20,6 +20,7 @@ extern "C" {
WASM_TEST_HANDLER_EX(test_db, idx_double_nan_create_fail); WASM_TEST_HANDLER_EX(test_db, idx_double_nan_create_fail);
WASM_TEST_HANDLER_EX(test_db, idx_double_nan_modify_fail); WASM_TEST_HANDLER_EX(test_db, idx_double_nan_modify_fail);
WASM_TEST_HANDLER_EX(test_db, idx_double_nan_lookup_fail); WASM_TEST_HANDLER_EX(test_db, idx_double_nan_lookup_fail);
WASM_TEST_HANDLER_EX(test_db, misaligned_secondary_key256_tests);
//unhandled test call //unhandled test call
eosio_assert(false, "Unknown Test"); eosio_assert(false, "Unknown Test");
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <eosiolib/datastream.hpp> #include <eosiolib/datastream.hpp>
#include <eosiolib/db.h> #include <eosiolib/db.h>
#include <eosiolib/memory.hpp> #include <eosiolib/memory.hpp>
#include <eosiolib/fixed_key.hpp>
#include "../test_api/test_api.hpp" #include "../test_api/test_api.hpp"
int primary[11] = {0,1,2,3,4,5,6,7,8,9,10}; int primary[11] = {0,1,2,3,4,5,6,7,8,9,10};
...@@ -534,3 +535,13 @@ void test_db::idx_double_nan_lookup_fail(uint64_t receiver, uint64_t, uint64_t) ...@@ -534,3 +535,13 @@ void test_db::idx_double_nan_lookup_fail(uint64_t receiver, uint64_t, uint64_t)
eosio_assert( false, "idx_double_nan_lookup_fail: unexpected lookup_type" ); eosio_assert( false, "idx_double_nan_lookup_fail: unexpected lookup_type" );
} }
} }
void test_db::misaligned_secondary_key256_tests(uint64_t receiver, uint64_t, uint64_t) {
auto key = eosio::key256::make_from_word_sequence<uint64_t>(0ULL, 0ULL, 0ULL, 42ULL);
char* ptr = (char*)(&key);
ptr += 1;
// test that store doesn't crash on unaligned data
db_idx256_store( N(testapi), N(testtable), N(testapi), 1, (eosio::key256*)(ptr), 2 );
// test that find_primary doesn't crash on unaligned data
db_idx256_find_primary( N(testapi), N(testtable), N(testapi), (eosio::key256*)(ptr), 2, 0);
}
...@@ -163,7 +163,6 @@ namespace eosio { namespace chain { ...@@ -163,7 +163,6 @@ namespace eosio { namespace chain {
FC_ASSERT( result.header.producer == h.producer, "wrong producer specified" ); FC_ASSERT( result.header.producer == h.producer, "wrong producer specified" );
FC_ASSERT( result.header.schedule_version == h.schedule_version, "schedule_version in signed block is corrupted" ); FC_ASSERT( result.header.schedule_version == h.schedule_version, "schedule_version in signed block is corrupted" );
//idump((h.producer)(h.block_num()-h.confirmed)(h.block_num()));
auto itr = producer_to_last_produced.find(h.producer); auto itr = producer_to_last_produced.find(h.producer);
if( itr != producer_to_last_produced.end() ) { if( itr != producer_to_last_produced.end() ) {
FC_ASSERT( itr->second <= result.block_num - h.confirmed, "producer double-confirming known range" ); FC_ASSERT( itr->second <= result.block_num - h.confirmed, "producer double-confirming known range" );
......
...@@ -191,6 +191,10 @@ namespace eosio { namespace chain { ...@@ -191,6 +191,10 @@ namespace eosio { namespace chain {
FC_DECLARE_DERIVED_EXCEPTION( wasm_serialization_error, wasm_exception, FC_DECLARE_DERIVED_EXCEPTION( wasm_serialization_error, wasm_exception,
3070003, "Serialization Error Processing WASM" ) 3070003, "Serialization Error Processing WASM" )
FC_DECLARE_DERIVED_EXCEPTION( overlapping_memory_error, wasm_exception,
3070004, "memcpy with overlapping memory" )
FC_DECLARE_DERIVED_EXCEPTION( resource_exhausted_exception, chain_exception, FC_DECLARE_DERIVED_EXCEPTION( resource_exhausted_exception, chain_exception,
3080000, "resource exhausted exception" ) 3080000, "resource exhausted exception" )
......
...@@ -76,12 +76,12 @@ struct interpreter_interface : ModuleInstance::ExternalInterface { ...@@ -76,12 +76,12 @@ struct interpreter_interface : ModuleInstance::ExternalInterface {
FC_THROW_EXCEPTION(wasm_execution_error, why); FC_THROW_EXCEPTION(wasm_execution_error, why);
} }
void assert_memory_is_accessible(uint32_t offset, size_t size) { void assert_memory_is_accessible(uint32_t offset, uint32_t size) {
if (offset + size > current_memory_size || offset + size < offset) EOS_ASSERT(offset + size <= current_memory_size && offset + size >= offset,
FC_THROW_EXCEPTION(wasm_execution_error, "access violation"); wasm_execution_error, "access violation");
} }
char* get_validated_pointer(uint32_t offset, size_t size) { char* get_validated_pointer(uint32_t offset, uint32_t size) {
assert_memory_is_accessible(offset, size); assert_memory_is_accessible(offset, size);
return memory.data + offset; return memory.data + offset;
} }
...@@ -155,9 +155,9 @@ class binaryen_runtime : public eosio::chain::wasm_runtime_interface { ...@@ -155,9 +155,9 @@ class binaryen_runtime : public eosio::chain::wasm_runtime_interface {
* @tparam T * @tparam T
*/ */
template<typename T> template<typename T>
inline array_ptr<T> array_ptr_impl (interpreter_interface* interface, uint32_t ptr, size_t length) inline array_ptr<T> array_ptr_impl (interpreter_interface* interface, uint32_t ptr, uint32_t length)
{ {
return array_ptr<T>((T*)(interface->get_validated_pointer(ptr, length * sizeof(T)))); return array_ptr<T>((T*)(interface->get_validated_pointer(ptr, length * (uint32_t)sizeof(T))));
} }
/** /**
...@@ -348,13 +348,40 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>> ...@@ -348,13 +348,40 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>>
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>>;
using then_type = Ret(*)(interpreter_interface*, array_ptr<T>, size_t, Inputs..., LiteralList&, int); using then_type = Ret(*)(interpreter_interface*, array_ptr<T>, size_t, Inputs..., LiteralList&, int);
template<then_type Then> template<then_type Then, typename U=T>
static Ret translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) { static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t<std::is_const<U>::value, Ret> {
static_assert(!std::is_pointer<U>::value, "Currently don't support array of pointers");
uint32_t ptr = args.at(offset - 1).geti32(); uint32_t ptr = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti32(); size_t length = args.at(offset).geti32();
return Then(interface, array_ptr_impl<T>(interface, ptr, length), length, rest..., args, offset - 2); T* base = array_ptr_impl<T>(interface, ptr, length);
if ( reinterpret_cast<uintptr_t>(base) % alignof(T) != 0 ) {
wlog( "misaligned array of const values" );
std::remove_const_t<T> copy[length];
T* copy_ptr = &copy[0];
memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) );
return Then(interface, static_cast<array_ptr<T>>(copy_ptr), length, rest..., args, offset - 2);
}
return Then(interface, static_cast<array_ptr<T>>(base), length, rest..., args, offset - 2);
}; };
template<then_type Then, typename U=T>
static auto translate_one(interpreter_interface* interface, Inputs... rest, LiteralList& args, int offset) -> std::enable_if_t<!std::is_const<U>::value, Ret> {
static_assert(!std::is_pointer<U>::value, "Currently don't support array of pointers");
uint32_t ptr = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti32();
T* base = array_ptr_impl<T>(interface, ptr, length);
if ( reinterpret_cast<uintptr_t>(base) % alignof(T) != 0 ) {
wlog( "misaligned array of values" );
std::remove_const_t<T> copy[length];
T* copy_ptr = &copy[0];
memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) );
Ret ret = Then(interface, static_cast<array_ptr<T>>(copy_ptr), length, rest..., args, offset - 2);
memcpy( (void*)base, (void*)copy_ptr, length * sizeof(T) );
return ret;
}
return Then(interface, static_cast<array_ptr<T>>(base), length, rest..., args, offset - 2);
};
template<then_type Then> template<then_type Then>
static const auto fn() { static const auto fn() {
return next_step::template fn<translate_one<Then>>(); return next_step::template fn<translate_one<Then>>();
...@@ -404,7 +431,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, array_ptr<U>, size_t ...@@ -404,7 +431,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, array_ptr<U>, size_t
uint32_t ptr_t = args.at(offset - 2).geti32(); uint32_t ptr_t = args.at(offset - 2).geti32();
uint32_t ptr_u = args.at(offset - 1).geti32(); uint32_t ptr_u = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti32(); size_t length = args.at(offset).geti32();
assert(sizeof(T) == sizeof(U)); static_assert(std::is_same<std::remove_const_t<T>, char>::value && std::is_same<std::remove_const_t<U>, char>::value, "Currently only support array of (const)chars");
return Then(interface, array_ptr_impl<T>(interface, ptr_t, length), array_ptr_impl<U>(interface, ptr_u, length), length, args, offset - 3); return Then(interface, array_ptr_impl<T>(interface, ptr_t, length), array_ptr_impl<U>(interface, ptr_u, length), length, args, offset - 3);
}; };
......
...@@ -60,7 +60,7 @@ namespace eosio { namespace chain { ...@@ -60,7 +60,7 @@ namespace eosio { namespace chain {
} }
T *value; T *value;
}; };
/** /**
* class to represent an in-wasm-memory char array that must be null terminated * class to represent an in-wasm-memory char array that must be null terminated
......
...@@ -53,6 +53,8 @@ inline array_ptr<T> array_ptr_impl (running_instance_context& ctx, U32 ptr, size ...@@ -53,6 +53,8 @@ inline array_ptr<T> array_ptr_impl (running_instance_context& ctx, U32 ptr, size
size_t mem_total = IR::numBytesPerPage * Runtime::getMemoryNumPages(mem); size_t mem_total = IR::numBytesPerPage * Runtime::getMemoryNumPages(mem);
if (ptr >= mem_total || length > (mem_total - ptr) / sizeof(T)) if (ptr >= mem_total || length > (mem_total - ptr) / sizeof(T))
Runtime::causeException(Exception::Cause::accessViolation); Runtime::causeException(Exception::Cause::accessViolation);
T* ret_ptr = (T*)(getMemoryBaseAddress(mem) + ptr);
return array_ptr<T>((T*)(getMemoryBaseAddress(mem) + ptr)); return array_ptr<T>((T*)(getMemoryBaseAddress(mem) + ptr));
} }
...@@ -373,10 +375,36 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>, ...@@ -373,10 +375,36 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>,
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32, I32>>; using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32, I32>>;
using then_type = Ret(*)(running_instance_context&, array_ptr<T>, size_t, Inputs..., Translated...); using then_type = Ret(*)(running_instance_context&, array_ptr<T>, size_t, Inputs..., Translated...);
template<then_type Then> template<then_type Then, typename U=T>
static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) { static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t<std::is_const<U>::value, Ret> {
static_assert(!std::is_pointer<U>::value, "Currently don't support array of pointers");
const auto length = size_t(size);
T* base = array_ptr_impl<T>(ctx, ptr, length);
if ( reinterpret_cast<uintptr_t>(base) % alignof(T) != 0 ) {
wlog( "misaligned array of const values" );
std::remove_const_t<T> copy[length];
T* copy_ptr = &copy[0];
memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) );
return Then(ctx, static_cast<array_ptr<T>>(copy_ptr), length, rest..., translated...);
}
return Then(ctx, static_cast<array_ptr<T>>(base), length, rest..., translated...);
};
template<then_type Then, typename U=T>
static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr, I32 size) -> std::enable_if_t<!std::is_const<U>::value, Ret> {
static_assert(!std::is_pointer<U>::value, "Currently don't support array of pointers");
const auto length = size_t(size); const auto length = size_t(size);
return Then(ctx, array_ptr_impl<T>(ctx, ptr, length), length, rest..., translated...); T* base = array_ptr_impl<T>(ctx, ptr, length);
if ( reinterpret_cast<uintptr_t>(base) % alignof(T) != 0 ) {
wlog( "misaligned array of values" );
std::remove_const_t<T> copy[length];
T* copy_ptr = &copy[0];
memcpy( (void*)copy_ptr, (void*)base, length * sizeof(T) );
Ret ret = Then(ctx, static_cast<array_ptr<T>>(copy_ptr), length, rest..., translated...);
memcpy( (void*)base, (void*)copy_ptr, length * sizeof(T) );
return ret;
}
return Then(ctx, static_cast<array_ptr<T>>(base), length, rest..., translated...);
}; };
template<then_type Then> template<then_type Then>
...@@ -426,8 +454,8 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, array_ptr<U>, size_t ...@@ -426,8 +454,8 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, array_ptr<U>, size_t
template<then_type Then> template<then_type Then>
static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr_t, I32 ptr_u, I32 size) { static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr_t, I32 ptr_u, I32 size) {
static_assert(std::is_same<std::remove_const_t<T>, char>::value && std::is_same<std::remove_const_t<U>, char>::value, "Currently only support array of (const)chars");
const auto length = size_t(size); const auto length = size_t(size);
assert(sizeof(T)==sizeof(U));
return Then(ctx, array_ptr_impl<T>(ctx, ptr_t, length), array_ptr_impl<U>(ctx, ptr_u, length), length, rest..., translated...); return Then(ctx, array_ptr_impl<T>(ctx, ptr_t, length), array_ptr_impl<U>(ctx, ptr_u, length), length, rest..., translated...);
}; };
...@@ -535,32 +563,6 @@ struct intrinsic_invoker_impl<Ret, std::tuple<const name&, Inputs...>, std::tupl ...@@ -535,32 +563,6 @@ struct intrinsic_invoker_impl<Ret, std::tuple<const name&, Inputs...>, std::tupl
} }
}; };
/**
* Specialization for transcribing a reference to a fc::time_point_sec which can be passed as a native value
* This type transcribes into a native type which is loaded by value into a
* variable on the stack and then passed by reference to the intrinsic.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template<typename Ret, typename... Inputs, typename ...Translated>
struct intrinsic_invoker_impl<Ret, std::tuple<const fc::time_point_sec&, Inputs...>, std::tuple<Translated...>> {
using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., native_to_wasm_t<const fc::time_point_sec&> >>;
using then_type = Ret (*)(running_instance_context&, const fc::time_point_sec&, Inputs..., Translated...);
template<then_type Then>
static Ret translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, native_to_wasm_t<const fc::time_point_sec&> wasm_value) {
auto value = fc::time_point_sec(wasm_value);
return Then(ctx, value, rest..., translated...);
}
template<then_type Then>
static const auto fn() {
return next_step::template fn<translate_one<Then>>();
}
};
/** /**
* Specialization for transcribing a reference type in the native method signature * Specialization for transcribing a reference type in the native method signature
* This type transcribes into an int32 pointer checks the validity of that memory * This type transcribes into an int32 pointer checks the validity of that memory
......
...@@ -681,7 +681,7 @@ class producer_api : public context_aware_api { ...@@ -681,7 +681,7 @@ class producer_api : public context_aware_api {
auto copy_size = std::min( buffer_size, s ); auto copy_size = std::min( buffer_size, s );
memcpy( producers, active_producers.data(), copy_size ); memcpy( producers, active_producers.data(), copy_size );
return copy_size; return copy_size;
} }
}; };
...@@ -1208,6 +1208,8 @@ class memory_api : public context_aware_api { ...@@ -1208,6 +1208,8 @@ class memory_api : public context_aware_api {
:context_aware_api(ctx,true){} :context_aware_api(ctx,true){}
char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) { char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
EOS_ASSERT((abs((ptrdiff_t)dest.value - (ptrdiff_t)src.value)) >= length,
overlapping_memory_error, "memcpy can only accept non-aliasing pointers");
return (char *)::memcpy(dest, src, length); return (char *)::memcpy(dest, src, length);
} }
......
...@@ -1105,6 +1105,7 @@ BOOST_FIXTURE_TEST_CASE(db_tests, TESTER) { try { ...@@ -1105,6 +1105,7 @@ BOOST_FIXTURE_TEST_CASE(db_tests, TESTER) { try {
CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_db", "idx_double_nan_lookup_fail", fc::raw::pack(lookup_type), CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION( *this, "test_db", "idx_double_nan_lookup_fail", fc::raw::pack(lookup_type),
transaction_exception, "NaN is not an allowed value for a secondary key"); transaction_exception, "NaN is not an allowed value for a secondary key");
CALL_TEST_FUNCTION( *this, "test_db", "misaligned_secondary_key256_tests", {});
BOOST_REQUIRE_EQUAL( validate(), true ); BOOST_REQUIRE_EQUAL( validate(), true );
} FC_LOG_AND_RETHROW() } } FC_LOG_AND_RETHROW() }
...@@ -1299,9 +1300,9 @@ BOOST_FIXTURE_TEST_CASE(memory_tests, TESTER) { try { ...@@ -1299,9 +1300,9 @@ BOOST_FIXTURE_TEST_CASE(memory_tests, TESTER) { try {
#endif #endif
CALL_TEST_FUNCTION( *this, "test_memory", "test_memset_memcpy", {} ); CALL_TEST_FUNCTION( *this, "test_memory", "test_memset_memcpy", {} );
produce_blocks(1000); produce_blocks(1000);
CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_start", {} ); BOOST_CHECK_THROW( CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_start", {} ), overlapping_memory_error );
produce_blocks(1000); produce_blocks(1000);
CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_end", {} ); BOOST_CHECK_THROW( CALL_TEST_FUNCTION( *this, "test_memory", "test_memcpy_overlap_end", {} ), overlapping_memory_error );
produce_blocks(1000); produce_blocks(1000);
CALL_TEST_FUNCTION( *this, "test_memory", "test_memcmp", {} ); CALL_TEST_FUNCTION( *this, "test_memory", "test_memcmp", {} );
produce_blocks(1000); produce_blocks(1000);
......
...@@ -79,7 +79,7 @@ static const char misaligned_const_ref_wast[] = R"=====( ...@@ -79,7 +79,7 @@ static const char misaligned_const_ref_wast[] = R"=====(
(module (module
(import "env" "sha256" (func $sha256 (param i32 i32 i32))) (import "env" "sha256" (func $sha256 (param i32 i32 i32)))
(import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32))) (import "env" "assert_sha256" (func $assert_sha256 (param i32 i32 i32)))
(import "env" "memcpy" (func $memcpy (param i32 i32 i32) (result i32))) (import "env" "memmove" (func $memmove (param i32 i32 i32) (result i32)))
(table 0 anyfunc) (table 0 anyfunc)
(memory $0 32) (memory $0 32)
(data (i32.const 4) "hello") (data (i32.const 4) "hello")
...@@ -92,7 +92,7 @@ static const char misaligned_const_ref_wast[] = R"=====( ...@@ -92,7 +92,7 @@ static const char misaligned_const_ref_wast[] = R"=====(
(i32.const 16) (i32.const 16)
) )
(set_local $3 (set_local $3
(call $memcpy (call $memmove
(i32.const 17) (i32.const 17)
(i32.const 16) (i32.const 16)
(i32.const 64) (i32.const 64)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册