Merge pull request #12773 from ethereum/encodeCallBug

Fix encodeCall bug.
This commit is contained in:
chriseth 2022-03-15 10:52:13 +01:00 committed by GitHub
commit c6ac1625bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 9 deletions

View File

@ -1,5 +1,9 @@
### 0.8.13 (unreleased)
Important Bugfixes:
* Code Generator: Correctly encode literals used in ``abi.encodeCall`` in place of fixed bytes arguments.
Language Features:
* General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
* General: ``using M for Type;`` is allowed at file level and ``M`` can now also be a brace-enclosed list of free functions or library functions.

View File

@ -1,4 +1,15 @@
[
{
"uid": "SOL-2022-1",
"name": "AbiEncodeCallLiteralAsFixedBytesBug",
"summary": "Literals used for a fixed length bytes parameter in ``abi.encodeCall`` were encoded incorrectly.",
"description": "For the encoding, the compiler only considered the types of the expressions in the second argument of ``abi.encodeCall`` itself, but not the parameter types of the function given as first argument. In almost all cases the abi encoding of the type of the expression matches the abi encoding of the parameter type of the given function. This is because the type checker ensures the expression is implicitly convertible to the respective parameter type. However this is not true for number literals used for fixed bytes types shorter than 32 bytes, nor for string literals used for any fixed bytes type. Number literals were encoded as numbers instead of being shifted to become left-aligned. String literals were encoded as dynamically sized memory strings instead of being converted to a left-aligned bytes value.",
"link": "https://blog.soliditylang.org/2022/03/16/encodecall-bug/",
"introduced": "0.8.11",
"fixed": "0.8.13",
"severity": "very low"
},
{
"uid": "SOL-2021-4",
"name": "UserDefinedValueTypesBug",
@ -8,7 +19,6 @@
"introduced": "0.8.8",
"fixed": "0.8.9",
"severity": "very low"
},
{
"uid": "SOL-2021-3",

View File

@ -1549,11 +1549,15 @@
"released": "2021-11-09"
},
"0.8.11": {
"bugs": [],
"bugs": [
"AbiEncodeCallLiteralAsFixedBytesBug"
],
"released": "2021-12-20"
},
"0.8.12": {
"bugs": [],
"bugs": [
"AbiEncodeCallLiteralAsFixedBytesBug"
],
"released": "2022-02-16"
},
"0.8.2": {

View File

@ -1258,6 +1258,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
function.kind() == FunctionType::Kind::ABIEncodeWithSignature;
TypePointers argumentTypes;
TypePointers targetTypes;
ASTNode::listAccept(arguments, *this);
@ -1265,14 +1266,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
solAssert(arguments.size() == 2);
auto const functionPtr = dynamic_cast<FunctionTypePointer>(arguments[0]->annotation().type);
solAssert(functionPtr);
// Account for tuples with one component which become that component
if (auto const tupleType = dynamic_cast<TupleType const*>(arguments[1]->annotation().type))
argumentTypes = tupleType->components();
else
argumentTypes.emplace_back(arguments[1]->annotation().type);
auto functionPtr = dynamic_cast<FunctionTypePointer>(arguments[0]->annotation().type);
solAssert(functionPtr);
functionPtr = functionPtr->asExternallyCallableFunction(false);
solAssert(functionPtr);
targetTypes = functionPtr->parameterTypes();
}
else
for (unsigned i = 0; i < arguments.size(); ++i)
@ -1292,12 +1296,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
if (isPacked)
{
solAssert(!function.padArguments(), "");
utils().packedEncode(argumentTypes, TypePointers());
utils().packedEncode(argumentTypes, targetTypes);
}
else
{
solAssert(function.padArguments(), "");
utils().abiEncode(argumentTypes, TypePointers());
utils().abiEncode(argumentTypes, targetTypes);
}
utils().fetchFreeMemoryPointer();
// stack: [<selector/functionPointer/signature>] <data_encoding_area_end> <bytes_memory_ptr>

View File

@ -1160,10 +1160,22 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
for (auto const& argument: argumentsOfEncodeFunction)
{
argumentTypes.emplace_back(&type(*argument));
targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked));
argumentVars += IRVariable(*argument).stackSlots();
}
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
{
auto encodedFunctionType = dynamic_cast<FunctionType const*>(arguments.front()->annotation().type);
solAssert(encodedFunctionType);
encodedFunctionType = encodedFunctionType->asExternallyCallableFunction(false);
solAssert(encodedFunctionType);
targetTypes = encodedFunctionType->parameterTypes();
}
else
for (auto const& argument: argumentsOfEncodeFunction)
targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked));
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
{
auto const& selectorType = dynamic_cast<FunctionType const&>(type(*arguments.front()));

View File

@ -0,0 +1,21 @@
contract C {
function removeSignature(bytes calldata x) external pure returns (bytes memory) {
return x[4:];
}
function g(bytes2, bytes2, bytes2) public {}
function h(uint16, uint16) public {}
function f() public returns (bytes memory) {
uint16 x = 0x1234;
return this.removeSignature(abi.encodeCall(this.g, (0x1234, "ab", bytes2(x))));
}
function f2() public returns (bytes memory) {
bytes2 x = 0x1234;
return this.removeSignature(abi.encodeCall(this.h, (0x1234, uint16(x))));
}
}
// ====
// compileViaYul: also
// EVMVersion: >homestead
// ----
// f() -> 0x20, 0x60, 0x1234000000000000000000000000000000000000000000000000000000000000, 0x6162000000000000000000000000000000000000000000000000000000000000, 0x1234000000000000000000000000000000000000000000000000000000000000
// f2() -> 0x20, 0x40, 0x1234, 0x1234