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

Issue with injected code failing unexpectedly

上级 9c9d2243
...@@ -119,7 +119,6 @@ else( WIN32 ) # Apple AND Linux ...@@ -119,7 +119,6 @@ else( WIN32 ) # Apple AND Linux
#if(NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARIES) #if(NOT READLINE_INCLUDE_DIR OR NOT READLINE_LIBRARIES)
# MESSAGE(FATAL_ERROR "Could not find lib readline.") # MESSAGE(FATAL_ERROR "Could not find lib readline.")
#endif() #endif()
if( APPLE ) if( APPLE )
# Apple Specific Options Here # Apple Specific Options Here
message( STATUS "Configuring Eos on OS X" ) message( STATUS "Configuring Eos on OS X" )
...@@ -128,7 +127,7 @@ else( WIN32 ) # Apple AND Linux ...@@ -128,7 +127,7 @@ else( WIN32 ) # Apple AND Linux
else( APPLE ) else( APPLE )
# Linux Specific Options Here # Linux Specific Options Here
message( STATUS "Configuring Eos on Linux" ) 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 ) if ( FULL_STATIC_BUILD )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif ( FULL_STATIC_BUILD ) endif ( FULL_STATIC_BUILD )
......
...@@ -11,7 +11,6 @@ add_library( eosio_chain ...@@ -11,7 +11,6 @@ add_library( eosio_chain
wasm_interface.cpp wasm_interface.cpp
wasm_eosio_constraints.cpp wasm_eosio_constraints.cpp
wasm_eosio_injection.cpp wasm_eosio_injection.cpp
wasm_eosio_binary_ops.cpp
wasm_module_walker.cpp wasm_module_walker.cpp
apply_context.cpp apply_context.cpp
rate_limiting.cpp rate_limiting.cpp
......
...@@ -5,95 +5,51 @@ ...@@ -5,95 +5,51 @@
#include <functional> #include <functional>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <map>
#include "IR/Module.h" #include "IR/Module.h"
#include "IR/Operators.h" #include "IR/Operators.h"
#include "WASM/WASM.h" #include "WASM/WASM.h"
namespace eosio { namespace chain { namespace wasm_injections {
// module validators namespace eosio { namespace chain { namespace wasm_injections {
// effectively do nothing and pass using namespace IR;
struct noop_injection_visitor { // helper functions for injection
static void inject( IR::Module& m );
static void initializer(); 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 U32 checktimeIndex(const Module& module) static void init() { type_slots.clear(); }
{
return module.functions.imports.size() - 1; 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() ) {
void setTypeSlot(const Module& module, ResultType returnType, const std::vector<ValueType>& parameterTypes) type_slots.emplace( std::vector<uint16_t>{FromResultType<Result>::value, FromValueType<Params>::value...}, mod.types.size() );
{ mod.types.push_back( FunctionType::get( Result, { Params... } ) );
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)));
} }
}
void addImport(Module& 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(u8"checktime") != 0) { if (module.functions.imports.size() == 0 || module.functions.imports.back().exportName.compare(func_name) != 0) {
if (typeSlot < 0) { add_type_slot<Result, Params...>( module );
addTypeSlot(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> struct noop_injection_visitor {
void adjustCallIndex(const Module& , Imm& ) static void inject( IR::Module& m );
{ static void initializer();
} };
*/
struct memories_injection_visitor { struct memories_injection_visitor {
static void inject( IR::Module& m ); static void inject( IR::Module& m );
...@@ -114,7 +70,7 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -114,7 +70,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
static void inject( IR::Module& m ); static void inject( IR::Module& m );
static void initializer(); static void initializer();
}; };
struct blacklist_injection_visitor { struct blacklist_injection_visitor {
static void inject( IR::Module& m ); static void inject( IR::Module& m );
static void initializer(); static void initializer();
...@@ -138,6 +94,7 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -138,6 +94,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct debug_printer { struct debug_printer {
static constexpr bool kills = false; static constexpr bool kills = false;
static void init() {}
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
std::cout << "INSTRUCTION : " << inst->to_string() << "\n"; std::cout << "INSTRUCTION : " << inst->to_string() << "\n";
} }
...@@ -145,6 +102,7 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -145,6 +102,7 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct instruction_counter { struct instruction_counter {
static constexpr bool kills = false; static constexpr bool kills = false;
static void init() { icnt = 0; }
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
// maybe change this later to variable weighting for different instruction types // maybe change this later to variable weighting for different instruction types
icnt++; icnt++;
...@@ -154,22 +112,23 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -154,22 +112,23 @@ namespace eosio { namespace chain { namespace wasm_injections {
struct checktime_injector { struct checktime_injector {
static constexpr bool kills = false; static constexpr bool kills = false;
static void init() { checktime_idx = -1; }
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
// if (checktime_idx == -1) // first add the import for checktime
// FC_THROW("Error, this should be run after module injector"); injector_utils::add_import<ResultType::none, ValueType::i32>( *(arg.module), u8"env", u8"checktime", checktime_idx );
//std::cout << "HIT A BLOCK " << " " << index << "\n";
wasm_ops::op_types<>::i32_const_t cnt; wasm_ops::op_types<>::i32_const_t cnt;
cnt.field = instruction_counter::icnt; cnt.field = instruction_counter::icnt;
wasm_ops::op_types<>::call_t chktm; wasm_ops::op_types<>::call_t chktm;
chktm.field = checktime_idx; chktm.field = checktime_idx;
instruction_counter::icnt = 0; instruction_counter::icnt = 0;
// pack the ops for insertion // pack the ops for insertion
std::vector<U8> injected = cnt.pack(); std::vector<U8> injected = cnt.pack();
std::vector<U8> tmp = chktm.pack(); std::vector<U8> tmp = chktm.pack();
injected.insert( injected.end(), tmp.begin(), tmp.end() ); injected.insert( injected.end(), tmp.begin(), tmp.end() );
//arg.new_code->insert( arg.new_code->end(), injected.begin(), injected.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() );
} }
static int32_t checktime_idx; static int32_t checktime_idx;
}; };
...@@ -327,8 +286,9 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -327,8 +286,9 @@ namespace eosio { namespace chain { namespace wasm_injections {
wasm_binary_injection() { wasm_binary_injection() {
_module_injectors.init(); _module_injectors.init();
// initialize static fields of injectors // initialize static fields of injectors
instruction_counter::icnt = 0; //injector_utils::init();
checktime_injector::checktime_idx = -1; instruction_counter::init();
checktime_injector::init();
} }
static void inject( IR::Module& mod ) { static void inject( IR::Module& mod ) {
...@@ -338,17 +298,9 @@ namespace eosio { namespace chain { namespace wasm_injections { ...@@ -338,17 +298,9 @@ namespace eosio { namespace chain { namespace wasm_injections {
std::vector<U8> new_code; std::vector<U8> new_code;
while ( decoder ) { while ( decoder ) {
auto op = decoder.decodeOp(); auto op = decoder.decodeOp();
std::vector<U8>::iterator decoded_index = (fd.code.begin() + decoder.index());
op->visit( { &mod, &new_code, &fd, 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; fd.code = new_code;
} }
} }
......
#pragma once #pragma once
#include <fc/exception/exception.hpp> #include <fc/exception/exception.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wasm_eosio_binary_ops.hpp> #include <eosio/chain/wasm_eosio_binary_ops.hpp>
#include <functional> #include <functional>
#include <vector> #include <vector>
...@@ -48,6 +49,8 @@ namespace eosio { namespace chain { namespace wasm_constraints { ...@@ -48,6 +49,8 @@ namespace eosio { namespace chain { namespace wasm_constraints {
// instruction validators // instruction validators
// simple mutator that doesn't actually mutate anything // simple mutator that doesn't actually mutate anything
// used to verify that a given instruction is valid for execution on our platform // 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 { struct whitelist_validator {
static constexpr bool kills = true; static constexpr bool kills = true;
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) {
...@@ -55,6 +58,17 @@ namespace eosio { namespace chain { namespace wasm_constraints { ...@@ -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 { struct wasm_opcode_no_disposition_exception {
std::string opcode_name; std::string opcode_name;
}; };
...@@ -62,7 +76,8 @@ namespace eosio { namespace chain { namespace wasm_constraints { ...@@ -62,7 +76,8 @@ namespace eosio { namespace chain { namespace wasm_constraints {
struct blacklist_validator { struct blacklist_validator {
static constexpr bool kills = true; static constexpr bool kills = true;
static void accept( wasm_ops::instr* inst, wasm_ops::visitor_arg& arg ) { 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 { ...@@ -92,29 +107,29 @@ namespace eosio { namespace chain { namespace wasm_constraints {
using set_global_t = wasm_ops::set_global <whitelist_validator>; using set_global_t = wasm_ops::set_global <whitelist_validator>;
using nop_t = wasm_ops::nop <whitelist_validator>; using nop_t = wasm_ops::nop <whitelist_validator>;
using i32_load_t = wasm_ops::i32_load <whitelist_validator>; using i32_load_t = wasm_ops::i32_load <large_offset_validator, whitelist_validator>;
using i64_load_t = wasm_ops::i64_load <whitelist_validator>; using i64_load_t = wasm_ops::i64_load <large_offset_validator, whitelist_validator>;
using f32_load_t = wasm_ops::f32_load <whitelist_validator>; using f32_load_t = wasm_ops::f32_load <large_offset_validator, whitelist_validator>;
using f64_load_t = wasm_ops::f64_load <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 <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 <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 <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 <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 <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 <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 <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 <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 <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 <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 <whitelist_validator>; using i32_store_t = wasm_ops::i32_store <large_offset_validator, whitelist_validator>;
using i64_store_t = wasm_ops::i64_store <whitelist_validator>; using i64_store_t = wasm_ops::i64_store <large_offset_validator, whitelist_validator>;
using f32_store_t = wasm_ops::f32_store <whitelist_validator>; using f32_store_t = wasm_ops::f32_store <large_offset_validator, whitelist_validator>;
using f64_store_t = wasm_ops::f64_store <whitelist_validator>; using f64_store_t = wasm_ops::f64_store <large_offset_validator, whitelist_validator>;
using i32_store8_t = wasm_ops::i32_store8 <whitelist_validator>; using i32_store8_t = wasm_ops::i32_store8 <large_offset_validator, whitelist_validator>;
using i32_store16_t = wasm_ops::i32_store16 <whitelist_validator>; using i32_store16_t = wasm_ops::i32_store16 <large_offset_validator, whitelist_validator>;
using i64_store8_t = wasm_ops::i64_store8 <whitelist_validator>; using i64_store8_t = wasm_ops::i64_store8 <large_offset_validator, whitelist_validator>;
using i64_store16_t = wasm_ops::i64_store16 <whitelist_validator>; using i64_store16_t = wasm_ops::i64_store16 <large_offset_validator, whitelist_validator>;
using i64_store32_t = wasm_ops::i64_store32 <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 i32_const_t = wasm_ops::i32_const <whitelist_validator>;
using i64_const_t = wasm_ops::i64_const <whitelist_validator>; using i64_const_t = wasm_ops::i64_const <whitelist_validator>;
......
...@@ -9,57 +9,63 @@ ...@@ -9,57 +9,63 @@
namespace eosio { namespace chain { namespace wasm_ops { namespace eosio { namespace chain { namespace wasm_ops {
using namespace IR; using namespace IR;
std::string to_string( NoImm imm ) { inline std::string to_string( NoImm imm ) {
return "no imm"; return "no imm";
} }
std::string to_string( MemoryImm imm ) { inline std::string to_string( MemoryImm imm ) {
return "memory 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)); 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)); 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); 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); 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); 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); 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); return std::string("memarg : ")+std::to_string(field.a)+std::string(", ")+std::to_string(field.o);
} }
std::string to_string( callindirecttype field ) { inline std::string to_string( branchtabletype field ) {
return std::string("callindirecttype : ")+ return std::string("branchtabletype : ")+std::to_string(field.target_depth)+std::string(", ")+std::to_string(field.table_index);
std::to_string(field.funcidx)+std::string(", ")+std::to_string((uint32_t)field.end);
} }
std::vector<U8> pack( uint32_t field ) { inline std::vector<U8> pack( uint32_t field ) {
return { U8(field >> 24), U8(field >> 16), U8(field >> 8), U8(field) }; return { U8(field), U8(field >> 8), U8(field >> 16), U8(field >> 24) };
} }
std::vector<U8> pack( uint64_t field ) { inline std::vector<U8> pack( uint64_t field ) {
return { U8(field >> 56), U8(field >> 48), U8(field >> 40), U8(field >> 32), return { U8(field), U8(field >> 8), U8(field >> 16), U8(field >> 24),
U8(field >> 24), U8(field >> 16), U8(field >> 8), U8(field) }; 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) }; return { U8(field.result) };
} }
std::vector<U8> pack( memoryoptype field ) { inline std::vector<U8> pack( memoryoptype field ) {
return { U8(field.end) }; return { U8(field.end) };
} }
std::vector<U8> pack( memarg field ) { inline std::vector<U8> pack( memarg field ) {
return { U8(field.a >> 24), U8(field.a >> 16), U8(field.a >> 8), U8(field.a), return { U8(field.a), U8(field.a >> 8), U8(field.a >> 16), U8(field.a >> 24),
U8(field.o >> 24), U8(field.o >> 16), U8(field.o >> 8), U8(field.o) }; U8(field.o), U8(field.o >> 8), U8(field.o >> 16), U8(field.o >> 24),
};
} }
std::vector<U8> pack( callindirecttype field ) { inline std::vector<U8> pack( branchtabletype field ) {
return { U8(field.funcidx >> 24), U8(field.funcidx >> 16), U8(field.funcidx >> 8), U8(field.funcidx), return { U8(field.target_depth), U8(field.target_depth >> 8), U8(field.target_depth >> 16), U8(field.target_depth >> 24),
U8(field.end) }; 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 }}} // namespace eosio, chain, wasm_ops
...@@ -9,14 +9,9 @@ ...@@ -9,14 +9,9 @@
namespace eosio { namespace chain { namespace wasm_injections { namespace eosio { namespace chain { namespace wasm_injections {
using namespace IR; using namespace IR;
/*
std::string to_string( ControlStructureImm imm ) { //std::unordered_map<type_slot_pair, uint32_t, tsp_hasher> injector_utils::type_slots;
return "result type : "+std::to_string(uint32_t(imm.resultType)); std::map<std::vector<uint16_t>, uint32_t> injector_utils::type_slots;
}
std::string to_string( BranchImm imm ) {
return "branch target : "+std::to_string(uint32_t(imm.targetDepth));
}
*/
void noop_injection_visitor::inject( Module& m ) { /* just pass */ } void noop_injection_visitor::inject( Module& m ) { /* just pass */ }
void noop_injection_visitor::initializer() { /* just pass */ } void noop_injection_visitor::initializer() { /* just pass */ }
......
...@@ -185,128 +185,110 @@ namespace eosio { namespace chain { ...@@ -185,128 +185,110 @@ namespace eosio { namespace chain {
fc::optional<binaryen::info> binaryen_info; fc::optional<binaryen::info> binaryen_info;
try { 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); Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
WASM::serializeWithInjection(stream, *module); Serialization::MemoryInputStream stream2((const U8 *) wasm_binary, wasm_binary_size);
validate_eosio_wasm_constraints(*module); WASM::serialize(stream, *module);
wasm_module_walker< WASM::serializeWithInjection(stream2, *module2);
wasm_constraints::constraints_validators<wasm_constraints::memories_validator,
wasm_constraints::data_segments_validator, wasm_constraints::wasm_binary_validation::validate( *module );
wasm_constraints::tables_validator, wasm_injections::wasm_binary_injection::inject( *module );
wasm_constraints::globals_validator>, /*
wasm_constraints::constraints_validators<wasm_constraints::memories_validator, std::cout << "INJECTED\n";
wasm_constraints::data_segments_validator, wasm_injections::wasm_binary_injection::inject( *module );
wasm_constraints::tables_validator, std::cout << "INJECTEDSS\n";
wasm_constraints::globals_validator>> wasm_injections::wasm_binary_injection::inject( *module2 );
wmw(*module);
auto restype = [](IR::ResultType f){
wasm_ops::wasm_instr_ptr nopi = std::make_shared< wasm_ops::nop<test_mutator> >(); if (f == IR::ResultType::none ) return "none";
wasm_ops::wasm_instr_ptr blocki = std::make_shared< wasm_ops::block<test_mutator2> >(); if (f == IR::ResultType::i32 ) return "i32";
wasm_ops::op_types<test_mutator>::block_t b; if (f == IR::ResultType::i64 ) return "i64";
wasm_ops::op_types<test_mutator>::i64_popcount_t ipc; if (f == IR::ResultType::f32 ) return "f32";
wasm_ops::nop<test_mutator> n; if (f == IR::ResultType::f64 ) return "f64";
wasm_ops::call<test_mutator> br; };
br.field = 23; auto valtype = [](IR::ValueType f){
wasm_rewriter::op_constrainers::f32_add_t f32; if (f == IR::ValueType::any ) return "any";
b.visit(); if (f == IR::ValueType::i32 ) return "i32";
ipc.visit(); if (f == IR::ValueType::i64 ) return "i64";
wmw.pre_validate(); if (f == IR::ValueType::f32 ) return "f32";
for (auto def : module->functions.defs) { if (f == IR::ValueType::f64 ) return "f64";
char* code = (char*)(def.code.data()); };
char* code_end = code+def.code.size();
std::cout << "FUNC " << "\n";
uint32_t it = 0; std::cout << "FUNCTION_Type A \n";
/* for (auto e : module->types) {
while ( it < def.code.size() ) { std::cout << "Function ("<< restype(e->ret) << ") (";
std::cout << "OPCODE " << std::hex << (uint32_t)code[it] << "\n"; for (auto ee : e->parameters) {
it++; std::cout << valtype(ee) << ", ";
}
*/
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";
*/
}
} }
/* }
while ( it < def.code.size() ) { std::cout << "\n";
std::cout << "OPCODE " << std::hex << (uint32_t)code[it] << "\n"; std::cout << "FUNCTION_Type B \n";
wasm_ops::instr* op = wasm_ops::get_instr_from_op<wasm_ops::op_types<>>(code[it]); for (auto e : module->types) {
it = op->unpack( def.code, it ); std::cout << "Function ("<< restype(e->ret) << ") (";
if ( op->get_code() == 0x41 ) for (auto ee : e->parameters) {
std::cout << "OP " << op->to_string() << " " << (uint32_t)((wasm_ops::i32_const<test_mutator>*)op)->field << "\n"; std::cout << valtype(ee) << ", ";
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 << (int)n << " ";
} }
/*
std::cout << "\n"; std::cout << "\n";
uint8_t* buff = new uint8_t[3];
buff[0] = wasm_ops::block_code; std::cout << "FUNCTION_Import A \n";
buff[1] = 120; for (auto e : module->functions.imports)
//buff[2] = wasm_ops::nop_code; std::cout << e.exportName << "\n";
buff[2] = 34; std::cout << "\n";
std::vector<uint8_t> code = {wasm_ops::block_code, 13, wasm_ops::nop_code}; std::cout << "FUNCTION_Import B \n";
// 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); for (auto e : module2->functions.imports)
// 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)); std::cout << e.exportName << "\n";
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); std::cout << "\n";
std::cout << "TABLES_Import A \n";
datastream<uint8_t*> ds( code.data(), code.size() ); for (auto e : module->tables.imports)
std::cout << e.exportName << "\n";
//fc::raw::unpack(ds, *nop_);
block_->visit(); std::cout << "\n";
std::cout << "TABLES_Import B \n";
std::cout << "FIELD : " << (uint64_t)((wasm_ops::block<test_mutator>*)block_)->field.result << "\n"; for (auto e : module2->tables.imports)
std::cout << "CODE : " << (int)block_->get_code() << "NAME : " << block_->to_string() << "\n"; std::cout << e.exportName << "\n";
std::cout << "CODE : " << (int)nop_->get_code() << "NAME : " << nop_->to_string() << "\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); WASM::serialize(outstream, *module);
std::vector<U8> bytes = outstream.getBytes(); std::vector<U8> bytes = outstream.getBytes();
wavm = wavm::entry::build((char*)bytes.data(), bytes.size()); wavm = wavm::entry::build((char*)bytes.data(), bytes.size());
wavm_info.emplace(*wavm); wavm_info.emplace(*wavm);
...@@ -613,6 +595,7 @@ public: ...@@ -613,6 +595,7 @@ public:
using context_aware_api::context_aware_api; using context_aware_api::context_aware_api;
void checktime(uint32_t instruction_count) { void checktime(uint32_t instruction_count) {
std::cout << "CHECKTIME\n";
context.checktime(instruction_count); context.checktime(instruction_count);
} }
}; };
......
...@@ -159,7 +159,7 @@ entry entry::build(const char* wasm_binary, size_t wasm_binary_size) { ...@@ -159,7 +159,7 @@ entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
WasmBinaryBuilder builder(*module, code, false); WasmBinaryBuilder builder(*module, code, false);
builder.read(); builder.read();
inject_checktime(*module.get()); //inject_checktime(*module.get());
FC_ASSERT(module->memory.initial * Memory::kPageSize <= wasm_constraints::maximum_linear_memory); 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 ...@@ -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 ) { ...@@ -120,9 +120,7 @@ void entry::prepare( const info& base_info ) {
entry entry::build(const char* wasm_binary, size_t wasm_binary_size) { entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
Module* module = new Module(); Module* module = new Module();
Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size); Serialization::MemoryInputStream stream((const U8 *) wasm_binary, wasm_binary_size);
WASM::serializeWithInjection(stream, *module); WASM::serialize(stream, *module);
// TODO clean this up
//validate_eosio_wasm_constraints(*module);
root_resolver resolver; root_resolver resolver;
LinkResult link_result = linkModule(*module, resolver); LinkResult link_result = linkModule(*module, resolver);
......
...@@ -25,6 +25,7 @@ namespace IR ...@@ -25,6 +25,7 @@ namespace IR
struct BranchTableImm struct BranchTableImm
{ {
static_assert(sizeof(Uptr) == 8, "SIZEE");
Uptr defaultTargetDepth; Uptr defaultTargetDepth;
Uptr branchTableIndex; // An index into the FunctionDef's branchTables array. Uptr branchTableIndex; // An index into the FunctionDef's branchTables array.
}; };
......
...@@ -26,6 +26,21 @@ namespace IR ...@@ -26,6 +26,21 @@ namespace IR
max = num-1 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<ValueType type> struct ValueTypeInfo;
template<> struct ValueTypeInfo<ValueType::i32> { typedef I32 Value; }; template<> struct ValueTypeInfo<ValueType::i32> { typedef I32 Value; };
template<> struct ValueTypeInfo<ValueType::i64> { typedef I64 Value; }; template<> struct ValueTypeInfo<ValueType::i64> { typedef I64 Value; };
...@@ -128,7 +143,22 @@ namespace IR ...@@ -128,7 +143,22 @@ namespace IR
num, num,
max = num-1, 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 Uptr getArity(ResultType returnType) { return returnType == ResultType::none ? 0 : 1; }
inline const char* asString(ResultType type) inline const char* asString(ResultType type)
...@@ -337,4 +367,4 @@ namespace IR ...@@ -337,4 +367,4 @@ namespace IR
default: Errors::unreachable(); 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.
先完成此消息的编辑!
想要评论请 注册