diff --git a/.changeset/violet-insects-press.md b/.changeset/violet-insects-press.md new file mode 100644 index 0000000000..26b2084017 --- /dev/null +++ b/.changeset/violet-insects-press.md @@ -0,0 +1,6 @@ +--- +"@latticexyz/cli": patch +"@latticexyz/common": patch +--- + +Table libraries now correctly handle uninitialized fixed length arrays. diff --git a/packages/cli/contracts/src/codegen/tables/Dynamics1.sol b/packages/cli/contracts/src/codegen/tables/Dynamics1.sol index 4957973342..4d40e8f720 100644 --- a/packages/cli/contracts/src/codegen/tables/Dynamics1.sol +++ b/packages/cli/contracts/src/codegen/tables/Dynamics1.sol @@ -1495,37 +1495,67 @@ library Dynamics1 { } function toStaticArray_bytes32_1(bytes32[] memory _value) pure returns (bytes32[1] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 1) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } function toStaticArray_int32_2(int32[] memory _value) pure returns (int32[2] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 2) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } function toStaticArray_uint128_3(uint128[] memory _value) pure returns (uint128[3] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 3) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } function toStaticArray_address_4(address[] memory _value) pure returns (address[4] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 4) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } function toStaticArray_bool_5(bool[] memory _value) pure returns (bool[5] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 5) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } diff --git a/packages/cli/contracts/src/codegen/tables/Singleton.sol b/packages/cli/contracts/src/codegen/tables/Singleton.sol index ab91f15ecc..1d44b0d39c 100644 --- a/packages/cli/contracts/src/codegen/tables/Singleton.sol +++ b/packages/cli/contracts/src/codegen/tables/Singleton.sol @@ -912,16 +912,28 @@ library Singleton { } function toStaticArray_uint32_2(uint32[] memory _value) pure returns (uint32[2] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 2) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } function toStaticArray_uint32_1(uint32[] memory _value) pure returns (uint32[1] memory _result) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < 1) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } diff --git a/packages/common/src/codegen/render-solidity/renderTypeHelpers.ts b/packages/common/src/codegen/render-solidity/renderTypeHelpers.ts index 8446cfc88d..0d6fca112f 100644 --- a/packages/common/src/codegen/render-solidity/renderTypeHelpers.ts +++ b/packages/common/src/codegen/render-solidity/renderTypeHelpers.ts @@ -63,9 +63,15 @@ function renderWrapperStaticArray( ) pure returns ( ${elementType}[${staticLength}] memory _result ) { - // in memory static arrays are just dynamic arrays without the length byte - assembly { - _result := add(_value, 0x20) + if (_value.length < ${staticLength}) { + // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption + return _result; + } else { + // in memory static arrays are just dynamic arrays without the length byte + // (without the length check this could lead to memory corruption) + assembly { + _result := add(_value, 0x20) + } } } `;