From aba0b2957c48c87166ccb7cbbe03a48cc9cf2d0d Mon Sep 17 00:00:00 2001 From: a3d4 Date: Sun, 5 Apr 2020 04:04:08 +0200 Subject: [PATCH] Fix tuple assignments with multi-slot components. --- Changelog.md | 3 + docs/bugs.json | 8 +++ docs/bugs_by_version.json | 66 ++++++++++++++++++- libsolidity/codegen/CompilerUtils.cpp | 4 +- .../{tuple_in_tuple.sol => nested_tuples.sol} | 0 .../types/nested_tuples_noyul.sol | 17 +++++ .../types/tuple_assign_multi_slot_grow.sol | 13 ++++ 7 files changed, 108 insertions(+), 3 deletions(-) rename test/libsolidity/semanticTests/types/{tuple_in_tuple.sol => nested_tuples.sol} (100%) create mode 100644 test/libsolidity/semanticTests/types/nested_tuples_noyul.sol create mode 100644 test/libsolidity/semanticTests/types/tuple_assign_multi_slot_grow.sol diff --git a/Changelog.md b/Changelog.md index 828d86ed4..34b230822 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,8 @@ ### 0.6.6 (unreleased) +Important Bugfixes: + * Fix tuple assignments with components occupying multiple stack slots and different stack size on left- and right-hand-side. + Language Features: diff --git a/docs/bugs.json b/docs/bugs.json index 066e17e93..42a5277b1 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "TupleAssignmentMultiStackSlotComponents", + "summary": "Tuple assignments with components that occupy several stack slots, i.e. nested tuples, pointers to external functions or references to dynamically sized calldata arrays, can result in invalid values.", + "description": "Tuple assignments did not correctly account for tuple components that occupy multiple stack slots in case the number of stack slots differs between left-hand-side and right-hand-side. This can either happen in the presence of nested tuples or if the right-hand-side contains external function pointers or references to dynamic calldata arrays, while the left-hand-side contains an omission.", + "introduced": "0.1.6", + "fixed": "0.6.6", + "severity": "very low" + }, { "name": "MemoryArrayCreationOverflow", "summary": "The creation of very large memory arrays can result in overlapping memory regions and thus memory corruption.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index b12393016..d5d417669 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -111,6 +111,7 @@ }, "0.1.6": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", @@ -131,6 +132,7 @@ }, "0.1.7": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", @@ -151,6 +153,7 @@ }, "0.2.0": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -172,6 +175,7 @@ }, "0.2.1": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -193,6 +197,7 @@ }, "0.2.2": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "ExpExponentCleanup", "NestedArrayFunctionCallDecoder", @@ -214,6 +219,7 @@ }, "0.3.0": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -237,6 +243,7 @@ }, "0.3.1": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -259,6 +266,7 @@ }, "0.3.2": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -281,6 +289,7 @@ }, "0.3.3": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -302,6 +311,7 @@ }, "0.3.4": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -323,6 +333,7 @@ }, "0.3.5": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -344,6 +355,7 @@ }, "0.3.6": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -363,6 +375,7 @@ }, "0.4.0": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -382,6 +395,7 @@ }, "0.4.1": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -401,6 +415,7 @@ }, "0.4.10": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -418,6 +433,7 @@ }, "0.4.11": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -434,6 +450,7 @@ }, "0.4.12": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -449,6 +466,7 @@ }, "0.4.13": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -464,6 +482,7 @@ }, "0.4.14": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -478,6 +497,7 @@ }, "0.4.15": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -491,6 +511,7 @@ }, "0.4.16": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -506,6 +527,7 @@ }, "0.4.17": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -522,6 +544,7 @@ }, "0.4.18": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -537,6 +560,7 @@ }, "0.4.19": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -553,6 +577,7 @@ }, "0.4.2": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -571,6 +596,7 @@ }, "0.4.20": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -587,6 +613,7 @@ }, "0.4.21": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -603,6 +630,7 @@ }, "0.4.22": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -619,6 +647,7 @@ }, "0.4.23": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -634,6 +663,7 @@ }, "0.4.24": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -649,6 +679,7 @@ }, "0.4.25": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -662,6 +693,7 @@ }, "0.4.26": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -672,6 +704,7 @@ }, "0.4.3": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -689,6 +722,7 @@ }, "0.4.4": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "IncorrectEventSignatureInLibraries_0.4.x", @@ -705,6 +739,7 @@ }, "0.4.5": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -723,6 +758,7 @@ }, "0.4.6": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "UninitializedFunctionPointerInConstructor_0.4.x", @@ -740,6 +776,7 @@ }, "0.4.7": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -757,6 +794,7 @@ }, "0.4.8": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -774,6 +812,7 @@ }, "0.4.9": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -791,6 +830,7 @@ }, "0.5.0": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -804,6 +844,7 @@ }, "0.5.1": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -817,6 +858,7 @@ }, "0.5.10": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", @@ -826,6 +868,7 @@ }, "0.5.11": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" @@ -834,6 +877,7 @@ }, "0.5.12": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" @@ -842,6 +886,7 @@ }, "0.5.13": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" @@ -850,6 +895,7 @@ }, "0.5.14": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", @@ -859,6 +905,7 @@ }, "0.5.15": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5" @@ -867,6 +914,7 @@ }, "0.5.16": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden" ], @@ -874,12 +922,14 @@ }, "0.5.17": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], "released": "2020-03-17" }, "0.5.2": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -893,6 +943,7 @@ }, "0.5.3": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -906,6 +957,7 @@ }, "0.5.4": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -919,6 +971,7 @@ }, "0.5.5": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "SignedArrayStorageCopy", @@ -934,6 +987,7 @@ }, "0.5.6": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", @@ -949,6 +1003,7 @@ }, "0.5.7": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers", @@ -962,6 +1017,7 @@ }, "0.5.8": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", @@ -974,6 +1030,7 @@ }, "0.5.9": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "privateCanBeOverridden", "YulOptimizerRedundantAssignmentBreakContinue0.5", @@ -985,6 +1042,7 @@ }, "0.6.0": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow", "YulOptimizerRedundantAssignmentBreakContinue" ], @@ -992,30 +1050,36 @@ }, "0.6.1": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], "released": "2020-01-02" }, "0.6.2": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], "released": "2020-01-27" }, "0.6.3": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], "released": "2020-02-18" }, "0.6.4": { "bugs": [ + "TupleAssignmentMultiStackSlotComponents", "MemoryArrayCreationOverflow" ], "released": "2020-03-10" }, "0.6.5": { - "bugs": [], + "bugs": [ + "TupleAssignmentMultiStackSlotComponents" + ], "released": "2020-04-06" } } \ No newline at end of file diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index d4f35ad79..3d0117707 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1108,12 +1108,12 @@ void CompilerUtils::convertType( // Value shrank for (unsigned j = targetSize; j < sourceSize; ++j) { - moveToStackTop(depth - 1, 1); + moveToStackTop(depth + targetSize - sourceSize, 1); m_context << Instruction::POP; } // Value grew if (targetSize > sourceSize) - moveIntoStack(depth + targetSize - sourceSize - 1, targetSize - sourceSize); + moveIntoStack(depth - sourceSize, targetSize - sourceSize); } } depth -= sourceSize; diff --git a/test/libsolidity/semanticTests/types/tuple_in_tuple.sol b/test/libsolidity/semanticTests/types/nested_tuples.sol similarity index 100% rename from test/libsolidity/semanticTests/types/tuple_in_tuple.sol rename to test/libsolidity/semanticTests/types/nested_tuples.sol diff --git a/test/libsolidity/semanticTests/types/nested_tuples_noyul.sol b/test/libsolidity/semanticTests/types/nested_tuples_noyul.sol new file mode 100644 index 000000000..1eff9e2b9 --- /dev/null +++ b/test/libsolidity/semanticTests/types/nested_tuples_noyul.sol @@ -0,0 +1,17 @@ +contract test { + function f3() public returns(int) { + int a = 3; + ((, ), ) = ((7, 8), 9); + return a; + } + function f4() public returns(int) { + int a; + (a, ) = (4, (8, 16, 32)); + return a; + } +} +// ==== +// compileViaYul: false +// ---- +// f3() -> 3 +// f4() -> 4 diff --git a/test/libsolidity/semanticTests/types/tuple_assign_multi_slot_grow.sol b/test/libsolidity/semanticTests/types/tuple_assign_multi_slot_grow.sol new file mode 100644 index 000000000..6735563b9 --- /dev/null +++ b/test/libsolidity/semanticTests/types/tuple_assign_multi_slot_grow.sol @@ -0,0 +1,13 @@ +contract C { + + function f() public pure returns (uint, uint, uint) { + bytes memory a; bytes memory b; bytes memory c; + (a, (b, c)) = ("0", ("1", "2")); + return (uint8(a[0]), uint8(b[0]), uint8(c[0])); + } + +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x30, 0x31, 0x32