提交 748f75da 编写于 作者: B Bucky Kittinger

Issue with injected code failing unexpectedly

上级 9c9d2243
......@@ -119,7 +119,6 @@ else( WIN32 ) # Apple AND Linux
#if(NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARIES)
# MESSAGE(FATAL_ERROR "Could not find lib readline.")
#endif()
if( APPLE )
# Apple Specific Options Here
message( STATUS "Configuring Eos on OS X" )
......@@ -128,7 +127,7 @@ else( WIN32 ) # Apple AND Linux
else( APPLE )
# Linux Specific Options Here
message( STATUS "Configuring Eos on Linux" )
set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall" )
set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++1z -Wc++1z-extensions -Wall" )
if ( FULL_STATIC_BUILD )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif ( FULL_STATIC_BUILD )
......
......@@ -11,7 +11,6 @@ add_library( eosio_chain
wasm_interface.cpp
wasm_eosio_constraints.cpp
wasm_eosio_injection.cpp
wasm_eosio_binary_ops.cpp
wasm_module_walker.cpp
apply_context.cpp
rate_limiting.cpp
......
......@@ -5,95 +5,51 @@
#include <functional>
#include <vector>
#include <iostream>
#include <map>
#include "IR/Module.h"
#include "IR/Operators.h"
#include "WASM/WASM.h"
namespace eosio { namespace chain { namespace wasm_injections {
// module validators
// effectively do nothing and pass
struct noop_injection_visitor {
static void inject( IR::Module& m );
static void initializer();
};
/*
static U32 checktimeIndex(const Module& module)
{
return module.functions.imports.size() - 1;
}
void setTypeSlot(const Module& module, ResultType returnType, const std::vector<ValueType>& parameterTypes)
{
if (returnType == ResultType::none && parameterTypes.size() == 1 && parameterTypes[0] == ValueType::i32 )
typeSlot = module.types.size() - 1;
}
void addTypeSlot(Module& module)
{
if (typeSlot < 0)
{
// add a type for void func(void)
typeSlot = module.types.size();
module.types.push_back(FunctionType::get(ResultType::none, std::vector<ValueType>(1, ValueType::i32)));
namespace eosio { namespace chain { namespace wasm_injections {
using namespace IR;
// helper functions for injection
struct injector_utils {
//static std::unordered_map<type_slot_pair, uint32_t, tsp_hasher > type_slots;
static std::map<std::vector<uint16_t>, uint32_t> type_slots;
static void init() { type_slots.clear(); }
template <ResultType Result, ValueType... Params>
static void add_type_slot( Module& mod ) {
if ( type_slots.find({FromResultType<Result>::value, FromValueType<Params>::value...}) == type_slots.end() ) {
type_slots.emplace( std::vector<uint16_t>{FromResultType<Result>::value, FromValueType<Params>::value...}, mod.types.size() );
mod.types.push_back( FunctionType::get( Result, { Params... } ) );
}
}
}
void addImport(Module& module)
{
if (module.functions.imports.size() == 0 || module.functions.imports.back().exportName.compare(u8"checktime") != 0) {
if (typeSlot < 0) {
addTypeSlot(module);
template <ResultType Result, ValueType... Params>
static void add_import(Module& module, const char* scope, const char* func_name, int32_t& index ) {
if (module.functions.imports.size() == 0 || module.functions.imports.back().exportName.compare(func_name) != 0) {
add_type_slot<Result, Params...>( module );
const uint32_t func_type_index = type_slots[{ FromResultType<Result>::value, FromValueType<Params>::value... }];
module.functions.imports.push_back({{func_type_index}, std::move(scope), std::move(func_name)});
index = module.functions.imports.size()-1;
// shift all exported functions by 1
for ( int i=0; i < module.exports.size(); i++ ) {
if ( module.exports[i].kind == IR::ObjectKind::function )
module.exports[i].index += 1;
}
}
const U32 functionTypeIndex = typeSlot;
module.functions.imports.push_back({{functionTypeIndex}, std::move(u8"env"), std::move(u8"checktime")});
}
}
void conditionallyAddCall(Opcode opcode, const ControlStructureImm& imm, Module& module, OperatorEncoderStream& operatorEncoderStream, CodeValidationStream& codeValidationStream)
{
switch(opcode)
{
case Opcode::loop:
case Opcode::block:
addCall(module, operatorEncoderStream, codeValidationStream);
default:
break;
};
}
template<typename Imm>
void conditionallyAddCall(Opcode , const Imm& , Module& , OperatorEncoderStream& , CodeValidationStream& )
{
}
void adjustIfFunctionIndex(Uptr& index, ObjectKind kind)
{
if (kind == ObjectKind::function)
++index;
}
void adjustExportIndex(Module& module)
{
// all function exports need to have their index increased to account for inserted definition
for (auto& exportDef : module.exports)
{
adjustIfFunctionIndex(exportDef.index, exportDef.kind);
}
}
void adjustCallIndex(const Module& module, CallImm& imm)
{
if (imm.functionIndex >= checktimeIndex(module))
++imm.functionIndex;
}
};
template<typename Imm>
void adjustCallIndex(const Module& , Imm& )
{
}
*/
struct noop_injection_visitor {
static void inject( IR::Module& m );
static void initializer();
};
struct memories_injection_visitor {
static void inject( IR::Module& m );
......@@ -114,7 +70,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
static void inject( IR::Module& m );
static void initializer();
};
struct blacklist_injection_visitor {
static void inject( IR::Module& m );
static void initializer();
......@@ -138,6 +94,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct debug_printer {
static constexpr bool kills = false;
static void init() {}
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
std::cout << "INSTRUCTION : " << inst->to_string() << "\n";
}
......@@ -145,6 +102,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct instruction_counter {
static constexpr bool kills = false;
static void init() { icnt = 0; }
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
// maybe change this later to variable weighting for different instruction types
icnt++;
......@@ -154,22 +112,23 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct checktime_injector {
static constexpr bool kills = false;
static void init() { checktime_idx = -1; }
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
// if (checktime_idx == -1)
// FC_THROW("Error, this should be run after module injector");
//std::cout << "HIT A BLOCK " << " " << index << "\n";
// first add the import for checktime
injector_utils::add_import<ResultType::none, ValueType::i32>( *(arg.module), u8"env", u8"checktime", checktime_idx );
wasm_ops::op_types<>::i32_const_t cnt;
cnt.field = instruction_counter::icnt;
wasm_ops::op_types<>::call_t chktm;
chktm.field = checktime_idx;
instruction_counter::icnt = 0;
// pack the ops for insertion
std::vector<U8> injected = cnt.pack();
std::vector<U8> tmp = chktm.pack();
injected.insert( injected.end(), tmp.begin(), tmp.end() );
//arg.new_code->insert( arg.new_code->end(), injected.begin(), injected.end() );
//arg.function_def->code.insert( arg.function_def->code.begin()+arg.code_index,
// injected.begin(), injected.end() );
arg.new_code->insert( arg.new_code->end(), injected.begin(), injected.end() );
}
static int32_t checktime_idx;
};
......@@ -327,8 +286,9 @@ namespace eosio { namespace chain { namespace wasm_injections {
wasm_binary_injection() {
_module_injectors.init();
// initialize static fields of injectors
instruction_counter::icnt = 0;
checktime_injector::checktime_idx = -1;
//injector_utils::init();
instruction_counter::init();
checktime_injector::init();
}
static void inject( IR::Module& mod ) {
......@@ -338,17 +298,9 @@ namespace eosio { namespace chain { namespace wasm_injections {
std::vector<U8> new_code;
while ( decoder ) {
auto op = decoder.decodeOp();
std::vector<U8>::iterator decoded_index = (fd.code.begin() + decoder.index());
op->visit( { &mod, &new_code, &fd, decoder.index() } );
}
for ( int i=0; i < new_code.size(); i++ )
std::cout <<std::hex << uint32_t(new_code[i]) << ", ";
std::cout << "\n";
for ( int i=0; i < fd.code.size(); i++ )
std::cout << std::hex << uint32_t(fd.code[i]) << ", ";
std::cout << "\n";
fd.code = new_code;
}
}
......
#pragma once
#include <fc/exception/exception.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wasm_eosio_binary_ops.hpp>
#include <functional>
#include <vector>
......@@ -48,6 +49,8 @@ namespace eosio { namespace chain { namespace wasm_constraints {
// instruction validators
// simple mutator that doesn't actually mutate anything
// used to verify that a given instruction is valid for execution on our platform
// for validators set kills to true, this eliminates the extraneous building
// of new code that is going to get thrown away any way
struct whitelist_validator {
static constexpr bool kills = true;
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
......@@ -55,6 +58,17 @@ namespace eosio { namespace chain { namespace wasm_constraints {
}
};
struct large_offset_validator {
static constexpr bool kills = true;
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
// cast to a type that has a memarg field
wasm_ops::op_types<>::i32_load_t* memarg_instr = reinterpret_cast<wasm_ops::op_types<>::i32_load_t*>(inst);
if(memarg_instr->field.o >= wasm_constraints::maximum_linear_memory)
FC_THROW_EXCEPTION(wasm_execution_error, "Smart contract used an invalid large memory store/load offset");
}
};
struct wasm_opcode_no_disposition_exception {
std::string opcode_name;
};
......@@ -62,7 +76,8 @@ namespace eosio { namespace chain { namespace wasm_constraints {
struct blacklist_validator {
static constexpr bool kills = true;
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
throw wasm_opcode_no_disposition_exception { inst->to_string() };
FC_THROW_EXCEPTION(wasm_execution_error, "Error, blacklisted opcode ${op} ",
("op", inst->to_string()));
}
};
......@@ -92,29 +107,29 @@ namespace eosio { namespace chain { namespace wasm_constraints {
using set_global_t = wasm_ops::set_global <whitelist_validator>;
using nop_t = wasm_ops::nop <whitelist_validator>;
using i32_load_t = wasm_ops::i32_load <whitelist_validator>;
using i64_load_t = wasm_ops::i64_load <whitelist_validator>;
using f32_load_t = wasm_ops::f32_load <whitelist_validator>;
using f64_load_t = wasm_ops::f64_load <whitelist_validator>;
using i32_load8_s_t = wasm_ops::i32_load8_s <whitelist_validator>;
using i32_load8_u_t = wasm_ops::i32_load8_u <whitelist_validator>;
using i32_load16_s_t = wasm_ops::i32_load16_s <whitelist_validator>;
using i32_load16_u_t = wasm_ops::i32_load16_u <whitelist_validator>;
using i64_load8_s_t = wasm_ops::i64_load8_s <whitelist_validator>;
using i64_load8_u_t = wasm_ops::i64_load8_u <whitelist_validator>;
using i64_load16_s_t = wasm_ops::i64_load16_s <whitelist_validator>;
using i64_load16_u_t = wasm_ops::i64_load16_u <whitelist_validator>;
using i64_load32_s_t = wasm_ops::i64_load32_s <whitelist_validator>;
using i64_load32_u_t = wasm_ops::i64_load32_u <whitelist_validator>;
using i32_store_t = wasm_ops::i32_store <whitelist_validator>;
using i64_store_t = wasm_ops::i64_store <whitelist_validator>;
using f32_store_t = wasm_ops::f32_store <whitelist_validator>;
using f64_store_t = wasm_ops::f64_store <whitelist_validator>;
using i32_store8_t = wasm_ops::i32_store8 <whitelist_validator>;
using i32_store16_t = wasm_ops::i32_store16 <whitelist_validator>;
using i64_store8_t = wasm_ops::i64_store8 <whitelist_validator>;
using i64_store16_t = wasm_ops::i64_store16 <whitelist_validator>;
using i64_store32_t = wasm_ops::i64_store32 <whitelist_validator>;
using i32_load_t = wasm_ops::i32_load <large_offset_validator, whitelist_validator>;
using i64_load_t = wasm_ops::i64_load <large_offset_validator, whitelist_validator>;
using f32_load_t = wasm_ops::f32_load <large_offset_validator, whitelist_validator>;
using f64_load_t = wasm_ops::f64_load <large_offset_validator, whitelist_validator>;
using i32_load8_s_t = wasm_ops::i32_load8_s <large_offset_validator, whitelist_validator>;
using i32_load8_u_t = wasm_ops::i32_load8_u <large_offset_validator, whitelist_validator>;
using i32_load16_s_t = wasm_ops::i32_load16_s <large_offset_validator, whitelist_validator>;
using i32_load16_u_t = wasm_ops::i32_load16_u <large_offset_validator, whitelist_validator>;
using i64_load8_s_t = wasm_ops::i64_load8_s <large_offset_validator, whitelist_validator>;
using i64_load8_u_t = wasm_ops::i64_load8_u <large_offset_validator, whitelist_validator>;
using i64_load16_s_t = wasm_ops::i64_load16_s <large_offset_validator, whitelist_validator>;
using i64_load16_u_t = wasm_ops::i64_load16_u <large_offset_validator, whitelist_validator>;
using i64_load32_s_t = wasm_ops::i64_load32_s <large_offset_validator, whitelist_validator>;
using i64_load32_u_t = wasm_ops::i64_load32_u <large_offset_validator, whitelist_validator>;
using i32_store_t = wasm_ops::i32_store <large_offset_validator, whitelist_validator>;
using i64_store_t = wasm_ops::i64_store <large_offset_validator, whitelist_validator>;
using f32_store_t = wasm_ops::f32_store <large_offset_validator, whitelist_validator>;
using f64_store_t = wasm_ops::f64_store <large_offset_validator, whitelist_validator>;
using i32_store8_t = wasm_ops::i32_store8 <large_offset_validator, whitelist_validator>;
using i32_store16_t = wasm_ops::i32_store16 <large_offset_validator, whitelist_validator>;
using i64_store8_t = wasm_ops::i64_store8 <large_offset_validator, whitelist_validator>;
using i64_store16_t = wasm_ops::i64_store16 <large_offset_validator, whitelist_validator>;
using i64_store32_t = wasm_ops::i64_store32 <large_offset_validator, whitelist_validator>;
using i32_const_t = wasm_ops::i32_const <whitelist_validator>;
using i64_const_t = wasm_ops::i64_const <whitelist_validator>;
......
......@@ -9,57 +9,63 @@
namespace eosio { namespace chain { namespace wasm_ops {
using namespace IR;
std::string to_string( NoImm imm ) {
inline std::string to_string( NoImm imm ) {
return "no imm";
}
std::string to_string( MemoryImm imm ) {
inline std::string to_string( MemoryImm imm ) {
return "memory imm";
}
std::string to_string( CallImm imm ) {
inline std::string to_string( CallImm imm ) {
return "call index : "+std::to_string(uint32_t(imm.functionIndex));
}
std::string to_string( CallIndirectImm imm ) {
inline std::string to_string( CallIndirectImm imm ) {
return "call indirect type : "+std::to_string(uint32_t(imm.type.index));
}
std::string to_string( uint32_t field ) {
inline std::string to_string( uint32_t field ) {
return std::string("i32 : ")+std::to_string(field);
}
std::string to_string( uint64_t field ) {
inline std::string to_string( uint64_t field ) {
return std::string("i64 : ")+std::to_string(field);
}
std::string to_string( blocktype field ) {
inline std::string to_string( blocktype field ) {
return std::string("blocktype : ")+std::to_string((uint32_t)field.result);
}
std::string to_string( memoryoptype field ) {
inline std::string to_string( memoryoptype field ) {
return std::string("memoryoptype : ")+std::to_string((uint32_t)field.end);
}
std::string to_string( memarg field ) {
inline std::string to_string( memarg field ) {
return std::string("memarg : ")+std::to_string(field.a)+std::string(", ")+std::to_string(field.o);
}
std::string to_string( callindirecttype field ) {
return std::string("callindirecttype : ")+
std::to_string(field.funcidx)+std::string(", ")+std::to_string((uint32_t)field.end);
inline std::string to_string( branchtabletype field ) {
return std::string("branchtabletype : ")+std::to_string(field.target_depth)+std::string(", ")+std::to_string(field.table_index);
}
std::vector<U8> pack( uint32_t field ) {
return { U8(field >> 24), U8(field >> 16), U8(field >> 8), U8(field) };
inline std::vector<U8> pack( uint32_t field ) {
return { U8(field), U8(field >> 8), U8(field >> 16), U8(field >> 24) };
}
std::vector<U8> pack( uint64_t field ) {
return { U8(field >> 56), U8(field >> 48), U8(field >> 40), U8(field >> 32),
U8(field >> 24), U8(field >> 16), U8(field >> 8), U8(field) };
inline std::vector<U8> pack( uint64_t field ) {
return { U8(field), U8(field >> 8), U8(field >> 16), U8(field >> 24),
U8(field >> 32), U8(field >> 40), U8(field >> 48), U8(field >> 56)
};
}
std::vector<U8> pack( blocktype field ) {
inline std::vector<U8> pack( blocktype field ) {
return { U8(field.result) };
}
std::vector<U8> pack( memoryoptype field ) {
inline std::vector<U8> pack( memoryoptype field ) {
return { U8(field.end) };
}
std::vector<U8> pack( memarg field ) {
return { U8(field.a >> 24), U8(field.a >> 16), U8(field.a >> 8), U8(field.a),
U8(field.o >> 24), U8(field.o >> 16), U8(field.o >> 8), U8(field.o) };
inline std::vector<U8> pack( memarg field ) {
return { U8(field.a), U8(field.a >> 8), U8(field.a >> 16), U8(field.a >> 24),
U8(field.o), U8(field.o >> 8), U8(field.o >> 16), U8(field.o >> 24),
};
}
std::vector<U8> pack( callindirecttype field ) {
return { U8(field.funcidx >> 24), U8(field.funcidx >> 16), U8(field.funcidx >> 8), U8(field.funcidx),
U8(field.end) };
inline std::vector<U8> pack( branchtabletype field ) {
return { U8(field.target_depth), U8(field.target_depth >> 8), U8(field.target_depth >> 16), U8(field.target_depth >> 24),
U8(field.target_depth >> 32), U8(field.target_depth >> 40), U8(field.target_depth >> 48), U8(field.target_depth >> 56),
U8(field.table_index), U8(field.table_index >> 8), U8(field.table_index >> 16), U8(field.table_index >> 24),
U8(field.table_index >> 32), U8(field.table_index >> 40), U8(field.table_index >> 48), U8(field.table_index >> 56)
};
}
}}} // namespace eosio, chain, wasm_ops
......@@ -9,14 +9,9 @@
namespace eosio { namespace chain { namespace wasm_injections {
using namespace IR;
/*
std::string to_string( ControlStructureImm imm ) {
return "result type : "+std::to_string(uint32_t(imm.resultType));
}
std::string to_string( BranchImm imm ) {
return "branch target : "+std::to_string(uint32_t(imm.targetDepth));
}
*/
//std::unordered_map<type_slot_pair, uint32_t, tsp_hasher> injector_utils::type_slots;
std::map<std::vector<uint16_t>, uint32_t> injector_utils::type_slots;
void noop_injection_visitor::inject( Module& m ) { /* just pass */ }
void noop_injection_visitor::initializer() { /* just pass */ }
......
......@@ -185,128 +185,110 @@ namespace eosio { namespace chain {
fc::optional<binaryen::info> binaryen_info;
try {
#if 0
IR::Module* module = new IR::Module();
IR::Module* module2 = new IR::Module();
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
WASM::serializeWithInjection(stream, *module);
validate_eosio_wasm_constraints(*module);
wasm_module_walker<
wasm_constraints::constraints_validators<wasm_constraints::memories_validator,
wasm_constraints::data_segments_validator,
wasm_constraints::tables_validator,
wasm_constraints::globals_validator>,
wasm_constraints::constraints_validators<wasm_constraints::memories_validator,
wasm_constraints::data_segments_validator,
wasm_constraints::tables_validator,
wasm_constraints::globals_validator>>
wmw(*module);
wasm_ops::wasm_instr_ptr nopi = std::make_shared< wasm_ops::nop<test_mutator> >();
wasm_ops::wasm_instr_ptr blocki = std::make_shared< wasm_ops::block<test_mutator2> >();
wasm_ops::op_types<test_mutator>::block_t b;
wasm_ops::op_types<test_mutator>::i64_popcount_t ipc;
wasm_ops::nop<test_mutator> n;
wasm_ops::call<test_mutator> br;
br.field = 23;
wasm_rewriter::op_constrainers::f32_add_t f32;
b.visit();
ipc.visit();
wmw.pre_validate();
for (auto def : module->functions.defs) {
char* code = (char*)(def.code.data());
char* code_end = code+def.code.size();
std::cout << "FUNC " << "\n";
uint32_t it = 0;
/*
while ( it < def.code.size() ) {
std::cout << "OPCODE " << std::hex << (uint32_t)code[it] << "\n";
it++;
}
*/
it = 0;
for (FunctionDef& fd : module->functions.defs ) {
OperatorDecoderStream decoder(fd.code);
while (decoder) {
std::cout << "OP " << std::hex << (uint32_t)decoder.decodeOp() << "\n";
wasm_ops::instr* op = wasm_ops::get_instr_from_op<wasm_ops::op_types<>>(*(decoder.index));
std::cout << "OP2 " << op->to_string() << " " << (uint32_t)((wasm_ops::i32_const<test_mutator>*)op)->field << "\n";
/*
if ( op->get_code() == 0x41 )
else
std::cout << "OP2 " << std::hex << (uint32_t)op->get_code() << " " << op->to_string() << "\n";
*/
}
Serialization::MemoryInputStream stream2((const U8 *) wasm_binary, wasm_binary_size);
WASM::serialize(stream, *module);
WASM::serializeWithInjection(stream2, *module2);
wasm_constraints::wasm_binary_validation::validate( *module );
wasm_injections::wasm_binary_injection::inject( *module );
/*
std::cout << "INJECTED\n";
wasm_injections::wasm_binary_injection::inject( *module );
std::cout << "INJECTEDSS\n";
wasm_injections::wasm_binary_injection::inject( *module2 );
auto restype = [](IR::ResultType f){
if (f == IR::ResultType::none ) return "none";
if (f == IR::ResultType::i32 ) return "i32";
if (f == IR::ResultType::i64 ) return "i64";
if (f == IR::ResultType::f32 ) return "f32";
if (f == IR::ResultType::f64 ) return "f64";
};
auto valtype = [](IR::ValueType f){
if (f == IR::ValueType::any ) return "any";
if (f == IR::ValueType::i32 ) return "i32";
if (f == IR::ValueType::i64 ) return "i64";
if (f == IR::ValueType::f32 ) return "f32";
if (f == IR::ValueType::f64 ) return "f64";
};
std::cout << "FUNCTION_Type A \n";
for (auto e : module->types) {
std::cout << "Function ("<< restype(e->ret) << ") (";
for (auto ee : e->parameters) {
std::cout << valtype(ee) << ", ";
}
/*
while ( it < def.code.size() ) {
std::cout << "OPCODE " << std::hex << (uint32_t)code[it] << "\n";
wasm_ops::instr* op = wasm_ops::get_instr_from_op<wasm_ops::op_types<>>(code[it]);
it = op->unpack( def.code, it );
if ( op->get_code() == 0x41 )
std::cout << "OP " << op->to_string() << " " << (uint32_t)((wasm_ops::i32_const<test_mutator>*)op)->field << "\n";
else if ( op->get_code() == 0x42 )
std::cout << "OP " << op->to_string() << " " << (uint32_t)((wasm_ops::i32_const<test_mutator>*)op)->field << "\n";
else
std::cout << "OP " << op->to_string() << "\n";
}
std::cout << "\n";
std::cout << "FUNCTION_Type B \n";
for (auto e : module->types) {
std::cout << "Function ("<< restype(e->ret) << ") (";
for (auto ee : e->parameters) {
std::cout << valtype(ee) << ", ";
}
*/
//std::cout << (int)n << " ";
}
/*
std::cout << "\n";
uint8_t* buff = new uint8_t[3];
buff[0] = wasm_ops::block_code;
buff[1] = 120;
//buff[2] = wasm_ops::nop_code;
buff[2] = 34;
std::vector<uint8_t> code = {wasm_ops::block_code, 13, wasm_ops::nop_code};
// wasm_ops::instr* block_ = new wasm_ops::wasm_op_table::which_pointer<wasm_ops::op_types<test_mutator2>, wasm_ops::block_code>::instr_t((char*)buff);
// wasm_ops::instr* nop_ = new wasm_ops::wasm_op_table::which_pointer<wasm_ops::op_types<test_mutator2>, wasm_ops::nop_code>::instr_t(block_->skip_ahead((char*)buff));
wasm_ops::instr* block_ = wasm_ops::get_instr_from_op<wasm_ops::op_types<test_mutator2>>(wasm_ops::block_code);
wasm_ops::instr* nop_ = wasm_ops::get_instr_from_op<wasm_ops::op_types<test_mutator2>>(wasm_ops::nop_code);
datastream<uint8_t*> ds( code.data(), code.size() );
//fc::raw::unpack(ds, *nop_);
block_->visit();
std::cout << "FIELD : " << (uint64_t)((wasm_ops::block<test_mutator>*)block_)->field.result << "\n";
std::cout << "CODE : " << (int)block_->get_code() << "NAME : " << block_->to_string() << "\n";
std::cout << "CODE : " << (int)nop_->get_code() << "NAME : " << nop_->to_string() << "\n";
std::cout << "FUNCTION_Import A \n";
for (auto e : module->functions.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "FUNCTION_Import B \n";
for (auto e : module2->functions.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "TABLES_Import A \n";
for (auto e : module->tables.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "TABLES_Import B \n";
for (auto e : module2->tables.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "MEMORIES_Import A \n";
for (auto e : module->memories.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "MEMORIES_Import B \n";
for (auto e : module2->memories.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "GLOBALS_Import A \n";
for (auto e : module->globals.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "GLOBALS_Import B \n";
for (auto e : module2->globals.imports)
std::cout << e.exportName << "\n";
std::cout << "\n";
std::cout << "EXPORT A \n";
for (auto e : module->exports)
std::cout << e.name << " " << uint32_t(e.index) << "\n";
std::cout << "\n";
std::cout << "EXPORT B \n";
for (auto e : module2->exports)
std::cout << e.name << " " << uint32_t(e.index) << "\n";
std::cout << "\n";
*/
root_resolver resolver;
LinkResult link_result = linkModule(*module, resolver);
instance = instantiateModule(*module, std::move(link_result.resolvedImports));
FC_ASSERT(instance != nullptr);
//populate the module's data segments in to a vector so the initial state can be
// restored on each invocation
//Be Warned, this may need to be revisited when module imports make sense. The
// code won't handle data segments that initalize an imported memory which I think
// is valid.
for(const DataSegment& data_segment : module->dataSegments) {
FC_ASSERT(data_segment.baseOffset.type == InitializerExpression::Type::i32_const);
FC_ASSERT(module->memories.defs.size());
const U32 base_offset = data_segment.baseOffset.i32;
const Uptr memory_size = (module->memories.defs[0].type.size.min << IR::numBytesPerPageLog2);
if(base_offset >= memory_size || base_offset + data_segment.data.size() > memory_size)
FC_THROW_EXCEPTION(wasm_execution_error, "WASM data segment outside of valid memory range");
if(base_offset + data_segment.data.size() > mem_image.size())
mem_image.resize(base_offset + data_segment.data.size(), 0x00);
memcpy(mem_image.data() + base_offset, data_segment.data.data(), data_segment.data.size());
}
#endif
/// TODO: make validation generic
IR::Module* module = new IR::Module();
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
wasm_constraints::wasm_binary_validation::validate( *module );
WASM::serialize(stream, *module);
Serialization::ArrayOutputStream outstream;
wasm_constraints::wasm_binary_validation::validate( *module );
wasm_injections::wasm_binary_injection::inject( *module );
Serialization::ArrayOutputStream outstream;
WASM::serialize(outstream, *module);
std::vector<U8> bytes = outstream.getBytes();
wavm = wavm::entry::build((char*)bytes.data(), bytes.size());
wavm_info.emplace(*wavm);
......@@ -613,6 +595,7 @@ public:
using context_aware_api::context_aware_api;
void checktime(uint32_t instruction_count) {
std::cout << "CHECKTIME\n";
context.checktime(instruction_count);
}
};
......
......@@ -159,7 +159,7 @@ entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
WasmBinaryBuilder builder(*module, code, false);
builder.read();
inject_checktime(*module.get());
//inject_checktime(*module.get());
FC_ASSERT(module->memory.initial * Memory::kPageSize <= wasm_constraints::maximum_linear_memory);
......@@ -226,4 +226,4 @@ entry::entry(unique_ptr<Module>&& module, linear_memory_type&& memory, call_indi
}
}}}}
\ No newline at end of file
}}}}
......@@ -120,9 +120,7 @@ void entry::prepare( const info& base_info ) {
entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
Module* module = new Module();
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
WASM::serializeWithInjection(stream, *module);
// TODO clean this up
//validate_eosio_wasm_constraints(*module);
WASM::serialize(stream, *module);
root_resolver resolver;
LinkResult link_result = linkModule(*module, resolver);
......
......@@ -25,6 +25,7 @@ namespace IR
struct BranchTableImm
{
static_assert(sizeof(Uptr) == 8, "SIZEE");
Uptr defaultTargetDepth;
Uptr branchTableIndex; // An index into the FunctionDef's branchTables array.
};
......
......@@ -26,6 +26,21 @@ namespace IR
max = num-1
};
template<ValueType type> struct FromValueType;
template<> struct FromValueType<ValueType::any> { static constexpr uint16_t value = 0; };
template<> struct FromValueType<ValueType::i32> { static constexpr uint16_t value = 1; };
template<> struct FromValueType<ValueType::i64> { static constexpr uint16_t value = 2; };
template<> struct FromValueType<ValueType::f32> { static constexpr uint16_t value = 3; };
template<> struct FromValueType<ValueType::f64> { static constexpr uint16_t value = 4; };
template<uint16_t type> struct ToValueType;
template<> struct ToValueType<0> { static constexpr ValueType value = ValueType::any; };
template<> struct ToValueType<1> { static constexpr ValueType value = ValueType::i32; };
template<> struct ToValueType<2> { static constexpr ValueType value = ValueType::i64; };
template<> struct ToValueType<3> { static constexpr ValueType value = ValueType::f32; };
template<> struct ToValueType<4> { static constexpr ValueType value = ValueType::f64; };
template<ValueType type> struct ValueTypeInfo;
template<> struct ValueTypeInfo<ValueType::i32> { typedef I32 Value; };
template<> struct ValueTypeInfo<ValueType::i64> { typedef I64 Value; };
......@@ -128,7 +143,22 @@ namespace IR
num,
max = num-1,
};
template<uint16_t type> struct ToResultType;
template<> struct ToResultType<0> { static constexpr ResultType value = ResultType::none; };
template<> struct ToResultType<1> { static constexpr ResultType value = ResultType::i32; };
template<> struct ToResultType<2> { static constexpr ResultType value = ResultType::i64; };
template<> struct ToResultType<3> { static constexpr ResultType value = ResultType::f32; };
template<> struct ToResultType<4> { static constexpr ResultType value = ResultType::f64; };
template<ResultType type> struct FromResultType;
template<> struct FromResultType<ResultType::none> { static constexpr uint16_t value = 0; };
template<> struct FromResultType<ResultType::i32> { static constexpr uint16_t value = 1; };
template<> struct FromResultType<ResultType::i64> { static constexpr uint16_t value = 2; };
template<> struct FromResultType<ResultType::f32> { static constexpr uint16_t value = 3; };
template<> struct FromResultType<ResultType::f64> { static constexpr uint16_t value = 4; };
inline Uptr getArity(ResultType returnType) { return returnType == ResultType::none ? 0 : 1; }
inline const char* asString(ResultType type)
......@@ -337,4 +367,4 @@ namespace IR
default: Errors::unreachable();
};
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册