Fabcoin Core  0.16.2
P2P Digital Currency
VMValidate.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
20 #include <libethereum/ExtVM.h>
21 #include "VMConfig.h"
22 #include "VM.h"
23 using namespace std;
24 using namespace dev;
25 using namespace dev::eth;
26 
27 #if EVM_JUMPS_AND_SUBS
28 
30 //
31 // invalid code will throw an exception
32 //
33 
34 void VM::validate(ExtVMFace& _ext)
35 {
36  m_ext = &_ext;
37  initEntry();
38  size_t PC;
39  byte OP;
40  for (PC = 0; (OP = m_code[PC]); ++PC)
41  if (OP == byte(Instruction::BEGINSUB))
42  validateSubroutine(PC, m_return, m_stack);
43  else if (OP == byte(Instruction::BEGINDATA))
44  break;
45  else if (
46  (byte)Instruction::PUSH1 <= (byte)OP &&
47  (byte)PC <= (byte)Instruction::PUSH32)
48  PC += (byte)OP - (byte)Instruction::PUSH1;
49  else if (
50  OP == Instruction::JUMPTO ||
51  OP == Instruction::JUMPIF ||
52  OP == Instruction::JUMPSUB)
53  PC += 4;
54  else if (OP == Instruction::JUMPV || op == Instruction::JUMPSUBV)
55  PC += 4 * m_code[PC]; // number of 4-byte dests followed by table
56  }
57 }
58 
59 // we validate each subroutine individually, as if at top level
60 // - PC is the offset in the code to start validating at
61 // - RP is the top PC on return stack that RETURNSUB returns to
62 // - SP = FP at the top level, so the stack size is also the frame size
63 void VM::validateSubroutine(uint64_t _PC, uint64_t* _RP, u256* _SP)
64 {
65  // set current interpreter state
66  m_PC = _PC, m_RP = _RP, m_SP = _SP;
67 
69  DO_CASES
70  {
71  CASE(JUMPDEST)
72  {
73  // if frame size is set then we have been here before
74  ptrdiff_t frameSize = m_frameSize[m_PC];
75  if (0 <= frameSize)
76  {
77  // check for constant frame size
78  if (stackSize() != frameSize)
79  throwBadStack(stackSize(), frameSize, 0);
80 
81  // return to break cycle in control flow graph
82  return;
83  }
84  // set frame size to check later
85  m_frameSize[m_PC] = stackSize();
86  ++m_PC;
87  }
88  NEXT
89 
90  CASE(JUMPTO)
91  {
92  // extract jump destination from bytecode
93  m_PC = decodeJumpDest(m_code, m_PC);
94  }
95  NEXT
96 
97  CASE(JUMPIF)
98  {
99  // recurse to validate code to jump to, saving and restoring
100  // interpreter state around call
101  _PC = m_PC, _RP = m_RP, _SP = m_SP;
102  validateSubroutine(decodeJumpvDest(m_code, m_PC, m_SP), _RP, _SP);
103  m_PC = _PC, m_RP = _RP, m_SP = _SP;
104  ++m_PC;
105  }
106  NEXT
107 
108  CASE(JUMPV)
109  {
110  // for every jump destination in jump vector
111  for (size_t dest = 0, nDests = m_code[m_PC+1]; dest < nDests; ++dest)
112  {
113  // recurse to validate code to jump to, saving and
114  // restoring interpreter state around call
115  _PC = m_PC, _RP = m_RP, _SP = m_SP;
116  validateSubroutine(decodeJumpDest(m_code, m_PC), _RP, _SP);
117  m_PC = _PC, m_RP = _RP, m_SP = _SP;
118  }
119  }
120  RETURN
121 
122  CASE(JUMPSUB)
123  {
124  // check for enough arguments on stack
125  size_t destPC = decodeJumpDest(m_code, m_PC);
126  byte nArgs = m_code[destPC+1];
127  if (stackSize() < nArgs)
128  throwBadStack(stackSize(), nArgs, 0);
129  }
130  NEXT
131 
132  CASE(JUMPSUBV)
133  {
134  // for every subroutine in jump vector
135  _PC = m_PC;
136  for (size_t sub = 0, nSubs = m_code[m_PC+1]; sub < nSubs; ++sub)
137  {
138  // check for enough arguments on stack
139  u256 slot = sub;
140  _SP = &slot;
141  size_t destPC = decodeJumpvDest(m_code, _PC, _SP);
142  byte nArgs = m_code[destPC+1];
143  if (stackSize() < nArgs)
144  throwBadStack(stackSize(), nArgs, 0);
145  }
146  m_PC = _PC;
147  }
148  NEXT
149 
150  CASE(RETURNSUB)
151  CASE(RETURN)
152  CASE(SUICIDE)
153  CASE(STOP)
154  {
155  // return to top level
156  }
157  BREAK;
158 
159  CASE(BEGINSUB)
160  CASE(BEGINDATA)
161  CASE(BAD)
162  DEFAULT
163  {
164  throwBadInstruction();
165  }
166  }
167  END_CASES
168 }
169 
170 #endif
#define CASE(name)
Definition: VMConfig.h:133
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
uint8_t byte
Definition: Common.h:57
halt execution returning output data
get the program counter
std::hash for asio::adress
Definition: Common.h:323
#define DEFAULT
Definition: VMConfig.h:137
#define DO_CASES
Definition: VMConfig.h:132
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
#define NEXT
Definition: VMConfig.h:134
#define INIT_CASES
Definition: VMConfig.h:131
Interface and null implementation of the class for specifying VM externalities.
Definition: ExtVMFace.h:265
#define BREAK
Definition: VMConfig.h:136
uint8_t byte
Definition: Common.h:10