mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Randomize calldataload and storage slots and use dictionary tokens as function argument
This commit is contained in:
		
							parent
							
								
									d066ba71a4
								
							
						
					
					
						commit
						fce65ec811
					
				| @ -1078,17 +1078,67 @@ void ProtoConverter::registerFunction(FunctionDef const* _x) | ||||
| 	m_functionDefMap.emplace(make_pair(_x, funcName)); | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::fillFunctionCallInput(unsigned _numInParams) | ||||
| { | ||||
| 	for (unsigned i = 0; i < _numInParams; i++) | ||||
| 	{ | ||||
| 		// Throw a 4-sided dice to choose whether to populate function input
 | ||||
| 		// argument from a pseudo-randomly chosen slot in one of the following
 | ||||
| 		// locations: calldata, memory, storage, or yul optimizer dictionary.
 | ||||
| 		unsigned diceValue = counter() % 4; | ||||
| 		// Pseudo-randomly choose one of the first ten 32-byte
 | ||||
| 		// aligned slots.
 | ||||
| 		string slot = to_string((counter() % 10) * 32); | ||||
| 		switch (diceValue) | ||||
| 		{ | ||||
| 		case 0: | ||||
| 			m_output << "calldataload(" << slot << ")"; | ||||
| 			break; | ||||
| 		case 1: | ||||
| 			m_output << "mload(" << slot << ")"; | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			m_output << "sload(" << slot << ")"; | ||||
| 			break; | ||||
| 		case 3: | ||||
| 			// Call to dictionaryToken() automatically picks a token
 | ||||
| 			// at a pseudo-random location.
 | ||||
| 			m_output << dictionaryToken(); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (i < _numInParams - 1) | ||||
| 			m_output << ","; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::saveFunctionCallOutput(vector<string> const& _varsVec) | ||||
| { | ||||
| 	for (auto const& var: _varsVec) | ||||
| 	{ | ||||
| 		// Flip a dice to choose whether to save output values
 | ||||
| 		// in storage or memory.
 | ||||
| 		bool coinFlip = counter() % 2 == 0; | ||||
| 		// Pseudo-randomly choose one of the first ten 32-byte
 | ||||
| 		// aligned slots.
 | ||||
| 		string slot = to_string((counter() % 10) * 32); | ||||
| 		if (coinFlip) | ||||
| 			m_output << "sstore(" << slot << ", " << var << ")\n"; | ||||
| 		else | ||||
| 			m_output << "mstore(" << slot << ", " << var << ")\n"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::createFunctionCall( | ||||
| 	string _funcName, | ||||
| 	unsigned _numInParams, | ||||
| 	unsigned _numOutParams | ||||
| ) | ||||
| { | ||||
| 	// Prints the following to output stream "let x_i,...,x_n := "
 | ||||
| 	unsigned startIdx = counter(); | ||||
| 	vector<string> varsVec{}; | ||||
| 	if (_numOutParams > 0) | ||||
| 	{ | ||||
| 		unsigned startIdx = counter(); | ||||
| 		// Prints the following to output stream "let x_i,...,x_n := "
 | ||||
| 		varsVec = createVarDecls( | ||||
| 			startIdx, | ||||
| 			startIdx + _numOutParams, | ||||
| @ -1096,24 +1146,22 @@ void ProtoConverter::createFunctionCall( | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	// Call the function with the correct number of input parameters via calls to calldataload with
 | ||||
| 	// incremental addresses.
 | ||||
| 	// Call the function with the correct number of input parameters
 | ||||
| 	m_output << _funcName << "("; | ||||
| 	for (unsigned i = 0; i < _numInParams; i++) | ||||
| 	{ | ||||
| 		m_output << "calldataload(" << std::to_string(i*32) << ")"; | ||||
| 		if (i < _numInParams - 1) | ||||
| 			m_output << ","; | ||||
| 	} | ||||
| 	if (_numInParams > 0) | ||||
| 		fillFunctionCallInput(_numInParams); | ||||
| 	m_output << ")\n"; | ||||
| 
 | ||||
| 	// Save output values to storage
 | ||||
| 	for (unsigned i = 0; i < varsVec.size(); i++) | ||||
| 		m_output << "sstore(" << std::to_string(i*32) << ", " << varsVec[i] << ")\n"; | ||||
| 
 | ||||
| 	// Add newly minted vars to current scope
 | ||||
| 	if (!varsVec.empty()) | ||||
| 	{ | ||||
| 		// Save values returned by function so that they are reflected
 | ||||
| 		// in the interpreter trace.
 | ||||
| 		saveFunctionCallOutput(varsVec); | ||||
| 		// Add newly minted vars to current scope
 | ||||
| 		addVarsToScope(varsVec); | ||||
| 	} | ||||
| 	else | ||||
| 		yulAssert(_numOutParams == 0, "Proto fuzzer: Function return value not saved"); | ||||
| } | ||||
| 
 | ||||
| void ProtoConverter::createFunctionDefAndCall( | ||||
|  | ||||
| @ -208,6 +208,21 @@ private: | ||||
| 	/// @param _numOutParams Number of output parameters in function signature
 | ||||
| 	void createFunctionCall(std::string _funcName, unsigned _numInParams, unsigned _numOutParams); | ||||
| 
 | ||||
| 	/// Print the yul syntax to pass input arguments to a function that has
 | ||||
| 	/// @a _numInParams number of input parameters to the output stream.
 | ||||
| 	/// The input arguments are pseudo-randomly chosen from calldata, memory,
 | ||||
| 	/// storage, or the yul optimizer hex dictionary.
 | ||||
| 	/// @param _numInParams Number of input arguments to fill
 | ||||
| 	void fillFunctionCallInput(unsigned _numInParams); | ||||
| 
 | ||||
| 	/// Print the yul syntax to save values returned by a function call
 | ||||
| 	/// to the output stream. The values are either stored to memory or
 | ||||
| 	/// storage based on a simulated coin flip. The saved location is
 | ||||
| 	/// decided pseudo-randomly.
 | ||||
| 	/// @param _varsVec A vector of strings that reference variables
 | ||||
| 	/// holding the return values of a function call.
 | ||||
| 	void saveFunctionCallOutput(std::vector<std::string> const& _varsVec); | ||||
| 
 | ||||
| 	/// Register a function declaration
 | ||||
| 	/// @param _f Pointer to a FunctionDef object
 | ||||
| 	void registerFunction(FunctionDef const* _f); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user