Check availability of data objects already in analysis phase.

This commit is contained in:
chriseth 2019-07-09 14:06:33 +02:00
parent f3bdc79187
commit 2a5280faa0
7 changed files with 72 additions and 27 deletions

View File

@ -18,6 +18,7 @@ Compiler Features:
Bugfixes:
* View/Pure Checker: Properly detect state variable access through base class.
* Yul analyzer: Check availability of data objects already in analysis phase.

View File

@ -383,11 +383,19 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall)
{
if (!expectExpression(arg))
success = false;
else if (needsLiteralArguments && arg.type() != typeid(Literal))
m_errorReporter.typeError(
_funCall.functionName.location,
"Function expects direct literals as arguments."
);
else if (needsLiteralArguments)
{
if (arg.type() != typeid(Literal))
m_errorReporter.typeError(
_funCall.functionName.location,
"Function expects direct literals as arguments."
);
else if (!m_dataNames.count(boost::get<Literal>(arg).value))
m_errorReporter.typeError(
_funCall.functionName.location,
"Unknown data object \"" + boost::get<Literal>(arg).value.str() + "\"."
);
}
}
// Use argument size instead of parameter count to avoid misleading errors.
m_stackHeight += int(returns) - int(_funCall.arguments.size());

View File

@ -61,13 +61,15 @@ public:
langutil::ErrorReporter& _errorReporter,
boost::optional<langutil::Error::Type> _errorTypeForLoose,
Dialect const& _dialect,
ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver()
ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver(),
std::set<YulString> const& _dataNames = {}
):
m_resolver(_resolver),
m_info(_analysisInfo),
m_errorReporter(_errorReporter),
m_dialect(_dialect),
m_errorTypeForLoose(_errorTypeForLoose)
m_errorTypeForLoose(_errorTypeForLoose),
m_dataNames(_dataNames)
{
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect))
m_evmVersion = evmDialect->evmVersion();
@ -124,6 +126,8 @@ private:
langutil::EVMVersion m_evmVersion;
Dialect const& m_dialect;
boost::optional<langutil::Error::Type> m_errorTypeForLoose;
/// Names of data objects to be referenced by builtin functions with literal arguments.
std::set<YulString> m_dataNames;
ForLoop const* m_currentForLoop = nullptr;
};

View File

@ -113,7 +113,20 @@ bool AssemblyStack::analyzeParsed(Object& _object)
{
solAssert(_object.code, "");
_object.analysisInfo = make_shared<AsmAnalysisInfo>();
AsmAnalyzer analyzer(*_object.analysisInfo, m_errorReporter, boost::none, languageToDialect(m_language, m_evmVersion));
set<YulString> objectNames;
objectNames.insert(_object.name);
for (auto const& subObject: _object.subIndexByName)
objectNames.insert(subObject.first);
AsmAnalyzer analyzer(
*_object.analysisInfo,
m_errorReporter,
boost::none,
languageToDialect(m_language, m_evmVersion),
{},
objectNames
);
bool success = analyzer.analyze(*_object.code);
for (auto& subNode: _object.subObjects)
if (auto subObject = dynamic_cast<Object*>(subNode.get()))

View File

@ -278,6 +278,19 @@ BOOST_AUTO_TEST_CASE(args_to_datacopy_are_arbitrary)
BOOST_CHECK(successParse(code));
}
BOOST_AUTO_TEST_CASE(non_existing_objects)
{
BOOST_CHECK(successParse(
"object \"main\" { code { pop(datasize(\"main\")) } }"
));
CHECK_ERROR(
"object \"main\" { code { pop(datasize(\"abc\")) } }",
TypeError,
"Unknown data object"
);
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -1,15 +1,18 @@
{
// Arguments to ``datasize`` and ``dataoffset`` need to be
// literals. We cannot simplify their arguments, but we can
// simplify them as a full expression.
// ``datacopy`` does not have this restriction.
let r := "abc"
let a := datasize("abc")
let x := dataoffset("abc")
// should be replaced by a
let y := datasize("abc")
datacopy("abc", x, y)
mstore(a, x)
object "main" {
code {
// Arguments to ``datasize`` and ``dataoffset`` need to be
// literals. We cannot simplify their arguments, but we can
// simplify them as a full expression.
// ``datacopy`` does not have this restriction.
let r := "abc"
let a := datasize("abc")
let x := dataoffset("abc")
// should be replaced by a
let y := datasize("abc")
datacopy("abc", x, y)
mstore(a, x)
}
data "abc" "Hello, World!"
}
// ====
// step: commonSubexpressionEliminator

View File

@ -1,10 +1,13 @@
{
// We should never split arguments to ``dataoffset``
// or ``datasize`` because they need to be literals
let x := dataoffset("abc")
let y := datasize("abc")
// datacopy is fine, though
datacopy(mload(0), mload(1), mload(2))
object "main" {
code {
// We should never split arguments to ``dataoffset``
// or ``datasize`` because they need to be literals
let x := dataoffset("abc")
let y := datasize("abc")
// datacopy is fine, though
datacopy(mload(0), mload(1), mload(2))
}
data "abc" "Hello, World!"
}
// ====
// step: expressionSplitter