diff --git a/Changelog.md b/Changelog.md index e8ccbb525302..aa6c5647b8e0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,9 @@ Language Features: +Important Bugfixes: +* Code Generator: Fix inconsistent handling of storage arrays at the slot overflow boundary, which could lead to incorrect storage cleanup when using `delete` or partial assignments of arrays. + Compiler Features: * NatSpec: Capture Natspec documentation of `enum` values in the AST. diff --git a/docs/bugs.json b/docs/bugs.json index 800524669048..b1194435658a 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,14 @@ [ + { + "uid": "SOL-2025-1", + "name": "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", + "summary": "Fixed-length storage arrays crossing the 2^256 slot boundary can exhibit unexpected behavior when cleared (using the delete operator) or partially assigned, leading to silent data retention and inconsistent results.", + "description": "Large static arrays in storage risk overlapping the 2^256 storage slot boundary. Partial assignments or delete operations may not properly reset all elements in such conditions, causing inconsistency during deletion and unexpected data retention. Although such situations are exceedingly rare in typical contracts, overflow on array deletion become more plausible when arrays are extremely large or the storage is manually positioned close to the storage boundaries. The compiler already warns about potential storage collisions in such scenarios.", + "link": "TODO", + "introduced": "0.1.1", + "fixed": "0.8.30", + "severity": "low" + }, { "uid": "SOL-2023-3", "name": "VerbatimInvalidDeduplication", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 60fcdd049a0f..14856820f688 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -23,6 +23,7 @@ }, "0.1.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -45,6 +46,7 @@ }, "0.1.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -67,6 +69,7 @@ }, "0.1.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -89,6 +92,7 @@ }, "0.1.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -112,6 +116,7 @@ }, "0.1.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -135,6 +140,7 @@ }, "0.1.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -160,6 +166,7 @@ }, "0.1.7": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -185,6 +192,7 @@ }, "0.2.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -211,6 +219,7 @@ }, "0.2.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -237,6 +246,7 @@ }, "0.2.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -263,6 +273,7 @@ }, "0.3.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -291,6 +302,7 @@ }, "0.3.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -318,6 +330,7 @@ }, "0.3.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -345,6 +358,7 @@ }, "0.3.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -371,6 +385,7 @@ }, "0.3.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -397,6 +412,7 @@ }, "0.3.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -423,6 +439,7 @@ }, "0.3.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -447,6 +464,7 @@ }, "0.4.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -471,6 +489,7 @@ }, "0.4.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -495,6 +514,7 @@ }, "0.4.10": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -518,6 +538,7 @@ }, "0.4.11": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -540,6 +561,7 @@ }, "0.4.12": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -561,6 +583,7 @@ }, "0.4.13": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -582,6 +605,7 @@ }, "0.4.14": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -602,6 +626,7 @@ }, "0.4.15": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -621,6 +646,7 @@ }, "0.4.16": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -643,6 +669,7 @@ }, "0.4.17": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -666,6 +693,7 @@ }, "0.4.18": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -688,6 +716,7 @@ }, "0.4.19": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -711,6 +740,7 @@ }, "0.4.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -734,6 +764,7 @@ }, "0.4.20": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -757,6 +788,7 @@ }, "0.4.21": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -780,6 +812,7 @@ }, "0.4.22": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -803,6 +836,7 @@ }, "0.4.23": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -825,6 +859,7 @@ }, "0.4.24": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -847,6 +882,7 @@ }, "0.4.25": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -867,6 +903,7 @@ }, "0.4.26": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -884,6 +921,7 @@ }, "0.4.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -906,6 +944,7 @@ }, "0.4.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -927,6 +966,7 @@ }, "0.4.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -951,6 +991,7 @@ }, "0.4.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -974,6 +1015,7 @@ }, "0.4.7": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -997,6 +1039,7 @@ }, "0.4.8": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -1020,6 +1063,7 @@ }, "0.4.9": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "KeccakCaching", "EmptyByteArrayCopy", @@ -1043,6 +1087,7 @@ }, "0.5.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1063,6 +1108,7 @@ }, "0.5.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1083,6 +1129,7 @@ }, "0.5.10": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1101,6 +1148,7 @@ }, "0.5.11": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1118,6 +1166,7 @@ }, "0.5.12": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1135,6 +1184,7 @@ }, "0.5.13": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1152,6 +1202,7 @@ }, "0.5.14": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1171,6 +1222,7 @@ }, "0.5.15": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1189,6 +1241,7 @@ }, "0.5.16": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1206,6 +1259,7 @@ }, "0.5.17": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1222,6 +1276,7 @@ }, "0.5.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1242,6 +1297,7 @@ }, "0.5.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1262,6 +1318,7 @@ }, "0.5.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1282,6 +1339,7 @@ }, "0.5.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1304,6 +1362,7 @@ }, "0.5.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1326,6 +1385,7 @@ }, "0.5.7": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "DirtyBytesArrayToStorage", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", @@ -1346,6 +1406,7 @@ }, "0.5.8": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1367,6 +1428,7 @@ }, "0.5.9": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1387,6 +1449,7 @@ }, "0.6.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1405,6 +1468,7 @@ }, "0.6.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", "NestedCalldataArrayAbiReencodingSizeValidation", @@ -1422,6 +1486,7 @@ }, "0.6.10": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1438,6 +1503,7 @@ }, "0.6.11": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1454,6 +1520,7 @@ }, "0.6.12": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1470,6 +1537,7 @@ }, "0.6.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", @@ -1488,6 +1556,7 @@ }, "0.6.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", @@ -1506,6 +1575,7 @@ }, "0.6.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", @@ -1524,6 +1594,7 @@ }, "0.6.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", @@ -1542,6 +1613,7 @@ }, "0.6.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", "DirtyBytesArrayToStorage", @@ -1559,6 +1631,7 @@ }, "0.6.7": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1577,6 +1650,7 @@ }, "0.6.8": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1592,6 +1666,7 @@ }, "0.6.9": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1609,6 +1684,7 @@ }, "0.7.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1625,6 +1701,7 @@ }, "0.7.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1642,6 +1719,7 @@ }, "0.7.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1658,6 +1736,7 @@ }, "0.7.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1673,6 +1752,7 @@ }, "0.7.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1687,6 +1767,7 @@ }, "0.7.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1701,6 +1782,7 @@ }, "0.7.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1715,6 +1797,7 @@ }, "0.8.0": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1729,6 +1812,7 @@ }, "0.8.1": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1743,6 +1827,7 @@ }, "0.8.10": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1755,6 +1840,7 @@ }, "0.8.11": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1768,6 +1854,7 @@ }, "0.8.12": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1781,6 +1868,7 @@ }, "0.8.13": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1795,6 +1883,7 @@ }, "0.8.14": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1807,6 +1896,7 @@ }, "0.8.15": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1817,6 +1907,7 @@ }, "0.8.16": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1826,6 +1917,7 @@ }, "0.8.17": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" @@ -1834,6 +1926,7 @@ }, "0.8.18": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" @@ -1842,6 +1935,7 @@ }, "0.8.19": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" @@ -1850,6 +1944,7 @@ }, "0.8.2": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1864,6 +1959,7 @@ }, "0.8.20": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess" @@ -1872,46 +1968,63 @@ }, "0.8.21": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication" ], "released": "2023-07-19" }, "0.8.22": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication" ], "released": "2023-10-25" }, "0.8.23": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2023-11-08" }, "0.8.24": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2024-01-25" }, "0.8.25": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2024-03-14" }, "0.8.26": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2024-05-21" }, "0.8.27": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2024-09-04" }, "0.8.28": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2024-10-09" }, "0.8.29": { - "bugs": [], + "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary" + ], "released": "2025-03-12" }, "0.8.3": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1925,6 +2038,7 @@ }, "0.8.4": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", "AbiReencodingHeadOverflowWithStaticArrayCleanup", @@ -1937,6 +2051,7 @@ }, "0.8.5": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1950,6 +2065,7 @@ }, "0.8.6": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1963,6 +2079,7 @@ }, "0.8.7": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1976,6 +2093,7 @@ }, "0.8.8": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", @@ -1990,6 +2108,7 @@ }, "0.8.9": { "bugs": [ + "InconsistentTreatmentOfStorageArraysOnSlotOverflowBoundary", "VerbatimInvalidDeduplication", "FullInlinerNonExpressionSplitArgumentEvaluationOrder", "MissingSideEffectsOnSelectorAccess", diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 455cfe0842ed..f43625c6a3e2 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -290,9 +290,27 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons _context << Instruction::POP << Instruction::SWAP1 << Instruction::POP; // stack: target_ref target_data_end target_data_pos_updated if (targetBaseType->storageBytes() < 32) - utils.clearStorageLoop(TypeProvider::uint256()); + { + if (!targetType->isDynamicallySized() && !sourceType->isDynamicallySized()) + if (auto const* targetArrayType = dynamic_cast(targetType)) + { + auto const* sourceArrayType = dynamic_cast(sourceType); + solAssert(sourceArrayType); + + auto const numSourceItemsPerSlot = 32 / sourceArrayType->baseType()->storageBytes(); + auto const paddedLength = numSourceItemsPerSlot * sourceArrayType->storageSize(); + auto const paddedTargetType = TypeProvider::array(targetArrayType->location(), targetArrayType->baseType(), paddedLength); + + if (paddedTargetType->storageSize() >= targetArrayType->storageSize()) + { + _context << Instruction::POP << Instruction::POP; + return; + } + } + utils.clearStorageLoop(TypeProvider::uint256(), !targetType->isDynamicallySized()); + } else - utils.clearStorageLoop(targetBaseType); + utils.clearStorageLoop(targetBaseType, !targetType->isDynamicallySized()); _context << Instruction::POP; } ); @@ -590,9 +608,9 @@ void ArrayUtils::clearArray(ArrayType const& _typeIn) const ArrayUtils(_context).convertLengthToSize(_type); _context << Instruction::ADD << Instruction::SWAP1; if (_type.baseType()->storageBytes() < 32) - ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256()); + ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256(), /* _canOverflow */ true); else - ArrayUtils(_context).clearStorageLoop(_type.baseType()); + ArrayUtils(_context).clearStorageLoop(_type.baseType(), /* _canOverflow */ true); _context << Instruction::POP; } solAssert(_context.stackHeight() == stackHeightStart - 2, ""); @@ -631,164 +649,14 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const << Instruction::SWAP1; // stack: data_pos_end data_pos if (_type.storageStride() < 32) - clearStorageLoop(TypeProvider::uint256()); + clearStorageLoop(TypeProvider::uint256(), /* _canOverflow */ false); else - clearStorageLoop(_type.baseType()); + clearStorageLoop(_type.baseType(), /* _canOverflow */ false); // cleanup m_context << endTag; m_context << Instruction::POP; } -void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const -{ - Type const* type = &_typeIn; - m_context.callLowLevelFunction( - "$resizeDynamicArray_" + _typeIn.identifier(), - 2, - 0, - [type](CompilerContext& _context) - { - ArrayType const& _type = dynamic_cast(*type); - solAssert(_type.location() == DataLocation::Storage, ""); - solAssert(_type.isDynamicallySized(), ""); - if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32) - solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); - - unsigned stackHeightStart = _context.stackHeight(); - evmasm::AssemblyItem resizeEnd = _context.newTag(); - - // stack: ref new_length - // fetch old length - ArrayUtils(_context).retrieveLength(_type, 1); - // stack: ref new_length old_length - solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "2"); - - // Special case for short byte arrays, they are stored together with their length - if (_type.isByteArrayOrString()) - { - evmasm::AssemblyItem regularPath = _context.newTag(); - // We start by a large case-distinction about the old and new length of the byte array. - - _context << Instruction::DUP3 << Instruction::SLOAD; - // stack: ref new_length current_length ref_value - - solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3"); - _context << Instruction::DUP2 << u256(31) << Instruction::LT; - evmasm::AssemblyItem currentIsLong = _context.appendConditionalJump(); - _context << Instruction::DUP3 << u256(31) << Instruction::LT; - evmasm::AssemblyItem newIsLong = _context.appendConditionalJump(); - - // Here: short -> short - - // Compute 1 << (256 - 8 * new_size) - evmasm::AssemblyItem shortToShort = _context.newTag(); - _context << shortToShort; - _context << Instruction::DUP3 << u256(8) << Instruction::MUL; - _context << u256(0x100) << Instruction::SUB; - _context << u256(2) << Instruction::EXP; - // Divide and multiply by that value, clearing bits. - _context << Instruction::DUP1 << Instruction::SWAP2; - _context << Instruction::DIV << Instruction::MUL; - // Insert 2*length. - _context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD; - _context << Instruction::OR; - // Store. - _context << Instruction::DUP4 << Instruction::SSTORE; - solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "3"); - _context.appendJumpTo(resizeEnd); - - _context.adjustStackOffset(1); // we have to do that because of the jumps - // Here: short -> long - - _context << newIsLong; - // stack: ref new_length current_length ref_value - solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3"); - // Zero out lower-order byte. - _context << u256(0xff) << Instruction::NOT << Instruction::AND; - // Store at data location. - _context << Instruction::DUP4; - CompilerUtils(_context).computeHashStatic(); - _context << Instruction::SSTORE; - // stack: ref new_length current_length - // Store new length: Compute 2*length + 1 and store it. - _context << Instruction::DUP2 << Instruction::DUP1 << Instruction::ADD; - _context << u256(1) << Instruction::ADD; - // stack: ref new_length current_length 2*new_length+1 - _context << Instruction::DUP4 << Instruction::SSTORE; - solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "3"); - _context.appendJumpTo(resizeEnd); - - _context.adjustStackOffset(1); // we have to do that because of the jumps - - _context << currentIsLong; - _context << Instruction::DUP3 << u256(31) << Instruction::LT; - _context.appendConditionalJumpTo(regularPath); - - // Here: long -> short - // Read the first word of the data and store it on the stack. Clear the data location and - // then jump to the short -> short case. - - // stack: ref new_length current_length ref_value - solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3"); - _context << Instruction::POP << Instruction::DUP3; - CompilerUtils(_context).computeHashStatic(); - _context << Instruction::DUP1 << Instruction::SLOAD << Instruction::SWAP1; - // stack: ref new_length current_length first_word data_location - _context << Instruction::DUP3; - ArrayUtils(_context).convertLengthToSize(_type); - _context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1; - // stack: ref new_length current_length first_word data_location_end data_location - ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256()); - _context << Instruction::POP; - // stack: ref new_length current_length first_word - solAssert(_context.stackHeight() - stackHeightStart == 4 - 2, "3"); - _context.appendJumpTo(shortToShort); - - _context << regularPath; - // stack: ref new_length current_length ref_value - _context << Instruction::POP; - } - - // Change of length for a regular array (i.e. length at location, data at KECCAK256(location)). - // stack: ref new_length old_length - // store new length - _context << Instruction::DUP2; - if (_type.isByteArrayOrString()) - // For a "long" byte array, store length as 2*length+1 - _context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD; - _context << Instruction::DUP4 << Instruction::SSTORE; - // skip if size is not reduced - _context << Instruction::DUP2 << Instruction::DUP2 - << Instruction::GT << Instruction::ISZERO; - _context.appendConditionalJumpTo(resizeEnd); - - // size reduced, clear the end of the array - // stack: ref new_length old_length - ArrayUtils(_context).convertLengthToSize(_type); - _context << Instruction::DUP2; - ArrayUtils(_context).convertLengthToSize(_type); - // stack: ref new_length old_size new_size - // compute data positions - _context << Instruction::DUP4; - CompilerUtils(_context).computeHashStatic(); - // stack: ref new_length old_size new_size data_pos - _context << Instruction::SWAP2 << Instruction::DUP3 << Instruction::ADD; - // stack: ref new_length data_pos new_size delete_end - _context << Instruction::SWAP2 << Instruction::ADD; - // stack: ref new_length delete_end delete_start - if (_type.storageStride() < 32) - ArrayUtils(_context).clearStorageLoop(TypeProvider::uint256()); - else - ArrayUtils(_context).clearStorageLoop(_type.baseType()); - - _context << resizeEnd; - // cleanup - _context << Instruction::POP << Instruction::POP << Instruction::POP; - solAssert(_context.stackHeight() == stackHeightStart - 2, ""); - } - ); -} - void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const { solAssert(_type.location() == DataLocation::Storage, ""); @@ -921,14 +789,14 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const } } -void ArrayUtils::clearStorageLoop(Type const* _type) const +void ArrayUtils::clearStorageLoop(Type const* _type, bool _canOverflow) const { solAssert(_type->storageBytes() >= 32, ""); m_context.callLowLevelFunction( - "$clearStorageLoop_" + _type->identifier(), + "$clearStorageLoop_" + _type->identifier() + (_canOverflow ? "_canOverflow" : "_cannotOverflow"), 2, 1, - [_type](CompilerContext& _context) + [_type, _canOverflow](CompilerContext& _context) { unsigned stackHeightStart = _context.stackHeight(); if (_type->category() == Type::Category::Mapping) @@ -943,9 +811,11 @@ void ArrayUtils::clearStorageLoop(Type const* _type) const // check for loop condition _context << Instruction::DUP1 << - Instruction::DUP3 << - Instruction::GT << - Instruction::ISZERO; + Instruction::DUP3; + if (_canOverflow) + _context << Instruction::EQ; + else + _context << Instruction::GT << Instruction::ISZERO; evmasm::AssemblyItem zeroLoopEnd = _context.newTag(); _context.appendConditionalJumpTo(zeroLoopEnd); // delete diff --git a/libsolidity/codegen/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h index 326084cb63a8..0aab702e9157 100644 --- a/libsolidity/codegen/ArrayUtils.h +++ b/libsolidity/codegen/ArrayUtils.h @@ -61,10 +61,6 @@ class ArrayUtils /// Stack pre: reference (excludes byte offset) /// Stack post: void clearDynamicArray(ArrayType const& _type) const; - /// Changes the size of a dynamic array and clears the tail if it is shortened. - /// Stack pre: reference (excludes byte offset) new_length - /// Stack post: - void resizeDynamicArray(ArrayType const& _type) const; /// Increments the size of a dynamic array by one. /// Does not touch the new data element. In case of a byte array, this might move the /// data. @@ -77,9 +73,10 @@ class ArrayUtils /// Stack post: void popStorageArrayElement(ArrayType const& _type) const; /// Appends a loop that clears a sequence of storage slots of the given type (excluding end). + /// @param _canOverflow whether the storage is treated as circular when clearing. /// Stack pre: end_ref start_ref /// Stack post: end_ref - void clearStorageLoop(Type const* _type) const; + void clearStorageLoop(Type const* _type, bool _canOverflow) const; /// Converts length to size (number of storage slots or calldata/memory bytes). /// if @a _pad then add padding to multiples of 32 bytes for calldata/memory. /// Stack pre: length diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index ffeaa790e1e8..e0998a92b314 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1431,7 +1431,7 @@ std::string YulUtilFunctions::cleanUpStorageArrayEndFunction(ArrayType const& _t )") ("convertToSize", arrayConvertLengthToSize(_type)) ("dataPosition", arrayDataAreaFunction(_type)) - ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())) + ("clearStorageRange", clearStorageRangeFunction(*_type.baseType(), !_type.isDynamicallySized())) ("packed", _type.baseType()->storageBytes() <= 16) ("itemsPerSlot", std::to_string(32 / _type.baseType()->storageBytes())) ("storageBytes", std::to_string(_type.baseType()->storageBytes())) @@ -1483,7 +1483,7 @@ std::string YulUtilFunctions::cleanUpDynamicByteArrayEndSlotsFunction(ArrayType )") ("dataLocation", arrayDataAreaFunction(_type)) ("div32Ceil", divide32CeilFunction()) - ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())) + ("clearStorageRange", clearStorageRangeFunction(*_type.baseType(), /* _canOverflow */ false)) .render(); }); } @@ -1523,7 +1523,7 @@ std::string YulUtilFunctions::decreaseByteArraySizeFunction(ArrayType const& _ty ("functionName", functionName) ("dataPosition", arrayDataAreaFunction(_type)) ("partialClearStorageSlot", partialClearStorageSlotFunction()) - ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())) + ("clearStorageRange", clearStorageRangeFunction(*_type.baseType(), /* _canOverflow */ true)) ("transitLongToShort", byteArrayTransitLongToShortFunction(_type)) ("div32Ceil", divide32CeilFunction()) ("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction()) @@ -1817,23 +1817,24 @@ std::string YulUtilFunctions::partialClearStorageSlotFunction() }); } -std::string YulUtilFunctions::clearStorageRangeFunction(Type const& _type) +std::string YulUtilFunctions::clearStorageRangeFunction(Type const& _type, bool _canOverflow) { if (_type.storageBytes() < 32) solAssert(_type.isValueType(), ""); - std::string functionName = "clear_storage_range_" + _type.identifier(); + std::string functionName = "clear_storage_range_" + _type.identifier() + (_canOverflow ? "_canOverflow" : "_cannotOverflow"); return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( function (start, end) { - for {} lt(start, end) { start := add(start, ) } + for {} (start, end) { start := add(start, ) } { (start, 0) } } )") ("functionName", functionName) + ("compare", _canOverflow ? "sub" : "lt") ("setToZero", storageSetToZeroFunction(_type.storageBytes() < 32 ? *TypeProvider::uint256() : _type, VariableDeclaration::Location::Unspecified)) ("increment", _type.storageSize().str()) .render(); @@ -1871,7 +1872,7 @@ std::string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type) ( "clearRange", _type.baseType()->category() != Type::Category::Mapping ? - clearStorageRangeFunction((_type.baseType()->storageBytes() < 32) ? *TypeProvider::uint256() : *_type.baseType()) : + clearStorageRangeFunction((_type.baseType()->storageBytes() < 32) ? *TypeProvider::uint256() : *_type.baseType(), /* _canOverflow */ true) : "" ) ("lenToSize", arrayConvertLengthToSize(_type)) diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index c28ba855c816..201ab2e93a4f 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -268,7 +268,8 @@ class YulUtilFunctions /// @returns the name of a function that will clear the storage area given /// by the start and end (exclusive) parameters (slots). /// signature: (start, end) - std::string clearStorageRangeFunction(Type const& _type); + /// if _canOverflow is true, it treats the storage as circular and clears by wrapping around. + std::string clearStorageRangeFunction(Type const& _type, bool _canOverflow); /// @returns the name of a function that will clear the given storage array /// signature: (slot) -> @@ -618,7 +619,7 @@ class YulUtilFunctions std::string cleanUpDynamicByteArrayEndSlotsFunction(ArrayType const& _type); /// @returns the name of a function that increases size of byte array - /// when we resize byte array frextractUsedSetLenom < 32 elements to >= 32 elements or we push to byte array of size 31 copying of data will occur + /// when we resize byte array from < 32 elements to >= 32 elements or we push to byte array of size 31 copying of data will occur /// signature: (array, data, oldLen, newLen) std::string increaseByteArraySizeFunction(ArrayType const& _type); diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_overlapped_dynamic_arrays.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_overlapped_dynamic_arrays.sol index aa1e494c2133..f767d4f9edd8 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_overlapped_dynamic_arrays.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_overlapped_dynamic_arrays.sol @@ -34,7 +34,7 @@ contract C { // f_which(uint256[],uint256[2],uint256): 0x40, 1, 2, 1 -> FAILURE // f_storage(uint256[],uint256[2]): 0x20, 1, 2 -> 0x20, 0x60, 0x20, 1, 2 // gas irOptimized: 111409 -// gas legacy: 112707 +// gas legacy: 112704 // gas legacyOptimized: 111845 // f_storage(uint256[],uint256[2]): 0x40, 1, 2, 5, 6 -> 0x20, 0x80, 0x20, 2, 5, 6 // f_storage(uint256[],uint256[2]): 0x40, 1, 2, 5 -> FAILURE diff --git a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol index 9599af6c8815..c47e36ea9d58 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol @@ -19,9 +19,9 @@ contract C { // ---- // h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324 // gas irOptimized: 180080 -// gas legacy: 184233 +// gas legacy: 184224 // gas legacyOptimized: 180856 // i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224 // gas irOptimized: 112031 -// gas legacy: 115091 +// gas legacy: 115082 // gas legacyOptimized: 112657 diff --git a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol index a9d08ec0c0cb..80c994a90cba 100644 --- a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol +++ b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol @@ -13,8 +13,8 @@ contract Test { // ---- // set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06 // gas irOptimized: 185216 -// gas legacy: 211054 -// gas legacyOptimized: 206077 +// gas legacy: 210694 +// gas legacyOptimized: 205741 // data(uint256,uint256): 0x02, 0x02 -> 0x09 // data(uint256,uint256): 0x05, 0x01 -> 0x11 // data(uint256,uint256): 0x06, 0x00 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol index 342f3218fcb4..9d1836b3e207 100644 --- a/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol +++ b/test/libsolidity/semanticTests/array/constant_var_as_array_length.sol @@ -10,9 +10,9 @@ contract C { // constructor(): 1, 2, 3 -> // gas irOptimized: 124991 // gas irOptimized code: 14800 -// gas legacy: 134317 +// gas legacy: 134298 // gas legacy code: 46200 -// gas legacyOptimized: 127166 +// gas legacyOptimized: 127147 // gas legacyOptimized code: 23400 // a(uint256): 0 -> 1 // a(uint256): 1 -> 2 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol b/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol index ecfe565f12cb..21b1796151e3 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_calldata_storage.sol @@ -21,6 +21,6 @@ contract c { // ---- // store(uint256[9],uint8[3][]): 21, 22, 23, 24, 25, 26, 27, 28, 29, 0x140, 4, 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33 -> 32 // gas irOptimized: 647725 -// gas legacy: 694354 -// gas legacyOptimized: 693849 +// gas legacy: 694351 +// gas legacyOptimized: 693847 // retrieve() -> 9, 28, 9, 28, 4, 3, 32 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol index bb621fcc84b5..1c76a79c5007 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol @@ -36,11 +36,11 @@ contract c { // ---- // test() -> 0x02000202 // gas irOptimized: 4549676 -// gas legacy: 4475394 -// gas legacyOptimized: 4447665 +// gas legacy: 4473198 +// gas legacyOptimized: 4445469 // storageEmpty -> 1 // clear() -> 0, 0 // gas irOptimized: 4478184 -// gas legacy: 4407185 -// gas legacyOptimized: 4381337 +// gas legacy: 4405274 +// gas legacyOptimized: 4379426 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol index 2d325a804bfa..48f2d2b312ca 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol @@ -13,5 +13,5 @@ contract c { // ---- // test(uint256[2][]): 32, 3, 7, 8, 9, 10, 11, 12 -> 10 // gas irOptimized: 689552 -// gas legacy: 686176 -// gas legacyOptimized: 685611 +// gas legacy: 686086 +// gas legacyOptimized: 685524 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base_nested.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base_nested.sol index ad745ff4203f..03b69817bd87 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base_nested.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_different_base_nested.sol @@ -22,5 +22,5 @@ contract c { // ---- // test() -> 3, 4 // gas irOptimized: 169669 -// gas legacy: 175415 -// gas legacyOptimized: 172533 +// gas legacy: 175289 +// gas legacyOptimized: 172413 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol index d1f2cbdedcde..392cad1228f6 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_static_static.sol @@ -15,5 +15,5 @@ contract c { // ---- // test() -> 8, 0 // gas irOptimized: 196251 -// gas legacy: 194842 -// gas legacyOptimized: 194281 +// gas legacy: 194779 +// gas legacyOptimized: 194218 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol index 22105f6429b9..13cbc47d9a05 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol @@ -18,5 +18,5 @@ contract c { // ---- // test() -> 0xffffffff, 0x0000000000000000000000000a00090008000700060005000400030002000100, 0x0000000000000000000000000000000000000000000000000000000000000000 // gas irOptimized: 100496 -// gas legacy: 158109 -// gas legacyOptimized: 141019 +// gas legacy: 158049 +// gas legacyOptimized: 140962 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol index 27fb9f0c5736..ba7394b57288 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple.sol @@ -19,5 +19,5 @@ contract c { // ---- // test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x0 // gas irOptimized: 273543 -// gas legacy: 282601 -// gas legacyOptimized: 281510 +// gas legacy: 282541 +// gas legacyOptimized: 281453 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol index 980e414d1451..9f8bdcb0a454 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_simple_2.sol @@ -19,5 +19,5 @@ contract c { // ---- // test() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x00 // gas irOptimized: 232995 -// gas legacy: 235694 -// gas legacyOptimized: 235193 +// gas legacy: 235688 +// gas legacyOptimized: 235187 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol index b892ec991ce3..e5370359c05e 100644 --- a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol @@ -38,12 +38,12 @@ contract Test { } // ---- // test() -> 24 -// gas irOptimized: 226734 +// gas irOptimized: 226728 // gas legacy: 227083 // gas legacyOptimized: 226529 // test1() -> 3 // test2() -> 6 // test3() -> 24 -// gas irOptimized: 141319 +// gas irOptimized: 141257 // gas legacy: 142238 // gas legacyOptimized: 141365 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol index 355c268f2514..7aeb9dcd56d6 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_memory_to_storage.sol @@ -26,4 +26,4 @@ contract C { // compileViaYul: true // ---- // f() -> 3, 3, 3, 1 -// gas irOptimized: 181928 +// gas irOptimized: 181919 diff --git a/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol b/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol index 95ba9d8ed8e8..33a46e881f59 100644 --- a/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/copy_internal_function_array_to_storage.sol @@ -18,6 +18,6 @@ contract C { } // ---- // one() -> 3 -// gas legacy: 140253 -// gas legacyOptimized: 140093 +// gas legacy: 140193 +// gas legacyOptimized: 140036 // two() -> FAILURE, hex"4e487b71", 0x51 diff --git a/test/libsolidity/semanticTests/array/copying/nested_array_element_storage_to_storage.sol b/test/libsolidity/semanticTests/array/copying/nested_array_element_storage_to_storage.sol index f3934fec0f6f..16b56ed90d8c 100644 --- a/test/libsolidity/semanticTests/array/copying/nested_array_element_storage_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/nested_array_element_storage_to_storage.sol @@ -79,6 +79,6 @@ contract C { // gas legacyOptimized: 150575 // test3() -> // gas irOptimized: 124300 -// gas legacy: 125333 -// gas legacyOptimized: 125127 +// gas legacy: 125330 +// gas legacyOptimized: 125124 // test4() -> FAILURE diff --git a/test/libsolidity/semanticTests/array/push/array_push_struct.sol b/test/libsolidity/semanticTests/array/push/array_push_struct.sol index 92f071e1fb22..df946f199f54 100644 --- a/test/libsolidity/semanticTests/array/push/array_push_struct.sol +++ b/test/libsolidity/semanticTests/array/push/array_push_struct.sol @@ -21,5 +21,5 @@ contract c { // ---- // test() -> 2, 3, 4, 5 // gas irOptimized: 135329 -// gas legacy: 147437 -// gas legacyOptimized: 146429 +// gas legacy: 147377 +// gas legacyOptimized: 146373 diff --git a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol index ed4eb6e4d15f..0332cfb988c7 100644 --- a/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol +++ b/test/libsolidity/semanticTests/constructor/constructor_static_array_argument.sol @@ -13,9 +13,9 @@ contract C { // constructor(): 1, 2, 3, 4 -> // gas irOptimized: 148129 // gas irOptimized code: 23000 -// gas legacy: 157977 +// gas legacy: 157958 // gas legacy code: 60400 -// gas legacyOptimized: 149973 +// gas legacyOptimized: 149954 // gas legacyOptimized code: 26200 // a() -> 1 // b(uint256): 0 -> 2 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_array_assignment.sol b/test/libsolidity/semanticTests/storage/storage_boundary_array_assignment.sol new file mode 100644 index 000000000000..b9583d295871 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_array_assignment.sol @@ -0,0 +1,28 @@ +contract C { + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function assignArray(uint256[10] memory y) public { + uint256[10][1] storage _x = getArray(); + _x[0] = y; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// assignArray(uint256[10]): 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> +// gas irOptimized: 245236 +// gas legacy: 247487 +// gas legacyOptimized: 245441 +// x() -> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 +// assignArray(uint256[10]): 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 -> +// x() -> 10, 0x14, 0x1e, 0x28, 0x32, 0x3c, 0x46, 0x50, 0x5a, 0x64 +// gas irOptimized: 198025 +// gas legacy: 200268 +// gas legacyOptimized: 198058 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_array_delete.sol b/test/libsolidity/semanticTests/storage/storage_boundary_array_delete.sol new file mode 100644 index 000000000000..3c1ccc6c7082 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_array_delete.sol @@ -0,0 +1,34 @@ +contract C { + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function fillArray() public { + uint256[10][1] storage _x = getArray(); + for (uint i = 1; i < 10; i++) + _x[0][i] = i; + } + + function clearArray() public { + uint256[10][1] storage _x = getArray(); + delete _x[0]; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 220705 +// gas legacy: 221434 +// gas legacyOptimized: 220871 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +// clearArray() +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 181920 +// gas legacy: 184143 +// gas legacyOptimized: 181899 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_array_delete_overlapping_variable.sol b/test/libsolidity/semanticTests/storage/storage_boundary_array_delete_overlapping_variable.sol new file mode 100644 index 000000000000..b00658a6a281 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_array_delete_overlapping_variable.sol @@ -0,0 +1,40 @@ +contract C { + uint256 public y = 42; + + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function fillArray() public { + uint256[10][1] storage _x = getArray(); + for (uint i = 1; i < 10; i++) + _x[0][i] = i; + } + + function clearArray() public { + uint256[10][1] storage _x = getArray(); + delete _x[0]; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } +} + +// ---- +// y() -> 42 +// x() -> 0, 0, 0, 0, 0, 0x2a, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 203627 +// gas legacy: 204356 +// gas legacyOptimized: 203793 +// y() -> 5 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +// clearArray() +// y() -> 0 +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 168243 +// gas legacy: 170463 +// gas legacyOptimized: 168219 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment.sol b/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment.sol new file mode 100644 index 000000000000..d6c43e5c472c --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment.sol @@ -0,0 +1,34 @@ +contract C { + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function fillArray() public { + uint256[10][1] storage _x = getArray(); + for (uint i = 1; i < 10; i++) + _x[0][i] = i; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } + + function partialAssignArray() public { + uint256[10][1] storage _x = getArray(); + _x[0] = [11, 12, 13]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 220705 +// gas legacy: 221434 +// gas legacyOptimized: 220871 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +// partialAssignArray() +// x() -> 11, 12, 13, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 198025 +// gas legacy: 200268 +// gas legacyOptimized: 198058 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment_cross_border.sol b/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment_cross_border.sol new file mode 100644 index 000000000000..09c753ef5ced --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_array_partial_assignment_cross_border.sol @@ -0,0 +1,34 @@ +contract C { + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function fillArray() public { + uint256[10][1] storage _x = getArray(); + for (uint i = 1; i < 10; i++) + _x[0][i] = i; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } + + function partialAssignArray() public { + uint256[10][1] storage _x = getArray(); + _x[0] = [11, 12, 13, 14, 15, 16, 17]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 220705 +// gas legacy: 221434 +// gas legacyOptimized: 220871 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 +// partialAssignArray() +// x() -> 11, 12, 13, 14, 15, 0x10, 0x11, 0, 0, 0 +// gas irOptimized: 198025 +// gas legacy: 200268 +// gas legacyOptimized: 198058 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_delete_array_with_layout.sol b/test/libsolidity/semanticTests/storage/storage_boundary_delete_array_with_layout.sol new file mode 100644 index 000000000000..713d724e3bfa --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_delete_array_with_layout.sol @@ -0,0 +1,54 @@ +contract C layout at 2**256 - 5 { + uint256 a; + + function getArray() internal pure returns (uint256[10][1] storage _x) { + assembly { + _x.slot := a.slot + } + } + + function fillArray() public { + uint256[10][1] storage _x = getArray(); + for (uint i = 1; i < 10; i++) + _x[0][i] = i; + } + + function partialAssignArrayBeforeStorageBoundary() public { + uint256[10][1] storage _x = getArray(); + _x[0] = [11, 12, 13]; + } + + function partialAssignArrayCrossStorageBoundary() public { + uint256[10][1] storage _x = getArray(); + _x[0] = [14, 15, 16, 17, 18, 19, 20]; + } + + function clearArray() public { + uint256[10][1] storage _x = getArray(); + delete _x[0]; + } + + function x() public view returns (uint256[10] memory) { + return getArray()[0]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 220749 +// gas legacy: 221473 +// gas legacyOptimized: 220915 +// partialAssignArrayBeforeStorageBoundary() +// x() -> 11, 12, 13, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 186549 +// gas legacy: 187273 +// gas legacyOptimized: 186715 +// x() -> 11, 1, 2, 3, 4, 5, 6, 7, 8, 9 +// partialAssignArrayCrossStorageBoundary() +// x() -> 14, 15, 0x10, 0x11, 0x12, 0x13, 0x14, 0, 0, 0 +// clearArray() +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 181930 +// gas legacy: 184143 +// gas legacyOptimized: 181900 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_delete_overflow_bug.sol b/test/libsolidity/semanticTests/storage/storage_boundary_delete_overflow_bug.sol new file mode 100644 index 000000000000..3a0d348e419d --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_delete_overflow_bug.sol @@ -0,0 +1,80 @@ +contract C { + mapping(string => uint256[256][2**240]) m; + + function getSlot() internal view returns (uint256) { + uint256[256][2**240] storage _x = m["v 2.2.3"]; + uint256 slot; + assembly { + slot := _x.slot + } + assert(slot == 0xffdb3f1d9f54eb0b5012935c286c508459d381405d269e01c15f4ec2826edbbf); + return slot; + } + + function getIndex() internal view returns (uint256) { + uint256 slot = getSlot(); + // Pick the largest index such that `slot + 256 * index` <= `2**256 - 1` + uint256 index = (type(uint256).max - slot) / 256; + assert(index <= type(uint240).max); + assert((type(uint256).max - slot + 1) % 256 != 0); + + return index; + } + + function getArray() internal view returns (uint256[256][2**240] storage _x) { + uint256 s = getSlot(); + assembly { + _x.slot := s + } + } + + function fillArray() public { + uint256[256][2**240] storage _x = getArray(); + for (uint i = 1; i < 256; i++) + _x[getIndex()][i] = i; + } + + function partialAssignArray() public { + uint256[256][2**240] storage _x = getArray(); + _x[getIndex()] = [11, 22, 33, 44, 55, 66, 77, 88, 99]; + } + + function clearArray() public { + uint256[256][2**240] storage _x = getArray(); + delete _x[getIndex()]; + } + + function x() public view returns (uint256[256] memory) { + return getArray()[getIndex()]; + } +} + +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 604108 +// gas legacy: 644983 +// gas legacyOptimized: 598016 +// fillArray() +// gas irOptimized: 5782148 +// gas legacy: 6044562 +// gas legacyOptimized: 5853893 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +// gas irOptimized: 604108 +// gas legacy: 644983 +// gas legacyOptimized: 598016 +// partialAssignArray() +// gas irOptimized: 1065037 +// gas legacy: 1067333 +// gas legacyOptimized: 1065189 +// x() -> 11, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d, 0x58, 0x63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 604108 +// gas legacy: 644983 +// gas legacyOptimized: 598016 +// clearArray() +// gas irOptimized: 578882 +// gas legacy: 581698 +// gas legacyOptimized: 578989 +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 604108 +// gas legacy: 644983 +// gas legacyOptimized: 598016 diff --git a/test/libsolidity/semanticTests/storage/storage_boundary_packed_array.sol b/test/libsolidity/semanticTests/storage/storage_boundary_packed_array.sol new file mode 100644 index 000000000000..f4f818781471 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_boundary_packed_array.sol @@ -0,0 +1,34 @@ +contract C { + function getArray() internal pure returns (uint64[40][1] storage _x) { + assembly { + _x.slot := sub(0, 5) + } + } + + function fillArray() public { + uint64[40][1] storage _x = getArray(); + for (uint64 i = 1; i < 40; i++) + _x[0][i] = i; + } + + function clearArray() public { + uint64[40][1] storage _x = getArray(); + delete _x[0]; + } + + function x() public view returns (uint64[40] memory) { + return getArray()[0]; + } +} +// ---- +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// fillArray() +// gas irOptimized: 254227 +// gas legacy: 258712 +// gas legacyOptimized: 257258 +// x() -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 +// clearArray() +// x() -> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +// gas irOptimized: 181920 +// gas legacy: 184143 +// gas legacyOptimized: 181899 diff --git a/test/libsolidity/semanticTests/storage/storage_packed_array_copy.sol b/test/libsolidity/semanticTests/storage/storage_packed_array_copy.sol new file mode 100644 index 000000000000..9ab6547e0057 --- /dev/null +++ b/test/libsolidity/semanticTests/storage/storage_packed_array_copy.sol @@ -0,0 +1,27 @@ +contract C { + bytes8[9] _x; // 4 per slot + bytes17[10] _y; // 1 per slot, no offset counter + + constructor() { + for (uint256 i = 0; i < _x.length; ++i) _x[i] = bytes8(uint64(i)); + _y[8] = _y[9] = bytes8(uint64(2)); + } + + function f() + public + returns (bytes17 a, bytes17 b, bytes17 c, bytes17 d, bytes17 e) + { + _y = _x; + a = _y[1]; + b = _y[2]; + c = _y[3]; + d = _y[4]; + e = _y[9]; + } +} + +// ---- +// f() -> 0x01000000000000000000000000000000000000000000000000, 0x02000000000000000000000000000000000000000000000000, 0x03000000000000000000000000000000000000000000000000, 0x04000000000000000000000000000000000000000000000000, 0x00 +// gas irOptimized: 191520 +// gas legacy: 199338 +// gas legacyOptimized: 198238 diff --git a/test/libsolidity/semanticTests/types/mapping/copy_from_mapping_to_mapping.sol b/test/libsolidity/semanticTests/types/mapping/copy_from_mapping_to_mapping.sol index 26e8294e3ac9..3c9d3fffe492 100644 --- a/test/libsolidity/semanticTests/types/mapping/copy_from_mapping_to_mapping.sol +++ b/test/libsolidity/semanticTests/types/mapping/copy_from_mapping_to_mapping.sol @@ -30,5 +30,5 @@ contract C { // ---- // f() -> 0x20, 7, 8, 9, 0xa0, 13, 2, 0x40, 0xa0, 2, 3, 4, 2, 3, 4 // gas irOptimized: 197102 -// gas legacy: 199887 -// gas legacyOptimized: 196845 +// gas legacy: 199827 +// gas legacyOptimized: 203694