From 2d22f2c76bef4f9078761a390b0cd93a3304b9c0 Mon Sep 17 00:00:00 2001 From: genisis0x Date: Thu, 14 May 2026 12:46:24 +0530 Subject: [PATCH] TypeChecker: reject zero-length static array element types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeclarationTypeChecker::endVisit(ArrayTypeName) rejects `uint256[0]` (and similar) with TypeError 1406 "Array with zero length specified.", but that visitor only runs for ArrayTypeName declarations. Static array types written as expressions — e.g. inside `abi.decode((uint256[0][]))` — are constructed in TypeChecker::visit(IndexAccess) through the TypeType branch, which never validated the literal length. The zero-length type then propagated to codegen and triggered an ICE in ABIFunctions::abiDecodingFunctionArrayAvailableLength (and other callers that assume `calldataStride() > 0`). Apply the same rejection here as a fatal type error so the existing 1406 diagnostic is the only message users see and codegen is never reached with a zero-length element type. Fixes #16627 --- libsolidity/analysis/TypeChecker.cpp | 10 ++++++++++ .../array/length/abi_decode_zero_length_element.sol | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 test/libsolidity/syntaxTests/array/length/abi_decode_zero_length_element.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 25bd4a915197..c28652a6da33 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3634,7 +3634,17 @@ bool TypeChecker::visit(IndexAccess const& _access) if (expectType(*index, *TypeProvider::uint256())) { if (auto indexValue = dynamic_cast(type(*index))) + { + // Mirror the zero-length rejection from + // DeclarationTypeChecker::endVisit(ArrayTypeName). Static array types + // written as expressions (e.g. inside `abi.decode((T[0][]))`) never + // go through that visitor, so without this guard the zero-length + // element type propagates to codegen and triggers an ICE in + // callers that assume `calldataStride() > 0`. + if (indexValue->value() == 0) + m_errorReporter.fatalTypeError(1406_error, index->location(), "Array with zero length specified."); length = indexValue->literalValue(nullptr); + } else m_errorReporter.fatalTypeError(3940_error, index->location(), "Integer constant expected."); } diff --git a/test/libsolidity/syntaxTests/array/length/abi_decode_zero_length_element.sol b/test/libsolidity/syntaxTests/array/length/abi_decode_zero_length_element.sol new file mode 100644 index 000000000000..850c629842b0 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/length/abi_decode_zero_length_element.sol @@ -0,0 +1,9 @@ +// Used to cause ICE in ABIFunctions::abiDecodingFunctionArrayAvailableLength +// when a dynamic array's element type was a zero-length static array. +contract C { + function f(bytes memory b) public pure { + abi.decode(b, (uint256[0][])); + } +} +// ---- +// TypeError 1406: (146-147): Array with zero length specified.