From 3a617f9cf27e81044914726a0f3576ca95611578 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 4 Aug 2020 16:37:36 +0100 Subject: [PATCH] Validate expected literal kind for yul::Dialect builtins Co-authored-by: Daniel Kirchner --- Changelog.md | 2 +- libyul/AsmAnalysis.cpp | 56 ++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Changelog.md b/Changelog.md index 28a1eff05..5b2babfa1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,7 @@ Language Features: Compiler Features: - + * Yul: Report error when using non-string literals for ``datasize()``, ``dataoffset()``, ``linkersymbol()``, ``loadimmutable()``, ``setimmutable()``. Bugfixes: * Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though. diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 428861472..bf968d950 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -44,6 +44,20 @@ using namespace solidity::yul; using namespace solidity::util; using namespace solidity::langutil; +namespace +{ +inline string to_string(LiteralKind _kind) +{ + switch (_kind) + { + case LiteralKind::Number: return "number"; + case LiteralKind::Boolean: return "boolean"; + case LiteralKind::String: return "string"; + default: yulAssert(false, ""); + } +} +} + bool AsmAnalyzer::analyze(Block const& _block) { auto watcher = m_errorReporter.errorWatcher(); @@ -318,15 +332,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) for (size_t i = _funCall.arguments.size(); i > 0; i--) { Expression const& arg = _funCall.arguments[i - 1]; - bool isLiteralArgument = literalArguments && (*literalArguments)[i - 1].has_value(); - bool isStringLiteral = holds_alternative(arg) && get(arg).kind == LiteralKind::String; - - if (isLiteralArgument && isStringLiteral) - argTypes.emplace_back(expectUnlimitedStringLiteral(get(arg))); - else - argTypes.emplace_back(expectExpression(arg)); - - if (isLiteralArgument) + if (auto literalArgumentKind = literalArguments ? literalArguments->at(i - 1) : std::nullopt) { if (!holds_alternative(arg)) m_errorReporter.typeError( @@ -334,17 +340,29 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) _funCall.functionName.location, "Function expects direct literals as arguments." ); - else if ( - _funCall.functionName.name.str() == "datasize" || - _funCall.functionName.name.str() == "dataoffset" - ) - if (!m_dataNames.count(std::get(arg).value)) - m_errorReporter.typeError( - 3517_error, - _funCall.functionName.location, - "Unknown data object \"" + std::get(arg).value.str() + "\"." - ); + else if (*literalArgumentKind != get(arg).kind) + m_errorReporter.typeError( + 5859_error, + get(arg).location, + "Function expects " + to_string(*literalArgumentKind) + " literal." + ); + else if (*literalArgumentKind == LiteralKind::String) + { + if ( + _funCall.functionName.name.str() == "datasize" || + _funCall.functionName.name.str() == "dataoffset" + ) + if (!m_dataNames.count(get(arg).value)) + m_errorReporter.typeError( + 3517_error, + get(arg).location, + "Unknown data object \"" + std::get(arg).value.str() + "\"." + ); + argTypes.emplace_back(expectUnlimitedStringLiteral(get(arg))); + continue; + } } + argTypes.emplace_back(expectExpression(arg)); } std::reverse(argTypes.begin(), argTypes.end());