-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Disallow passing a empty array type to abi functions.
#16416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
|
There was an error when running Please check that your changes are working as intended. |
libsolidity/analysis/TypeChecker.cpp
Outdated
|
|
||
| #include <libsolidity/analysis/TypeChecker.h> | ||
|
|
||
| #include "DeclarationTypeChecker.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
aa31d42 to
12c9408
Compare
|
There was an error when running Please check that your changes are working as intended. |
libsolidity/analysis/TypeChecker.cpp
Outdated
|
|
||
| #include <libsolidity/analysis/TypeChecker.h> | ||
|
|
||
| #include "DeclarationTypeChecker.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
12c9408 to
bc948b5
Compare
nikola-matic
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changelog
| library C { | ||
| function f() view public { | ||
| C[0]; | ||
| C[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add new cases testing specifically for the case of zero length in a situation like this? Or do we have them already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I'd add variants for interfaces for completeness.
And rename C here to L (we usually use C for a contract so it makes it easy to confuse things).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is specifically about decoding so I'd rename it to abi_decode_zero_length_array_type.sol. You can have int[0] in other situations and this test is not checking them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I'm assuming we already have coverage for those other cases, but maybe check whether that's the case. These are ones I can think of:
- Variable declaration
- Contract variable (
uint[0] x;,mapping(uint => uint[0]) m;,function() returns (uint[0] memory) f;) - Local variable (
uint[0] storage x;) - Function arguments and returns
- Try/catch statement (
try this.g() returns (uint[0] memory) {} catch (bytes memory b) {})
- Contract variable (
- Tuple declaration (
(uint[0] memory a, uint b) = ([], 1);) - Struct field (
struct S { uint[0] x; }) - Error and event parameters
- Array allocation (
new uint[0][](3); }) - No-op statement consisting of just the type (
uint[0];)
Technically, these but are disallowed for various other reasons in analysis, but are still valid syntax, so would not hurt to have them covered:
- UDVT declaration (
type U is uint[0];) type()builtin (type(uint[0])).- Ternary operator (
true ? uint[0] : uint[0]) - Inline Array indexing (
[uint[0]][0])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see f6() is actually not decoding. I'd still split it into separate tests though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworked and more tests added.
| @@ -0,0 +1,38 @@ | |||
| contract C { | |||
| function f0() public { | |||
| abi.decode("", (int[0])); | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| abi.decode("", (int[0])); | |
| abi.decode("", (int[0])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add the case from #13652 (comment). That one was not a compilation error so it's important that this no longer allowed:
contract C {
function f() public returns (bytes memory) {
return abi.encode(abi.decode("", (int[0])));
}
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added as a separated test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add a dedicated case for super (which is actually a type):
contract C {
function f() public {
super[0];
}
}contract C {
function f() public {
super[0] s;
}
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly, an array of super is a valid expression on its own (super[3];) even though you cannot use it in a variable declaration (super[3] s;). I think it should be disallowed in either case.
I suspect that we have more things like this. Would be good to take a look at DeclarationTypeChecker and compare what other checks it has for ArrayTypeName that we do not here. Perhaps we should extract them into a shared function to avoid such discrepancies in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, pinging @matheusaaguiar to pay attention to this in test cases related to comptime. Looks like we have two places in the code where we evaluate array sizes. These should always behave the same way.
Also, WTF, why does every random issue recently turn out to be related to comptime one way or another :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not open your refrigerator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reworked this part and put common logic in separated function, where it was possible.
bc948b5 to
0bc0d0b
Compare
| #include <libsolidity/analysis/DeclarationTypeChecker.h> | ||
|
|
||
| #include <libsolidity/analysis/ConstantEvaluator.h> | ||
| #include "TypeChecker.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
libsolidity/analysis/TypeChecker.cpp
Outdated
|
|
||
| #include <libsolidity/analysis/TypeChecker.h> | ||
|
|
||
| #include "ConstantEvaluator.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
libsolidity/analysis/TypeChecker.cpp
Outdated
| { | ||
| TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType); | ||
| if (auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType())) | ||
| const auto actualType = typeType.actualType(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
libsolidity/analysis/TypeChecker.cpp
Outdated
| TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType); | ||
| if (auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType())) | ||
| const auto actualType = typeType.actualType(); | ||
| const auto actualTypeCategory = actualType->category(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
|
Run |
0bc0d0b to
e7e72c7
Compare
libsolidity/analysis/TypeChecker.cpp
Outdated
| { | ||
| TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType); | ||
| if (auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType())) | ||
| const auto actualType = typeType.actualType(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
libsolidity/analysis/TypeChecker.cpp
Outdated
| TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType); | ||
| if (auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType())) | ||
| const auto actualType = typeType.actualType(); | ||
| const auto actualTypeCategory = actualType->category(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coding style error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error is not issued when running the script locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AI says so:
With git grep -E, the regex engine is POSIX extended regex. In that dialect, \s is not a whitespace escape (that’s a PCRE/Perl thing). So:
^\s* is effectively interpreted as ^s* (i.e., “zero or more s characters at BOL”)
which means it won’t match indentation made of spaces/tabs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As usual, AI is full of shit. You're getting the error because you're using const auto ... instead of auto const .... What OS are you running locally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know what was the problem, but this script doesn't find the pattern. And this is good explanation. I'm using MacOS with git in the newest version 2.52.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AI proposed to change \sto [[:space:]], because (POSIX ERE) does not understand \s :)
Looks like it's right. https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand it looks like they should be supported too https://www.boost.org/doc/libs/1_71_0/libs/regex/doc/html/boost_regex/syntax/basic_extended.html#boost_regex.syntax.basic_extended.single_character_character_class
Probable for some reason MacOS does not support it.
It's for boost.regexp only
7c5c3f2 to
56065c7
Compare
56065c7 to
8537278
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes issue #13652 by adding validation to prevent zero-length arrays from being used in expression contexts like abi.decode, which previously caused internal compiler errors during code generation. The fix adds a new shared validation function checkArrayLengthExpression that ensures array lengths are non-zero, positive integers within valid bounds.
Changes:
- Added
TypeChecker::checkArrayLengthExpressionfunction to validate array length expressions - Refactored array length validation logic to use the new shared function in both
TypeChecker(for expression contexts) andDeclarationTypeChecker(for declaration contexts) - Added comprehensive test coverage for zero-length arrays in various contexts (abi.decode, inline arrays, conditionals, type expressions, etc.)
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| libsolidity/analysis/TypeChecker.h | Added declaration for new static checkArrayLengthExpression function |
| libsolidity/analysis/TypeChecker.cpp | Implemented checkArrayLengthExpression function and refactored IndexAccess visitor to validate array lengths and handle super/library types more explicitly |
| libsolidity/analysis/DeclarationTypeChecker.cpp | Refactored to use the new shared checkArrayLengthExpression function instead of duplicate validation logic |
| test/libsolidity/syntaxTests/array/invalid/abi_decode_zero_length_array_type.sol | New test covering the exact issue case with various multi-dimensional array patterns |
| test/libsolidity/syntaxTests/array/invalid/abi_encode_decode_zero_length_array_type.sol | New test for abi.encode with zero-length arrays |
| test/libsolidity/syntaxTests/array/invalid/contract_zero_index_access.sol | New test for contract type with zero-length array |
| test/libsolidity/syntaxTests/array/invalid/interface_zero_index_access.sol | New test for interface type with zero-length array |
| test/libsolidity/syntaxTests/array/invalid/library_zero_index_access.sol | New test for library type with zero-length array (shows both errors) |
| test/libsolidity/syntaxTests/array/invalid/super_index_access.sol | New test for super keyword with index access |
| test/libsolidity/syntaxTests/array/length/*.sol | Multiple new tests for zero-length arrays in different contexts (inline arrays, type expressions, conditionals) |
| test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol | Expanded test with more zero-length array scenarios |
| test/libsolidity/syntaxTests/array/type_type_index_expression.sol | New test showing valid index expressions with various types |
| test/libsolidity/syntaxTests/array/contract_index_access.sol | Updated test to use non-zero index and pure function |
| test/libsolidity/syntaxTests/array/interface_index_access.sol | New test for valid interface array type |
| test/libsolidity/syntaxTests/array/invalid/library_index_access.sol | Updated test for clarity (renamed library) |
| test/libsolidity/syntaxTests/nameAndTypeResolution/366_invalid_array_as_statement.sol | Updated expected error message |
| test/libsolidity/syntaxTests/indexing/struct_array_noninteger_index.sol | Updated expected error message |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…clarationTypeChecker`
8537278 to
a01870d
Compare
Hmm... looks like |
This PR adds additional check in
TypeCheckerforIndexAccesswhich ensures that the array size is not0.As a result of this change, type which is an empty array of contracts is also forbidden.
Fixes #13652.