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

Commit

Permalink
fix dangling reference issues #6897
Browse files Browse the repository at this point in the history
  • Loading branch information
arhag committed Apr 1, 2019
1 parent ed8b7b4 commit 943522e
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 94 deletions.
91 changes: 65 additions & 26 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,61 @@ static inline void print_debug(account_name receiver, const action_trace& ar) {
}
}

void apply_context::exec_one( action_trace& trace )
apply_context::apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth)
:control(con)
,db(con.mutable_db())
,trx_context(trx_ctx)
,recurse_depth(depth)
,first_receiver_action_ordinal(action_ordinal)
,action_ordinal(action_ordinal)
,idx64(*this)
,idx128(*this)
,idx256(*this)
,idx_double(*this)
,idx_long_double(*this)
{
action_trace& trace = trx_ctx.get_action_trace(action_ordinal);
act = &trace.act;
receiver = trace.receiver;
context_free = trace.context_free;
}

void apply_context::exec_one()
{
auto start = fc::time_point::now();

action_receipt r;
r.receiver = receiver;
r.act_digest = digest_type::hash(act);
r.act_digest = digest_type::hash(*act);

const auto& cfg = control.get_global_properties().configuration;
try {
try {
const auto& a = control.get_account( receiver );
privileged = a.privileged;
auto native = control.find_apply_handler( receiver, act.account, act.name );
auto native = control.find_apply_handler( receiver, act->account, act->name );
if( native ) {
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act.account, act.name );
control.check_action_list( act->account, act->name );
}
(*native)( *this );
}

if( a.code.size() > 0
&& !(act.account == config::system_account_name && act.name == N( setcode ) &&
&& !(act->account == config::system_account_name && act->name == N( setcode ) &&
receiver == config::system_account_name) ) {
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
control.check_contract_list( receiver );
control.check_action_list( act.account, act.name );
control.check_action_list( act->account, act->name );
}
try {
control.get_wasm_interface().apply( a.code_version, a.code, *this );
} catch( const wasm_exit& ) {}
}
} FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) )
} catch( fc::exception& e ) {
action_trace& trace = trx_context.get_action_trace( action_ordinal );
trace.except = e;
finalize_trace( trace, start );
throw;
Expand All @@ -72,14 +92,15 @@ void apply_context::exec_one( action_trace& trace )
r.global_sequence = next_global_sequence();
r.recv_sequence = next_recv_sequence( receiver );

const auto& account_sequence = db.get<account_sequence_object, by_name>(act.account);
const auto& account_sequence = db.get<account_sequence_object, by_name>(act->account);
r.code_sequence = account_sequence.code_sequence; // could be modified by action execution above
r.abi_sequence = account_sequence.abi_sequence; // could be modified by action execution above

for( const auto& auth : act.authorization ) {
for( const auto& auth : act->authorization ) {
r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor );
}

action_trace& trace = trx_context.get_action_trace( action_ordinal );
trace.receipt = r;

trx_context.executed.emplace_back( std::move(r) );
Expand All @@ -102,13 +123,13 @@ void apply_context::finalize_trace( action_trace& trace, const fc::time_point& s
trace.elapsed = fc::time_point::now() - start;
}

void apply_context::exec( action_trace& trace )
void apply_context::exec()
{
_notified.emplace_back( receiver, action_ordinal );
exec_one( trace );
exec_one();
for( uint32_t i = 1; i < _notified.size(); ++i ) {
std::tie( receiver, action_ordinal ) = _notified[i];
exec_one( trx_context.get_action_trace( action_ordinal ) );
exec_one();
}

if( _cfa_inline_actions.size() > 0 || _inline_actions.size() > 0 ) {
Expand All @@ -131,28 +152,26 @@ bool apply_context::is_account( const account_name& account )const {
}

void apply_context::require_authorization( const account_name& account ) {
for( uint32_t i=0; i < act.authorization.size(); i++ ) {
if( act.authorization[i].actor == account ) {
used_authorizations[i] = true;
for( uint32_t i=0; i < act->authorization.size(); i++ ) {
if( act->authorization[i].actor == account ) {
return;
}
}
EOS_ASSERT( false, missing_auth_exception, "missing authority of ${account}", ("account",account));
}

bool apply_context::has_authorization( const account_name& account )const {
for( const auto& auth : act.authorization )
for( const auto& auth : act->authorization )
if( auth.actor == account )
return true;
return false;
}

void apply_context::require_authorization(const account_name& account,
const permission_name& permission) {
for( uint32_t i=0; i < act.authorization.size(); i++ )
if( act.authorization[i].actor == account ) {
if( act.authorization[i].permission == permission ) {
used_authorizations[i] = true;
for( uint32_t i=0; i < act->authorization.size(); i++ )
if( act->authorization[i].actor == account ) {
if( act->authorization[i].permission == permission ) {
return;
}
}
Expand All @@ -171,7 +190,7 @@ void apply_context::require_recipient( account_name recipient ) {
if( !has_recipient(recipient) ) {
_notified.emplace_back(
recipient,
trx_context.schedule_action( act, recipient, false, action_ordinal, first_receiver_action_ordinal )
schedule_action( action_ordinal, recipient, false, action_ordinal, first_receiver_action_ordinal )
);
}
}
Expand Down Expand Up @@ -202,7 +221,7 @@ void apply_context::execute_inline( action&& a ) {

bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated
bool send_to_self = (a.account == receiver);
bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block());
bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_producing_block());

flat_set<permission_level> inherited_authorizations;
if( inherit_parent_authorizations ) {
Expand All @@ -219,7 +238,7 @@ void apply_context::execute_inline( action&& a ) {
if( enforce_actor_whitelist_blacklist )
actors.insert( auth.actor );

if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) {
if( inherit_parent_authorizations && std::find(act->authorization.begin(), act->authorization.end(), auth) != act->authorization.end() ) {
inherited_authorizations.insert( auth );
}
}
Expand Down Expand Up @@ -265,7 +284,7 @@ void apply_context::execute_inline( action&& a ) {

auto inline_receiver = a.account;
_inline_actions.emplace_back(
trx_context.schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal )
schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal )
);
}

Expand All @@ -280,7 +299,7 @@ void apply_context::execute_context_free_inline( action&& a ) {

auto inline_receiver = a.account;
_cfa_inline_actions.emplace_back(
trx_context.schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal )
schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal )
);
}

Expand Down Expand Up @@ -403,7 +422,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a
} );
}

EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account) || (receiver == payer) || privileged,
EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account) || (receiver == payer) || privileged,
subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." );
add_ram_usage( payer, (config::billable_size_v<generated_transaction_object> + trx_size) );
}
Expand All @@ -418,6 +437,26 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc
return gto;
}

int32_t apply_context::schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free,
int32_t creator_action_ordinal, int32_t parent_action_ordinal )
{
int32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, receiver, context_free,
creator_action_ordinal, parent_action_ordinal );

act = &trx_context.get_action_trace( action_ordinal ).act;
return scheduled_action_ordinal;
}

int32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free,
int32_t creator_action_ordinal, int32_t parent_action_ordinal )
{
int32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), receiver, context_free,
creator_action_ordinal, parent_action_ordinal );

act = &trx_context.get_action_trace( action_ordinal ).act;
return scheduled_action_ordinal;
}

const table_id_object* apply_context::find_table( name code, name scope, name table ) {
return db.find<table_id_object, by_code_scope_table>(boost::make_tuple(code, scope, table));
}
Expand Down Expand Up @@ -461,7 +500,7 @@ bytes apply_context::get_packed_transaction() {
void apply_context::update_db_usage( const account_name& payer, int64_t delta ) {
if( delta > 0 ) {
if( !(privileged || payer == account_name(receiver)) ) {
EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account),
EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account),
subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." );
require_authorization( payer );
}
Expand Down
18 changes: 9 additions & 9 deletions libraries/chain/eosio_contract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void validate_authority_precondition( const apply_context& context, const author
* This method is called assuming precondition_system_newaccount succeeds a
*/
void apply_eosio_newaccount(apply_context& context) {
auto create = context.act.data_as<newaccount>();
auto create = context.get_action().data_as<newaccount>();
try {
context.require_authorization(create.creator);
// context.require_write_lock( config::eosio_auth_scope );
Expand Down Expand Up @@ -129,7 +129,7 @@ void apply_eosio_setcode(apply_context& context) {
const auto& cfg = context.control.get_global_properties().configuration;

auto& db = context.db;
auto act = context.act.data_as<setcode>();
auto act = context.get_action().data_as<setcode>();
context.require_authorization(act.account);

EOS_ASSERT( act.vmtype == 0, invalid_contract_vm_type, "code should be 0" );
Expand Down Expand Up @@ -174,7 +174,7 @@ void apply_eosio_setcode(apply_context& context) {

void apply_eosio_setabi(apply_context& context) {
auto& db = context.db;
auto act = context.act.data_as<setabi>();
auto act = context.get_action().data_as<setabi>();

context.require_authorization(act.account);

Expand Down Expand Up @@ -205,7 +205,7 @@ void apply_eosio_setabi(apply_context& context) {

void apply_eosio_updateauth(apply_context& context) {

auto update = context.act.data_as<updateauth>();
auto update = context.get_action().data_as<updateauth>();
context.require_authorization(update.account); // only here to mark the single authority on this action as used

auto& authorization = context.control.get_mutable_authorization_manager();
Expand Down Expand Up @@ -270,7 +270,7 @@ void apply_eosio_updateauth(apply_context& context) {
void apply_eosio_deleteauth(apply_context& context) {
// context.require_write_lock( config::eosio_auth_scope );

auto remove = context.act.data_as<deleteauth>();
auto remove = context.get_action().data_as<deleteauth>();
context.require_authorization(remove.account); // only here to mark the single authority on this action as used

EOS_ASSERT(remove.permission != config::active_name, action_validate_exception, "Cannot delete active authority");
Expand Down Expand Up @@ -301,7 +301,7 @@ void apply_eosio_deleteauth(apply_context& context) {
void apply_eosio_linkauth(apply_context& context) {
// context.require_write_lock( config::eosio_auth_scope );

auto requirement = context.act.data_as<linkauth>();
auto requirement = context.get_action().data_as<linkauth>();
try {
EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty");

Expand All @@ -318,7 +318,7 @@ void apply_eosio_linkauth(apply_context& context) {
const permission_object* permission = nullptr;
if( context.control.is_builtin_activated( builtin_protocol_feature_t::only_link_to_existing_permission ) ) {
permission = db.find<permission_object, by_owner>(
boost::make_tuple( requirement.account, requirement.requirement )
boost::make_tuple( requirement.account, requirement.requirement )
);
} else {
permission = db.find<permission_object, by_name>(requirement.requirement);
Expand Down Expand Up @@ -358,7 +358,7 @@ void apply_eosio_unlinkauth(apply_context& context) {
// context.require_write_lock( config::eosio_auth_scope );

auto& db = context.db;
auto unlink = context.act.data_as<unlinkauth>();
auto unlink = context.get_action().data_as<unlinkauth>();

context.require_authorization(unlink.account); // only here to mark the single authority on this action as used

Expand All @@ -374,7 +374,7 @@ void apply_eosio_unlinkauth(apply_context& context) {
}

void apply_eosio_canceldelay(apply_context& context) {
auto cancel = context.act.data_as<canceldelay>();
auto cancel = context.get_action().data_as<canceldelay>();
context.require_authorization(cancel.canceling_auth.actor); // only here to mark the single authority on this action as used

const auto& trx_id = cancel.trx_id;
Expand Down
40 changes: 19 additions & 21 deletions libraries/chain/include/eosio/chain/apply_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,34 +452,25 @@ class apply_context {

/// Constructor
public:
apply_context(controller& con, transaction_context& trx_ctx, const action& a, uint32_t depth=0)
:control(con)
,db(con.mutable_db())
,trx_context(trx_ctx)
,act(a)
,receiver(act.account)
,used_authorizations(act.authorization.size(), false)
,recurse_depth(depth)
,idx64(*this)
,idx128(*this)
,idx256(*this)
,idx_double(*this)
,idx_long_double(*this)
{
}

apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth=0);

/// Execution methods:
public:

void exec_one( action_trace& trace );
void exec( action_trace& trace );
void exec_one();
void exec();
void execute_inline( action&& a );
void execute_context_free_inline( action&& a );
void schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing );
bool cancel_deferred_transaction( const uint128_t& sender_id, account_name sender );
bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); }

protected:
int32_t schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free = false,
int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 );
int32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free = false,
int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 );


/// Authorization methods:
public:
Expand Down Expand Up @@ -560,22 +551,29 @@ class apply_context {
void add_ram_usage( account_name account, int64_t ram_delta );
void finalize_trace( action_trace& trace, const fc::time_point& start );

bool is_context_free()const { return context_free; }
bool is_privileged()const { return privileged; }
action_name get_receiver()const { return receiver; }
const action& get_action()const { return *act; }

/// Fields:
public:

controller& control;
chainbase::database& db; ///< database where state is stored
transaction_context& trx_context; ///< transaction context in which the action is running
const action& act; ///< message being applied

private:
const action* act = nullptr; ///< action being applied
// act pointer may be invalidated on call to trx_context.schedule_action
account_name receiver; ///< the code that is currently running
vector<bool> used_authorizations; ///< Parallel to act.authorization; tracks which permissions have been used while processing the message
uint32_t recurse_depth; ///< how deep inline actions can recurse
int32_t first_receiver_action_ordinal = -1;
int32_t action_ordinal = -1;
bool privileged = false;
bool context_free = false;
bool used_context_free_api = false;

public:
generic_index<index64_object> idx64;
generic_index<index128_object> idx128;
generic_index<index256_object, uint128_t*, const uint128_t*> idx256;
Expand Down
Loading

0 comments on commit 943522e

Please sign in to comment.