mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Yul grammar generator: Bound memory accesses.
This commit is contained in:
		
							parent
							
								
									ddbef8f650
								
							
						
					
					
						commit
						f8880cad82
					
				| @ -6,8 +6,6 @@ | ||||
| } | ||||
| // ---- | ||||
| // Trace: | ||||
| //   CREATE(0, 0xffffffffffffffffffffffffffffffffffffffff, 0) | ||||
| //   CREATE(0, 0xffffffffffffffffffffffffffffffffffffffff, 0) | ||||
| // Memory dump: | ||||
| //      0: 0000000000000000000000000000000000000000000000000000000000000001 | ||||
| // Storage dump: | ||||
|  | ||||
| @ -8,8 +8,6 @@ | ||||
| // EVMVersion: >=constantinople | ||||
| // ---- | ||||
| // Trace: | ||||
| //   CREATE2(0, 0xffffffffffffffffffffffffffffffffffffffff, 0, 0) | ||||
| //   CREATE2(0, 0xffffffffffffffffffffffffffffffffffffffff, 0, 0) | ||||
| // Memory dump: | ||||
| //      0: 0000000000000000000000000000000000000000000000000000000000000001 | ||||
| // Storage dump: | ||||
|  | ||||
| @ -14,7 +14,6 @@ | ||||
| // ---- | ||||
| // Trace: | ||||
| //   CALL(153, 0x11111111, 0, 64, 32, 256, 32) | ||||
| //   RETURN(0, 0) | ||||
| // Memory dump: | ||||
| //     40: 0000000000000000000000000000000000000000000000000000000000000042 | ||||
| //    100: 0000000000000000000000000000000000000000000000000000000000000042 | ||||
|  | ||||
| @ -7,38 +7,6 @@ | ||||
| } | ||||
| // ---- | ||||
| // Trace: | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   LOG0(0, 0) | ||||
| //   Trace size limit reached. | ||||
| //   Interpreter execution step limit reached. | ||||
| // Memory dump: | ||||
| // Storage dump: | ||||
|  | ||||
| @ -5,6 +5,5 @@ | ||||
| // EVMVersion: >=constantinople | ||||
| // ---- | ||||
| // Trace: | ||||
| //   CALL(0, 0, 0, 0, 0, 0, 0) | ||||
| // Memory dump: | ||||
| // Storage dump: | ||||
|  | ||||
| @ -5,6 +5,5 @@ | ||||
| } | ||||
| // ---- | ||||
| // Trace: | ||||
| //   CALLDATACOPY(32, 0, 0) | ||||
| // Memory dump: | ||||
| // Storage dump: | ||||
|  | ||||
| @ -351,9 +351,22 @@ void ProtoConverter::visit(BinaryOp const& _x) | ||||
| 		break; | ||||
| 	} | ||||
| 	m_output << "("; | ||||
| 	visit(_x.left()); | ||||
| 	m_output << ","; | ||||
| 	visit(_x.right()); | ||||
| 	if (op == BinaryOp::KECCAK) | ||||
| 	{ | ||||
| 		m_output << "mod("; | ||||
| 		visit(_x.left()); | ||||
| 		m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 		m_output << ","; | ||||
| 		m_output << "mod("; | ||||
| 		visit(_x.right()); | ||||
| 		m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		visit(_x.left()); | ||||
| 		m_output << ","; | ||||
| 		visit(_x.right()); | ||||
| 	} | ||||
| 	m_output << ")"; | ||||
| } | ||||
| 
 | ||||
| @ -623,7 +636,14 @@ void ProtoConverter::visit(UnaryOp const& _x) | ||||
| 		break; | ||||
| 	} | ||||
| 	m_output << "("; | ||||
| 	visit(_x.operand()); | ||||
| 	if (op == UnaryOp::MLOAD) | ||||
| 	{ | ||||
| 		m_output << "mod("; | ||||
| 		visit(_x.operand()); | ||||
| 		m_output << ", " << to_string(s_maxMemory) << ")"; | ||||
| 	} | ||||
| 	else | ||||
| 		visit(_x.operand()); | ||||
| 	m_output << ")"; | ||||
| } | ||||
| 
 | ||||
| @ -778,11 +798,15 @@ void ProtoConverter::visit(CopyFunc const& _x) | ||||
| 		break; | ||||
| 	} | ||||
| 	m_output << "("; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.target()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	visit(_x.source()); | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.size()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	m_output << ")\n"; | ||||
| } | ||||
| 
 | ||||
| @ -792,32 +816,42 @@ void ProtoConverter::visit(ExtCodeCopy const& _x) | ||||
| 	m_output << "("; | ||||
| 	visit(_x.addr()); | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.target()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	visit(_x.source()); | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.size()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	m_output << ")\n"; | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::visit(LogFunc const& _x) | ||||
| { | ||||
| 	auto visitPosAndSize = [&](LogFunc const& _y) { | ||||
| 		m_output << "mod("; | ||||
| 		visit(_y.pos()); | ||||
| 		m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 		m_output << ", "; | ||||
| 		m_output << "mod("; | ||||
| 		visit(_y.size()); | ||||
| 		m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	}; | ||||
| 
 | ||||
| 	switch (_x.num_topics()) | ||||
| 	{ | ||||
| 	case LogFunc::ZERO: | ||||
| 		m_output << "log0"; | ||||
| 		m_output << "("; | ||||
| 		visit(_x.pos()); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.size()); | ||||
| 		visitPosAndSize(_x); | ||||
| 		m_output << ")\n"; | ||||
| 		break; | ||||
| 	case LogFunc::ONE: | ||||
| 		m_output << "log1"; | ||||
| 		m_output << "("; | ||||
| 		visit(_x.pos()); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.size()); | ||||
| 		visitPosAndSize(_x); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.t1()); | ||||
| 		m_output << ")\n"; | ||||
| @ -825,9 +859,7 @@ void ProtoConverter::visit(LogFunc const& _x) | ||||
| 	case LogFunc::TWO: | ||||
| 		m_output << "log2"; | ||||
| 		m_output << "("; | ||||
| 		visit(_x.pos()); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.size()); | ||||
| 		visitPosAndSize(_x); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.t1()); | ||||
| 		m_output << ", "; | ||||
| @ -837,9 +869,7 @@ void ProtoConverter::visit(LogFunc const& _x) | ||||
| 	case LogFunc::THREE: | ||||
| 		m_output << "log3"; | ||||
| 		m_output << "("; | ||||
| 		visit(_x.pos()); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.size()); | ||||
| 		visitPosAndSize(_x); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.t1()); | ||||
| 		m_output << ", "; | ||||
| @ -851,9 +881,7 @@ void ProtoConverter::visit(LogFunc const& _x) | ||||
| 	case LogFunc::FOUR: | ||||
| 		m_output << "log4"; | ||||
| 		m_output << "("; | ||||
| 		visit(_x.pos()); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.size()); | ||||
| 		visitPosAndSize(_x); | ||||
| 		m_output << ", "; | ||||
| 		visit(_x.t1()); | ||||
| 		m_output << ", "; | ||||
| @ -1015,13 +1043,21 @@ void ProtoConverter::visit(LowLevelCall const& _x) | ||||
| 		visit(_x.wei()); | ||||
| 		m_output << ", "; | ||||
| 	} | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.in()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.insize()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.out()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.outsize()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	m_output << ")"; | ||||
| } | ||||
| 
 | ||||
| @ -1048,9 +1084,13 @@ void ProtoConverter::visit(Create const& _x) | ||||
| 	} | ||||
| 	visit(_x.wei()); | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.position()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.size()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	if (type == Create::CREATE2) | ||||
| 	{ | ||||
| 		m_output << ", "; | ||||
| @ -1069,7 +1109,8 @@ void ProtoConverter::visit(IfStmt const& _x) | ||||
| 
 | ||||
| void ProtoConverter::visit(StoreFunc const& _x) | ||||
| { | ||||
| 	switch (_x.st()) | ||||
| 	auto storeType = _x.st(); | ||||
| 	switch (storeType) | ||||
| 	{ | ||||
| 	case StoreFunc::MSTORE: | ||||
| 		m_output << "mstore("; | ||||
| @ -1081,7 +1122,15 @@ void ProtoConverter::visit(StoreFunc const& _x) | ||||
| 		m_output << "mstore8("; | ||||
| 		break; | ||||
| 	} | ||||
| 	visit(_x.loc()); | ||||
| 	// Write to memory within bounds, storage is unbounded
 | ||||
| 	if (storeType == StoreFunc::SSTORE) | ||||
| 		visit(_x.loc()); | ||||
| 	else | ||||
| 	{ | ||||
| 		m_output << "mod("; | ||||
| 		visit(_x.loc()); | ||||
| 		m_output << ", " << to_string(s_maxMemory) << ")"; | ||||
| 	} | ||||
| 	m_output << ", "; | ||||
| 	visit(_x.val()); | ||||
| 	m_output << ")\n"; | ||||
| @ -1262,9 +1311,13 @@ void ProtoConverter::visit(RetRevStmt const& _x) | ||||
| 		break; | ||||
| 	} | ||||
| 	m_output << "("; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.pos()); | ||||
| 	m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")"; | ||||
| 	m_output << ", "; | ||||
| 	m_output << "mod("; | ||||
| 	visit(_x.size()); | ||||
| 	m_output << ", " << to_string(s_maxSize) << ")"; | ||||
| 	m_output << ")\n"; | ||||
| } | ||||
| 
 | ||||
| @ -1651,8 +1704,12 @@ void ProtoConverter::fillFunctionCallInput(unsigned _numInParams) | ||||
| 			m_output << "calldataload(" << slot << ")"; | ||||
| 			break; | ||||
| 		case 1: | ||||
| 		{ | ||||
| 			// Access memory within stipulated bounds
 | ||||
| 			slot = "mod(" + dictionaryToken() + ", " + to_string(s_maxMemory) + ")"; | ||||
| 			m_output << "mload(" << slot << ")"; | ||||
| 			break; | ||||
| 		} | ||||
| 		case 2: | ||||
| 			m_output << "sload(" << slot << ")"; | ||||
| 			break; | ||||
|  | ||||
| @ -344,6 +344,11 @@ private: | ||||
| 	static unsigned constexpr s_modOutputParams = 5; | ||||
| 	/// Hard-coded identifier for a Yul object's data block
 | ||||
| 	static auto constexpr s_dataIdentifier = "datablock"; | ||||
| 	/// Upper bound on memory writes = 2**32 - 1
 | ||||
| 	/// See: https://eips.ethereum.org/EIPS/eip-1985#memory-size
 | ||||
| 	static unsigned constexpr s_maxMemory = 4294967295; | ||||
| 	/// Upper bound on size for range copy functions
 | ||||
| 	static unsigned constexpr s_maxSize = 65536; | ||||
| 	/// Predicate to keep track of for body scope. If false, break/continue
 | ||||
| 	/// statements can not be created.
 | ||||
| 	bool m_inForBodyScope; | ||||
|  | ||||
| @ -211,22 +211,24 @@ u256 EVMInstructionInterpreter::eval( | ||||
| 	case Instruction::CALLDATASIZE: | ||||
| 		return m_state.calldata.size(); | ||||
| 	case Instruction::CALLDATACOPY: | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (accessMemory(arg[0], arg[2])) | ||||
| 			copyZeroExtended( | ||||
| 				m_state.memory, m_state.calldata, | ||||
| 				size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||
| 			); | ||||
| 		if (arg[2] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::CODESIZE: | ||||
| 		return m_state.code.size(); | ||||
| 	case Instruction::CODECOPY: | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (accessMemory(arg[0], arg[2])) | ||||
| 			copyZeroExtended( | ||||
| 				m_state.memory, m_state.code, | ||||
| 				size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||
| 			); | ||||
| 		if (arg[2] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::GASPRICE: | ||||
| 		return m_state.gasprice; | ||||
| @ -239,23 +241,25 @@ u256 EVMInstructionInterpreter::eval( | ||||
| 	case Instruction::EXTCODEHASH: | ||||
| 		return u256(keccak256(h256(arg[0] + 1))); | ||||
| 	case Instruction::EXTCODECOPY: | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (accessMemory(arg[1], arg[3])) | ||||
| 			// TODO this way extcodecopy and codecopy do the same thing.
 | ||||
| 			copyZeroExtended( | ||||
| 				m_state.memory, m_state.code, | ||||
| 				size_t(arg[1]), size_t(arg[2]), size_t(arg[3]) | ||||
| 			); | ||||
| 		if (arg[3] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::RETURNDATASIZE: | ||||
| 		return m_state.returndata.size(); | ||||
| 	case Instruction::RETURNDATACOPY: | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (accessMemory(arg[0], arg[2])) | ||||
| 			copyZeroExtended( | ||||
| 				m_state.memory, m_state.returndata, | ||||
| 				size_t(arg[0]), size_t(arg[1]), size_t(arg[2]) | ||||
| 			); | ||||
| 		if (arg[2] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::BLOCKHASH: | ||||
| 		if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber) | ||||
| @ -297,38 +301,54 @@ u256 EVMInstructionInterpreter::eval( | ||||
| 		return 0x99; | ||||
| 	case Instruction::LOG0: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::LOG1: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::LOG2: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::LOG3: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	case Instruction::LOG4: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		return 0; | ||||
| 	// --------------- calls ---------------
 | ||||
| 	case Instruction::CREATE: | ||||
| 		accessMemory(arg[1], arg[2]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); | ||||
| 		if (arg[2] != 0) | ||||
| 		{ | ||||
| 			logTrace(_instruction, arg); | ||||
| 			return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); | ||||
| 		} | ||||
| 		return 0xcccccc; | ||||
| 	case Instruction::CREATE2: | ||||
| 		accessMemory(arg[1], arg[2]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); | ||||
| 		if (arg[2] != 0) | ||||
| 		{ | ||||
| 			logTrace(_instruction, arg); | ||||
| 			return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff"); | ||||
| 		} | ||||
| 		return 0xdddddd; | ||||
| 	case Instruction::CALL: | ||||
| 	case Instruction::CALLCODE: | ||||
| 		accessMemory(arg[3], arg[4]); | ||||
| 		accessMemory(arg[5], arg[6]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[4] != 0) | ||||
| 			accessMemory(arg[3], arg[4]); | ||||
| 		if (arg[6] != 0) | ||||
| 			accessMemory(arg[5], arg[6]); | ||||
| 		if (arg[4] != 0 && arg[6] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		// Randomly fail based on the called address if it isn't a call to self.
 | ||||
| 		// Used for fuzzing.
 | ||||
| 		return ( | ||||
| @ -337,10 +357,12 @@ u256 EVMInstructionInterpreter::eval( | ||||
| 		) ? 1 : 0; | ||||
| 	case Instruction::DELEGATECALL: | ||||
| 	case Instruction::STATICCALL: | ||||
| 		accessMemory(arg[2], arg[3]); | ||||
| 		accessMemory(arg[4], arg[5]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 
 | ||||
| 		if (arg[3] != 0) | ||||
| 			accessMemory(arg[2], arg[3]); | ||||
| 		if (arg[5] != 0) | ||||
| 			accessMemory(arg[4], arg[5]); | ||||
| 		if (arg[3] != 0 && arg[5] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		// Randomly fail based on the called address if it isn't a call to self.
 | ||||
| 		// Used for fuzzing.
 | ||||
| 		return ( | ||||
| @ -352,12 +374,14 @@ u256 EVMInstructionInterpreter::eval( | ||||
| 		m_state.returndata = {}; | ||||
| 		if (accessMemory(arg[0], arg[1])) | ||||
| 			m_state.returndata = m_state.readMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg, m_state.returndata); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg, m_state.returndata); | ||||
| 		BOOST_THROW_EXCEPTION(ExplicitlyTerminatedWithReturn()); | ||||
| 	} | ||||
| 	case Instruction::REVERT: | ||||
| 		accessMemory(arg[0], arg[1]); | ||||
| 		logTrace(_instruction, arg); | ||||
| 		if (arg[1] != 0) | ||||
| 			logTrace(_instruction, arg); | ||||
| 		m_state.storage.clear(); | ||||
| 		m_state.trace.clear(); | ||||
| 		BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); | ||||
| @ -479,7 +503,10 @@ u256 EVMInstructionInterpreter::evalBuiltin( | ||||
| 	else if (fun == "datacopy") | ||||
| 	{ | ||||
| 		// This is identical to codecopy.
 | ||||
| 		if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2))) | ||||
| 		if ( | ||||
| 				_evaluatedArguments.at(2) != 0 && | ||||
| 				accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2)) | ||||
| 		) | ||||
| 			copyZeroExtended( | ||||
| 				m_state.memory, | ||||
| 				m_state.code, | ||||
| @ -560,8 +587,13 @@ void EVMInstructionInterpreter::logTrace( | ||||
| 	if (!(_writesToMemory && memWriteTracingDisabled())) | ||||
| 	{ | ||||
| 		string message = _pseudoInstruction + "("; | ||||
| 		std::pair<bool, size_t> inputMemoryPtrModified = isInputMemoryPtrModified(_pseudoInstruction, _arguments); | ||||
| 		for (size_t i = 0; i < _arguments.size(); ++i) | ||||
| 			message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); | ||||
| 		{ | ||||
| 			bool printZero = inputMemoryPtrModified.first && inputMemoryPtrModified.second == i; | ||||
| 			u256 arg = printZero ? 0 : _arguments[i]; | ||||
| 			message += (i > 0 ? ", " : "") + formatNumber(arg); | ||||
| 		} | ||||
| 		message += ")"; | ||||
| 		if (!_data.empty()) | ||||
| 			message += " [" + util::toHex(_data) + "]"; | ||||
| @ -573,3 +605,65 @@ void EVMInstructionInterpreter::logTrace( | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| std::pair<bool, size_t> EVMInstructionInterpreter::isInputMemoryPtrModified( | ||||
| 	std::string const& _pseudoInstruction, | ||||
| 	std::vector<u256> const& _arguments | ||||
| ) | ||||
| { | ||||
| 	if (_pseudoInstruction == "return" || _pseudoInstruction == "revert") | ||||
| 	{ | ||||
| 		if (_arguments[1] == 0) | ||||
| 			return {true, 0}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	else if ( | ||||
| 		_pseudoInstruction == "returndatacopy" || _pseudoInstruction == "calldatacopy" | ||||
| 		|| _pseudoInstruction == "codecopy") | ||||
| 	{ | ||||
| 		if (_arguments[2] == 0) | ||||
| 			return {true, 0}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	else if (_pseudoInstruction == "extcodedatacopy") | ||||
| 	{ | ||||
| 		if (_arguments[3] == 0) | ||||
| 			return {true, 1}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	else if ( | ||||
| 		_pseudoInstruction == "log0" || _pseudoInstruction == "log1" || _pseudoInstruction == "log2" | ||||
| 		|| _pseudoInstruction == "log3" || _pseudoInstruction == "log4") | ||||
| 	{ | ||||
| 		if (_arguments[1] == 0) | ||||
| 			return {true, 0}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	if (_pseudoInstruction == "create" || _pseudoInstruction == "create2") | ||||
| 	{ | ||||
| 		if (_arguments[2] == 0) | ||||
| 			return {true, 1}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	if (_pseudoInstruction == "call" || _pseudoInstruction == "callcode") | ||||
| 	{ | ||||
| 		if (_arguments[4] == 0) | ||||
| 			return {true, 3}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	else if (_pseudoInstruction == "delegatecall" || _pseudoInstruction == "staticcall") | ||||
| 	{ | ||||
| 		if (_arguments[3] == 0) | ||||
| 			return {true, 2}; | ||||
| 		else | ||||
| 			return {false, 0}; | ||||
| 	} | ||||
| 	else | ||||
| 		return {false, 0}; | ||||
| } | ||||
|  | ||||
| @ -125,6 +125,19 @@ private: | ||||
| 		std::vector<u256> const& _arguments = {}, | ||||
| 		bytes const& _data = {} | ||||
| 	); | ||||
| 
 | ||||
| 	/// @returns a pair of boolean and size_t whose first value is true if @param _pseudoInstruction
 | ||||
| 	/// is a Yul instruction that the Yul optimizer's loadResolver step rewrites the input
 | ||||
| 	/// memory pointer value to zero if that instruction's read length (contained within @param
 | ||||
| 	// _arguments) is zero, and whose second value is the positional index of the input memory
 | ||||
| 	// pointer argument.
 | ||||
| 	/// If the Yul instruction is unaffected or affected but read length is non-zero, the first
 | ||||
| 	/// value is false.
 | ||||
| 	std::pair<bool, size_t> isInputMemoryPtrModified( | ||||
| 		std::string const& _pseudoInstruction, | ||||
| 		std::vector<u256> const& _arguments | ||||
| 	); | ||||
| 
 | ||||
| 	/// @returns disable trace flag.
 | ||||
| 	bool memWriteTracingDisabled() | ||||
| 	{ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user