mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fix literal arguments in interpreter.
This commit is contained in:
parent
3a409c39e4
commit
0226d104b7
19
test/libyul/yulInterpreterTests/long_obect_name.yul
Normal file
19
test/libyul/yulInterpreterTests/long_obect_name.yul
Normal file
@ -0,0 +1,19 @@
|
||||
object "t" {
|
||||
code {
|
||||
datacopy(not(datasize("object2.object3.object4.datablock")), 0, 0)
|
||||
}
|
||||
object "object2" {
|
||||
code{}
|
||||
object "object3" {
|
||||
code{}
|
||||
object "object4" {
|
||||
code{}
|
||||
data "datablock" ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Trace:
|
||||
// Memory dump:
|
||||
// Storage dump:
|
@ -430,28 +430,46 @@ u256 EVMInstructionInterpreter::eval(
|
||||
return 0;
|
||||
}
|
||||
|
||||
u256 EVMInstructionInterpreter::evalBuiltin(BuiltinFunctionForEVM const& _fun, const std::vector<u256>& _arguments)
|
||||
u256 EVMInstructionInterpreter::evalBuiltin(
|
||||
BuiltinFunctionForEVM const& _fun,
|
||||
vector<Expression> const& _arguments,
|
||||
vector<u256> const& _evaluatedArguments
|
||||
)
|
||||
{
|
||||
if (_fun.instruction)
|
||||
return eval(*_fun.instruction, _arguments);
|
||||
else if (_fun.name == "datasize"_yulstring)
|
||||
return u256(keccak256(h256(_arguments.at(0)))) & 0xfff;
|
||||
else if (_fun.name == "dataoffset"_yulstring)
|
||||
return u256(keccak256(h256(_arguments.at(0) + 2))) & 0xfff;
|
||||
else if (_fun.name == "datacopy"_yulstring)
|
||||
return eval(*_fun.instruction, _evaluatedArguments);
|
||||
|
||||
string fun = _fun.name.str();
|
||||
// Evaluate datasize/offset/copy instructions
|
||||
if (fun == "datasize" || fun == "dataoffset")
|
||||
{
|
||||
string arg = std::get<Literal>(_arguments.at(0)).value.str();
|
||||
if (arg.length() < 32)
|
||||
arg.resize(32, 0);
|
||||
if (fun == "datasize")
|
||||
return u256(keccak256(arg)) & 0xfff;
|
||||
else
|
||||
{
|
||||
// Force different value than for datasize
|
||||
arg[31] += 2;
|
||||
return u256(keccak256(arg)) & 0xfff;
|
||||
}
|
||||
}
|
||||
else if (fun == "datacopy")
|
||||
{
|
||||
// This is identical to codecopy.
|
||||
if (accessMemory(_arguments.at(0), _arguments.at(2)))
|
||||
if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2)))
|
||||
copyZeroExtended(
|
||||
m_state.memory,
|
||||
m_state.code,
|
||||
size_t(_arguments.at(0)),
|
||||
size_t(_arguments.at(1) & numeric_limits<size_t>::max()),
|
||||
size_t(_arguments.at(2))
|
||||
size_t(_evaluatedArguments.at(0)),
|
||||
size_t(_evaluatedArguments.at(1) & numeric_limits<size_t>::max()),
|
||||
size_t(_evaluatedArguments.at(2))
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
yulAssert(false, "Unknown builtin: " + _fun.name.str());
|
||||
yulAssert(false, "Unknown builtin: " + fun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,11 @@ public:
|
||||
/// Evaluate instruction
|
||||
u256 eval(evmasm::Instruction _instruction, std::vector<u256> const& _arguments);
|
||||
/// Evaluate builtin function
|
||||
u256 evalBuiltin(BuiltinFunctionForEVM const& _fun, std::vector<u256> const& _arguments);
|
||||
u256 evalBuiltin(
|
||||
BuiltinFunctionForEVM const& _fun,
|
||||
std::vector<Expression> const& _arguments,
|
||||
std::vector<u256> const& _evaluatedArguments
|
||||
);
|
||||
|
||||
private:
|
||||
/// Checks if the memory access is not too large for the interpreter and adjusts
|
||||
|
@ -116,27 +116,40 @@ uint64_t popcnt(uint64_t _v)
|
||||
|
||||
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
|
||||
|
||||
u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _arguments)
|
||||
u256 EwasmBuiltinInterpreter::evalBuiltin(
|
||||
YulString _functionName,
|
||||
vector<Expression> const& _arguments,
|
||||
vector<u256> const& _evaluatedArguments
|
||||
)
|
||||
{
|
||||
vector<uint64_t> arg;
|
||||
for (u256 const& a: _arguments)
|
||||
for (u256 const& a: _evaluatedArguments)
|
||||
arg.emplace_back(uint64_t(a & uint64_t(-1)));
|
||||
|
||||
string fun = _fun.str();
|
||||
if (fun == "datasize")
|
||||
return u256(keccak256(h256(_arguments.at(0)))) & 0xfff;
|
||||
else if (fun == "dataoffset")
|
||||
return u256(keccak256(h256(_arguments.at(0) + 2))) & 0xfff;
|
||||
string const fun = _functionName.str();
|
||||
if (fun == "datasize" || fun == "dataoffset")
|
||||
{
|
||||
string arg = std::get<Literal>(_arguments.at(0)).value.str();
|
||||
if (arg.length() < 32)
|
||||
arg.resize(32, 0);
|
||||
if (fun == "datasize")
|
||||
return u256(util::keccak256(arg)) & 0xfff;
|
||||
else if (fun == "dataoffset")
|
||||
{
|
||||
arg[31] += 2;
|
||||
return u256(util::keccak256(arg)) & 0xfff;
|
||||
}
|
||||
}
|
||||
else if (fun == "datacopy")
|
||||
{
|
||||
// This is identical to codecopy.
|
||||
if (accessMemory(_arguments.at(0), _arguments.at(2)))
|
||||
if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2)))
|
||||
copyZeroExtended(
|
||||
m_state.memory,
|
||||
m_state.code,
|
||||
static_cast<size_t>(_arguments.at(0)),
|
||||
static_cast<size_t>(_arguments.at(1) & numeric_limits<size_t>::max()),
|
||||
static_cast<size_t>(_arguments.at(2))
|
||||
static_cast<size_t>(_evaluatedArguments.at(0)),
|
||||
static_cast<size_t>(_evaluatedArguments.at(1) & numeric_limits<size_t>::max()),
|
||||
static_cast<size_t>(_evaluatedArguments.at(2))
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
@ -180,14 +193,14 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
accessMemory(arg[0], 4);
|
||||
return readMemoryHalfWord(arg[0]);
|
||||
}
|
||||
else if (_fun == "i32.clz"_yulstring)
|
||||
else if (fun == "i32.clz")
|
||||
// NOTE: the clz implementation assumes 64-bit inputs, hence the adjustment
|
||||
return clz64(arg[0] & uint32_t(-1)) - 32;
|
||||
else if (_fun == "i64.clz"_yulstring)
|
||||
else if (fun == "i64.clz")
|
||||
return clz64(arg[0]);
|
||||
else if (_fun == "i32.ctz"_yulstring)
|
||||
else if (fun == "i32.ctz")
|
||||
return ctz32(uint32_t(arg[0] & uint32_t(-1)));
|
||||
else if (_fun == "i64.ctz"_yulstring)
|
||||
else if (fun == "i64.ctz")
|
||||
return ctz64(arg[0]);
|
||||
|
||||
string prefix = fun;
|
||||
@ -211,7 +224,7 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
else if (prefix == "eth")
|
||||
return evalEthBuiltin(suffix, arg);
|
||||
|
||||
yulAssert(false, "Unknown builtin: " + _fun.str() + " (or implementation did not return)");
|
||||
yulAssert(false, "Unknown builtin: " + fun + " (or implementation did not return)");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,7 +69,11 @@ public:
|
||||
m_state(_state)
|
||||
{}
|
||||
/// Evaluate builtin function
|
||||
u256 evalBuiltin(YulString _fun, std::vector<u256> const& _arguments);
|
||||
u256 evalBuiltin(
|
||||
YulString _functionName,
|
||||
std::vector<Expression> const& _arguments,
|
||||
std::vector<u256> const& _evaluatedArguments
|
||||
);
|
||||
|
||||
private:
|
||||
template <typename Word>
|
||||
|
@ -261,14 +261,18 @@ void ExpressionEvaluator::operator()(Identifier const& _identifier)
|
||||
|
||||
void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
|
||||
{
|
||||
evaluateArgs(_funCall.arguments);
|
||||
vector<optional<LiteralKind>> const* literalArguments = nullptr;
|
||||
if (BuiltinFunction const* builtin = m_dialect.builtin(_funCall.functionName.name))
|
||||
if (!builtin->literalArguments.empty())
|
||||
literalArguments = &builtin->literalArguments;
|
||||
evaluateArgs(_funCall.arguments, literalArguments);
|
||||
|
||||
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
|
||||
{
|
||||
if (BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name))
|
||||
{
|
||||
EVMInstructionInterpreter interpreter(m_state);
|
||||
setValue(interpreter.evalBuiltin(*fun, values()));
|
||||
setValue(interpreter.evalBuiltin(*fun, _funCall.arguments, values()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -276,7 +280,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
|
||||
if (dialect->builtin(_funCall.functionName.name))
|
||||
{
|
||||
EwasmBuiltinInterpreter interpreter(m_state);
|
||||
setValue(interpreter.evalBuiltin(_funCall.functionName.name, values()));
|
||||
setValue(interpreter.evalBuiltin(_funCall.functionName.name, _funCall.arguments, values()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -317,14 +321,22 @@ void ExpressionEvaluator::setValue(u256 _value)
|
||||
m_values.emplace_back(std::move(_value));
|
||||
}
|
||||
|
||||
void ExpressionEvaluator::evaluateArgs(vector<Expression> const& _expr)
|
||||
void ExpressionEvaluator::evaluateArgs(
|
||||
vector<Expression> const& _expr,
|
||||
vector<optional<LiteralKind>> const* _literalArguments
|
||||
)
|
||||
{
|
||||
vector<u256> values;
|
||||
size_t i = 0;
|
||||
/// Function arguments are evaluated in reverse.
|
||||
for (auto const& expr: _expr | boost::adaptors::reversed)
|
||||
{
|
||||
visit(expr);
|
||||
if (!_literalArguments || !_literalArguments->at(_expr.size() - i - 1))
|
||||
visit(expr);
|
||||
else
|
||||
m_values = {0};
|
||||
values.push_back(value());
|
||||
++i;
|
||||
}
|
||||
m_values = std::move(values);
|
||||
std::reverse(m_values.begin(), m_values.end());
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libyul/AsmDataForward.h>
|
||||
#include <libyul/AsmData.h>
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
|
||||
#include <libsolutil/FixedHash.h>
|
||||
@ -197,7 +197,10 @@ private:
|
||||
|
||||
/// Evaluates the given expression from right to left and
|
||||
/// stores it in m_value.
|
||||
void evaluateArgs(std::vector<Expression> const& _expr);
|
||||
void evaluateArgs(
|
||||
std::vector<Expression> const& _expr,
|
||||
std::vector<std::optional<LiteralKind>> const* _literalArguments
|
||||
);
|
||||
|
||||
InterpreterState& m_state;
|
||||
Dialect const& m_dialect;
|
||||
|
Loading…
Reference in New Issue
Block a user