1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

emergency update

This commit is contained in:
ton 2020-03-24 03:32:16 +04:00
parent 5d846e0aaf
commit 9f351fc29f
87 changed files with 2486 additions and 655 deletions

View file

@ -789,7 +789,7 @@ void register_shift_logic_ops(OpcodeTable& cp0) {
int exec_minmax(VmState* st, int mode) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute MINMAXOP " << mode;
VM_LOG(st) << "execute " << (mode & 1 ? "Q" : "") << (mode & 2 ? "MIN" : "") << (mode & 4 ? "MAX" : "");
stack.check_underflow(2);
auto x = stack.pop_int();
auto y = stack.pop_int();
@ -811,7 +811,7 @@ int exec_minmax(VmState* st, int mode) {
int exec_abs(VmState* st, bool quiet) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute ABS";
VM_LOG(st) << "execute " << (quiet ? "QABS" : "ABS");
stack.check_underflow(1);
auto x = stack.pop_int();
if (x->is_valid() && x->sgn() < 0) {

View file

@ -58,14 +58,27 @@ std::string dump_push_ref(CellSlice& cs, unsigned args, int pfx_bits, std::strin
return "";
}
cs.advance(pfx_bits);
cs.advance_refs(1);
return name;
auto cell = cs.fetch_ref();
return name + " (" + cell->get_hash().to_hex() + ")";
}
int compute_len_push_ref(const CellSlice& cs, unsigned args, int pfx_bits) {
return cs.have_refs(1) ? (0x10000 + pfx_bits) : 0;
}
std::string dump_push_ref2(CellSlice& cs, unsigned args, int pfx_bits, std::string name) {
if (!cs.have_refs(2)) {
return "";
}
cs.advance(pfx_bits);
auto cell1 = cs.fetch_ref(), cell2 = cs.fetch_ref();
return name + " (" + cell1->get_hash().to_hex() + ") (" + cell2->get_hash().to_hex() + ")";
}
int compute_len_push_ref2(const CellSlice& cs, unsigned args, int pfx_bits) {
return cs.have_refs(2) ? (0x20000 + pfx_bits) : 0;
}
int exec_push_slice_common(VmState* st, CellSlice& cs, unsigned data_bits, unsigned refs, int pfx_bits) {
if (!cs.have(pfx_bits + data_bits)) {
throw VmError{Excno::inv_opcode, "not enough data bits for a PUSHSLICE instruction"};

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "vm/cellslice.h"
@ -28,4 +28,7 @@ void register_cell_ops(OpcodeTable &cp0);
std::string dump_push_ref(CellSlice &cs, unsigned args, int pfx_bits, std::string name);
int compute_len_push_ref(const CellSlice &cs, unsigned args, int pfx_bits);
std::string dump_push_ref2(CellSlice &cs, unsigned args, int pfx_bits, std::string name);
int compute_len_push_ref2(const CellSlice &cs, unsigned args, int pfx_bits);
} // namespace vm

View file

@ -26,10 +26,12 @@
#include "vm/excno.hpp"
#include "vm/vm.h"
using namespace std::literals::string_literals;
namespace vm {
int exec_execute(VmState* st) {
VM_LOG(st) << "execute EXECUTE\n";
VM_LOG(st) << "execute EXECUTE";
auto cont = st->get_stack().pop_cont();
return st->call(std::move(cont));
}
@ -150,12 +152,58 @@ int exec_callcc_varargs(VmState* st) {
int exec_do_with_ref(VmState* st, CellSlice& cs, int pfx_bits, const std::function<int(VmState*, Ref<OrdCont>)>& func,
const char* name) {
if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a CALLREF instruction"};
throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
}
cs.advance(pfx_bits);
auto cell = cs.fetch_ref();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
return func(st, Ref<OrdCont>{true, load_cell_slice_ref(std::move(cell)), st->get_cp()});
return func(st, st->ref_to_cont(std::move(cell)));
}
int exec_do_with_cell(VmState* st, CellSlice& cs, int pfx_bits, const std::function<int(VmState*, Ref<Cell>)>& func,
const char* name) {
if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
}
cs.advance(pfx_bits);
auto cell = cs.fetch_ref();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
return func(st, std::move(cell));
}
int exec_ifelse_ref(VmState* st, CellSlice& cs, int pfx_bits, bool mode) {
const char* name = mode ? "IFREFELSE" : "IFELSEREF";
if (!cs.have_refs(1)) {
throw VmError{Excno::inv_opcode, "no references left for a "s + name + " instruction"};
}
cs.advance(pfx_bits);
auto cell = cs.fetch_ref();
Stack& stack = st->get_stack();
VM_LOG(st) << "execute " << name << " (" << cell->get_hash().to_hex() << ")";
stack.check_underflow(2);
auto cont = stack.pop_cont();
if (stack.pop_bool() == mode) {
cont = st->ref_to_cont(std::move(cell));
} else {
cell.clear();
}
return st->call(std::move(cont));
}
int exec_ifref_elseref(VmState* st, CellSlice& cs, unsigned args, int pfx_bits) {
if (!cs.have_refs(2)) {
throw VmError{Excno::inv_opcode, "no references left for a IFREFELSEREF instruction"};
}
cs.advance(pfx_bits);
auto cell1 = cs.fetch_ref(), cell2 = cs.fetch_ref();
Stack& stack = st->get_stack();
VM_LOG(st) << "execute IFREFELSEREF (" << cell1->get_hash().to_hex() << ") (" << cell2->get_hash().to_hex() << ")";
if (!stack.pop_bool()) {
cell1 = std::move(cell2);
} else {
cell2.clear();
}
return st->call(st->ref_to_cont(std::move(cell1)));
}
int exec_ret_data(VmState* st) {
@ -349,7 +397,7 @@ int exec_if_bit_jmpref(VmState* st, CellSlice& cs, unsigned args, int pfx_bits)
bool val = x->get_bit(bit);
stack.push_int(std::move(x));
if (val ^ negate) {
return st->jump(Ref<OrdCont>{true, load_cell_slice_ref(std::move(cell)), st->get_cp()});
return st->jump(st->ref_to_cont(std::move(cell)));
}
return 0;
}
@ -365,66 +413,72 @@ std::string dump_if_bit_jmpref(CellSlice& cs, unsigned args, int pfx_bits) {
return os.str();
}
int exec_repeat(VmState* st) {
int exec_repeat(VmState* st, bool brk) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute REPEAT\n";
VM_LOG(st) << "execute REPEAT" << (brk ? "BRK" : "");
stack.check_underflow(2);
auto cont = stack.pop_cont();
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
if (c <= 0) {
return 0;
}
return st->repeat(std::move(cont), st->extract_cc(1), c);
return st->repeat(std::move(cont), st->c1_envelope_if(brk, st->extract_cc(1)), c);
}
int exec_repeat_end(VmState* st) {
int exec_repeat_end(VmState* st, bool brk) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute REPEATEND\n";
VM_LOG(st) << "execute REPEATEND" << (brk ? "BRK" : "");
stack.check_underflow(1);
int c = stack.pop_smallint_range(0x7fffffff, 0x80000000);
if (c <= 0) {
return st->ret();
}
auto cont = st->extract_cc(0);
return st->repeat(std::move(cont), st->get_c0(), c);
return st->repeat(std::move(cont), st->c1_envelope_if(brk, st->get_c0()), c);
}
int exec_until(VmState* st) {
int exec_until(VmState* st, bool brk) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute UNTIL\n";
VM_LOG(st) << "execute UNTIL" << (brk ? "BRK" : "");
auto cont = stack.pop_cont();
return st->until(std::move(cont), st->extract_cc(1));
return st->until(std::move(cont), st->c1_envelope_if(brk, st->extract_cc(1)));
}
int exec_until_end(VmState* st) {
VM_LOG(st) << "execute UNTILEND\n";
int exec_until_end(VmState* st, bool brk) {
VM_LOG(st) << "execute UNTILEND" << (brk ? "BRK" : "");
auto cont = st->extract_cc(0);
return st->until(std::move(cont), st->get_c0());
return st->until(std::move(cont), st->c1_envelope_if(brk, st->get_c0()));
}
int exec_while(VmState* st) {
int exec_while(VmState* st, bool brk) {
Stack& stack = st->get_stack();
VM_LOG(st) << "execute WHILE\n";
VM_LOG(st) << "execute WHILE" << (brk ? "BRK" : "");
stack.check_underflow(2);
auto body = stack.pop_cont();
auto cond = stack.pop_cont();
return st->loop_while(std::move(cond), std::move(body), st->extract_cc(1));
return st->loop_while(std::move(cond), std::move(body), st->c1_envelope_if(brk, st->extract_cc(1)));
}
int exec_while_end(VmState* st) {
VM_LOG(st) << "execute WHILEEND\n";
int exec_while_end(VmState* st, bool brk) {
VM_LOG(st) << "execute WHILEEND" << (brk ? "BRK" : "");
auto cond = st->get_stack().pop_cont();
auto body = st->extract_cc(0);
return st->loop_while(std::move(cond), std::move(body), st->get_c0());
return st->loop_while(std::move(cond), std::move(body), st->c1_envelope_if(brk, st->get_c0()));
}
int exec_again(VmState* st) {
VM_LOG(st) << "execute AGAIN\n";
int exec_again(VmState* st, bool brk) {
VM_LOG(st) << "execute AGAIN" << (brk ? "BRK" : "");
if (brk) {
st->set_c1(st->extract_cc(3));
}
return st->again(st->get_stack().pop_cont());
}
int exec_again_end(VmState* st) {
VM_LOG(st) << "execute AGAINEND\n";
int exec_again_end(VmState* st, bool brk) {
VM_LOG(st) << "execute AGAINEND" << (brk ? "BRK" : "");
if (brk) {
st->c1_save_set();
}
return st->again(st->extract_cc(0));
}
@ -437,44 +491,70 @@ void register_continuation_cond_loop_ops(OpcodeTable& cp0) {
.insert(OpcodeInstr::mksimple(0xe0, 8, "IFJMP", exec_if_jmp))
.insert(OpcodeInstr::mksimple(0xe1, 8, "IFNOTJMP", exec_ifnot_jmp))
.insert(OpcodeInstr::mksimple(0xe2, 8, "IFELSE", exec_if_else))
.insert(OpcodeInstr::mkext(
0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"),
std::bind(exec_do_with_ref, _1, _2, _4,
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->call(std::move(cont)) : 0; },
"IFREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(
0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"),
std::bind(exec_do_with_ref, _1, _2, _4,
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->call(std::move(cont)); },
"IFNOTREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(
0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"),
std::bind(exec_do_with_ref, _1, _2, _4,
[](auto st, auto cont) { return st->get_stack().pop_bool() ? st->jump(std::move(cont)) : 0; },
"IFJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(
0xe303, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTJMPREF"),
std::bind(exec_do_with_ref, _1, _2, _4,
[](auto st, auto cont) { return st->get_stack().pop_bool() ? 0 : st->jump(std::move(cont)); },
"IFNOTJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe300, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREF"),
std::bind(exec_do_with_cell, _1, _2, _4,
[](auto st, auto cell) {
return st->get_stack().pop_bool()
? st->call(st->ref_to_cont(std::move(cell)))
: 0;
},
"IFREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe301, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTREF"),
std::bind(exec_do_with_cell, _1, _2, _4,
[](auto st, auto cell) {
return st->get_stack().pop_bool()
? 0
: st->call(st->ref_to_cont(std::move(cell)));
},
"IFNOTREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe302, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFJMPREF"),
std::bind(exec_do_with_cell, _1, _2, _4,
[](auto st, auto cell) {
return st->get_stack().pop_bool()
? st->jump(st->ref_to_cont(std::move(cell)))
: 0;
},
"IFJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe303, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFNOTJMPREF"),
std::bind(exec_do_with_cell, _1, _2, _4,
[](auto st, auto cell) {
return st->get_stack().pop_bool()
? 0
: st->jump(st->ref_to_cont(std::move(cell)));
},
"IFNOTJMPREF"),
compute_len_push_ref))
.insert(OpcodeInstr::mksimple(0xe304, 16, "CONDSEL", exec_condsel))
.insert(OpcodeInstr::mksimple(0xe305, 16, "CONDSELCHK", exec_condsel_chk))
.insert(OpcodeInstr::mksimple(0xe308, 16, "IFRETALT", exec_ifretalt))
.insert(OpcodeInstr::mksimple(0xe309, 16, "IFNOTRETALT", exec_ifnotretalt))
.insert(OpcodeInstr::mkext(0xe30d, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFREFELSE"),
std::bind(exec_ifelse_ref, _1, _2, _4, true), compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe30e, 16, 0, std::bind(dump_push_ref, _1, _2, _3, "IFELSEREF"),
std::bind(exec_ifelse_ref, _1, _2, _4, false), compute_len_push_ref))
.insert(OpcodeInstr::mkext(0xe30f, 16, 0, std::bind(dump_push_ref2, _1, _2, _3, "IFREFELSEREF"),
exec_ifref_elseref, compute_len_push_ref2))
.insert(OpcodeInstr::mkfixed(0xe380 >> 6, 10, 6, dump_if_bit_jmp, exec_if_bit_jmp))
.insert(OpcodeInstr::mkext(0xe3c0 >> 6, 10, 6, dump_if_bit_jmpref, exec_if_bit_jmpref, compute_len_push_ref))
.insert(OpcodeInstr::mksimple(0xe4, 8, "REPEAT", exec_repeat))
.insert(OpcodeInstr::mksimple(0xe5, 8, "REPEATEND", exec_repeat_end))
.insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", exec_until))
.insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", exec_until_end))
.insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", exec_while))
.insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", exec_while_end))
.insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", exec_again))
.insert(OpcodeInstr::mksimple(0xeb, 8, "AGAINEND", exec_again_end));
.insert(OpcodeInstr::mksimple(0xe4, 8, "REPEAT", std::bind(exec_repeat, _1, false)))
.insert(OpcodeInstr::mksimple(0xe5, 8, "REPEATEND", std::bind(exec_repeat_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe6, 8, "UNTIL", std::bind(exec_until, _1, false)))
.insert(OpcodeInstr::mksimple(0xe7, 8, "UNTILEND", std::bind(exec_until_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe8, 8, "WHILE", std::bind(exec_while, _1, false)))
.insert(OpcodeInstr::mksimple(0xe9, 8, "WHILEEND", std::bind(exec_while_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xea, 8, "AGAIN", std::bind(exec_again, _1, false)))
.insert(OpcodeInstr::mksimple(0xeb, 8, "AGAINEND", std::bind(exec_again_end, _1, false)))
.insert(OpcodeInstr::mksimple(0xe314, 16, "REPEATBRK", std::bind(exec_repeat, _1, true)))
.insert(OpcodeInstr::mksimple(0xe315, 16, "REPEATENDBRK", std::bind(exec_repeat_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe316, 16, "UNTILBRK", std::bind(exec_until, _1, true)))
.insert(OpcodeInstr::mksimple(0xe317, 16, "UNTILENDBRK", std::bind(exec_until_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe318, 16, "WHILEBRK", std::bind(exec_while, _1, true)))
.insert(OpcodeInstr::mksimple(0xe319, 16, "WHILEENDBRK", std::bind(exec_while_end, _1, true)))
.insert(OpcodeInstr::mksimple(0xe31a, 16, "AGAINBRK", std::bind(exec_again, _1, true)))
.insert(OpcodeInstr::mksimple(0xe31b, 16, "AGAINENDBRK", std::bind(exec_again_end, _1, true)));
}
int exec_setcontargs_common(VmState* st, int copy, int more) {
@ -706,6 +786,17 @@ int exec_save_ctr(VmState* st, unsigned args) {
return 0;
}
int exec_samealt(VmState* st, bool save) {
VM_LOG(st) << "execute SAMEALT" << (save ? "SAVE" : "");
auto c0 = st->get_c0();
if (save) {
force_cregs(c0)->define_c1(st->get_c1());
st->set_c0(c0);
}
st->set_c1(std::move(c0));
return 0;
}
int exec_savealt_ctr(VmState* st, unsigned args) {
unsigned idx = args & 15;
VM_LOG(st) << "execute SAVEALTCTR c" << idx;
@ -883,6 +974,8 @@ void register_continuation_change_ops(OpcodeTable& cp0) {
.insert(OpcodeInstr::mksimple(0xedf7, 16, "THENRETALT", exec_thenret_alt))
.insert(OpcodeInstr::mksimple(0xedf8, 16, "INVERT", exec_invert))
.insert(OpcodeInstr::mksimple(0xedf9, 16, "BOOLEVAL", exec_booleval))
.insert(OpcodeInstr::mksimple(0xedfa, 16, "SAMEALT", std::bind(exec_samealt, _1, false)))
.insert(OpcodeInstr::mksimple(0xedfb, 16, "SAMEALTSAVE", std::bind(exec_samealt, _1, true)))
.insert(OpcodeInstr::mkfixed(0xee, 8, 8, std::bind(dump_setcontargs, _1, _2, "BLESSARGS"), exec_bless_args));
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
@ -45,6 +45,7 @@ const char* get_exception_msg(Excno exc_no);
class VmError {
Excno exc_no;
bool msg_alloc = false;
const char* msg;
long long arg;
@ -55,6 +56,18 @@ class VmError {
}
VmError(Excno _excno, const char* _msg, long long _arg) : exc_no(_excno), msg(_msg), arg(_arg) {
}
VmError(Excno _excno, std::string _msg, long long _arg = 0) : exc_no(_excno), msg_alloc(true), arg(_arg) {
msg_alloc = true;
char* p = (char*)malloc(_msg.size() + 1);
memcpy(p, _msg.data(), _msg.size());
p[_msg.size()] = 0;
msg = p;
}
~VmError() {
if (msg_alloc) {
free(const_cast<char*>(msg));
}
}
int get_errno() const {
return static_cast<int>(exc_no);
}

View file

@ -333,6 +333,22 @@ int VmState::ret_alt(int ret_args) {
return jump(std::move(cont), ret_args);
}
Ref<Continuation> VmState::c1_envelope(Ref<Continuation> cont, bool save) {
if (save) {
force_cregs(cont)->define_c1(cr.c[1]);
force_cregs(cont)->define_c0(cr.c[0]);
}
set_c1(cont);
return cont;
}
void VmState::c1_save_set(bool save) {
if (save) {
force_cregs(cr.c[0])->define_c1(cr.c[1]);
}
set_c1(cr.c[0]);
}
Ref<OrdCont> VmState::extract_cc(int save_cr, int stack_copy, int cc_args) {
Ref<Stack> new_stk;
if (stack_copy < 0 || stack_copy == stack->depth()) {

View file

@ -297,6 +297,11 @@ class VmState final : public VmStateInterface {
int throw_exception(int excno, StackEntry&& arg);
int throw_exception(int excno);
Ref<OrdCont> extract_cc(int save_cr = 1, int stack_copy = -1, int cc_args = -1);
Ref<Continuation> c1_envelope(Ref<Continuation> cont, bool save = true);
Ref<Continuation> c1_envelope_if(bool cond, Ref<Continuation> cont, bool save = true) {
return cond ? c1_envelope(std::move(cont), save) : std::move(cont);
}
void c1_save_set(bool save = true);
void fatal(void) const {
throw VmFatal{};
}
@ -313,6 +318,9 @@ class VmState final : public VmStateInterface {
bool get_chksig_always_succeed() const {
return chksig_always_succeed;
}
Ref<OrdCont> ref_to_cont(Ref<Cell> cell) const {
return td::make_ref<OrdCont>(load_cell_slice_ref(std::move(cell)), get_cp());
}
private:
void init_cregs(bool same_c3 = false, bool push_0 = true);