Skip to content

Commit 8cb01a9

Browse files
committed
Fix and updated test.
1 parent db27051 commit 8cb01a9

File tree

6 files changed

+50
-17
lines changed

6 files changed

+50
-17
lines changed

Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
### 0.8.13 (unreleased)
22

3+
Important Bugfixes:
4+
* Code Generator: Correctly encode literals used in ``abi.encodeCall`` in place of fixed bytes arguments.
5+
6+
37
Language Features:
48
* General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
59
* 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.

docs/bugs.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
[
2+
{
3+
"uid": "SOL-2022-1",
4+
"name": "AbiEncodeCallLiteralAsFixedBytesBug",
5+
"summary": "Literals used for a fixed length bytes parameter in ``abi.encodeCall`` were encoded incorrectly.",
6+
"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.",
7+
"link": "https://blog.soliditylang.org/2022/03/16/encodecall-bug/",
8+
"introduced": "0.8.11",
9+
"fixed": "0.8.13",
10+
"severity": "very low"
11+
12+
},
213
{
314
"uid": "SOL-2021-4",
415
"name": "UserDefinedValueTypesBug",
@@ -8,7 +19,6 @@
819
"introduced": "0.8.8",
920
"fixed": "0.8.9",
1021
"severity": "very low"
11-
1222
},
1323
{
1424
"uid": "SOL-2021-3",

docs/bugs_by_version.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,11 +1549,15 @@
15491549
"released": "2021-11-09"
15501550
},
15511551
"0.8.11": {
1552-
"bugs": [],
1552+
"bugs": [
1553+
"AbiEncodeCallLiteralAsFixedBytesBug"
1554+
],
15531555
"released": "2021-12-20"
15541556
},
15551557
"0.8.12": {
1556-
"bugs": [],
1558+
"bugs": [
1559+
"AbiEncodeCallLiteralAsFixedBytesBug"
1560+
],
15571561
"released": "2022-02-16"
15581562
},
15591563
"0.8.2": {

libsolidity/codegen/ExpressionCompiler.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,21 +1258,25 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
12581258
function.kind() == FunctionType::Kind::ABIEncodeWithSignature;
12591259

12601260
TypePointers argumentTypes;
1261+
TypePointers targetTypes;
12611262

12621263
ASTNode::listAccept(arguments, *this);
12631264

12641265
if (function.kind() == FunctionType::Kind::ABIEncodeCall)
12651266
{
12661267
solAssert(arguments.size() == 2);
12671268

1268-
auto const functionPtr = dynamic_cast<FunctionTypePointer>(arguments[0]->annotation().type);
1269-
solAssert(functionPtr);
1270-
12711269
// Account for tuples with one component which become that component
12721270
if (auto const tupleType = dynamic_cast<TupleType const*>(arguments[1]->annotation().type))
12731271
argumentTypes = tupleType->components();
12741272
else
12751273
argumentTypes.emplace_back(arguments[1]->annotation().type);
1274+
1275+
auto functionPtr = dynamic_cast<FunctionTypePointer>(arguments[0]->annotation().type);
1276+
solAssert(functionPtr);
1277+
functionPtr = functionPtr->asExternallyCallableFunction(false);
1278+
solAssert(functionPtr);
1279+
targetTypes = functionPtr->parameterTypes();
12761280
}
12771281
else
12781282
for (unsigned i = 0; i < arguments.size(); ++i)
@@ -1292,12 +1296,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
12921296
if (isPacked)
12931297
{
12941298
solAssert(!function.padArguments(), "");
1295-
utils().packedEncode(argumentTypes, TypePointers());
1299+
utils().packedEncode(argumentTypes, targetTypes);
12961300
}
12971301
else
12981302
{
12991303
solAssert(function.padArguments(), "");
1300-
utils().abiEncode(argumentTypes, TypePointers());
1304+
utils().abiEncode(argumentTypes, targetTypes);
13011305
}
13021306
utils().fetchFreeMemoryPointer();
13031307
// stack: [<selector/functionPointer/signature>] <data_encoding_area_end> <bytes_memory_ptr>

libsolidity/codegen/ir/IRGeneratorForStatements.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,10 +1160,22 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
11601160
for (auto const& argument: argumentsOfEncodeFunction)
11611161
{
11621162
argumentTypes.emplace_back(&type(*argument));
1163-
targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked));
11641163
argumentVars += IRVariable(*argument).stackSlots();
11651164
}
11661165

1166+
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
1167+
{
1168+
auto encodedFunctionType = dynamic_cast<FunctionType const*>(arguments.front()->annotation().type);
1169+
solAssert(encodedFunctionType);
1170+
encodedFunctionType = encodedFunctionType->asExternallyCallableFunction(false);
1171+
solAssert(encodedFunctionType);
1172+
targetTypes = encodedFunctionType->parameterTypes();
1173+
}
1174+
else
1175+
for (auto const& argument: argumentsOfEncodeFunction)
1176+
targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked));
1177+
1178+
11671179
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
11681180
{
11691181
auto const& selectorType = dynamic_cast<FunctionType const&>(type(*arguments.front()));
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
contract C {
2-
function removeSignature(bytes memory x) internal pure returns (bytes memory r) {
3-
r = new bytes(x.length - 4);
4-
for (uint i = 0; i < x.length - 4; ++i)
5-
r[i] = x[i + 4];
2+
function removeSignature(bytes calldata x) external pure returns (bytes memory) {
3+
return x[4:];
64
}
7-
function g(bytes2, bytes2) public {}
5+
function g(bytes2, bytes2, bytes2) public {}
86
function h(uint16, uint16) public {}
97
function f() public returns (bytes memory) {
108
uint16 x = 0x1234;
11-
return removeSignature(abi.encodeCall(this.g, (0x1234, bytes2(x))));
9+
return this.removeSignature(abi.encodeCall(this.g, (0x1234, "ab", bytes2(x))));
1210
}
1311
function f2() public returns (bytes memory) {
1412
bytes2 x = 0x1234;
15-
return removeSignature(abi.encodeCall(this.h, (0x1234, uint16(x))));
13+
return this.removeSignature(abi.encodeCall(this.h, (0x1234, uint16(x))));
1614
}
1715
}
1816
// ====
1917
// compileViaYul: also
18+
// EVMVersion: >homestead
2019
// ----
21-
// f() -> 0x20, 0x40, 0x1234, 0x1234000000000000000000000000000000000000000000000000000000000000
20+
// f() -> 0x20, 0x60, 0x1234000000000000000000000000000000000000000000000000000000000000, 0x6162000000000000000000000000000000000000000000000000000000000000, 0x1234000000000000000000000000000000000000000000000000000000000000
2221
// f2() -> 0x20, 0x40, 0x1234, 0x1234

0 commit comments

Comments
 (0)