-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Fix string.concat and bytes.concat assignment to a constant variable.
#16341
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
string.concat and bytes.concat assignment to a constant variable.
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.
type_information_pure_assignment_error.sol
I don't see any errors in this file :)
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.
Yeah. Too fast as always. Need to slow down a little. So basically I thought initially that runtime/creation codes cannot be compile time constants, but they can and it works well. Added test to type_information_pure_assignment.sol. As discussed async there is only one small issues with this. Namely we should verify that there is no circular dependency in the code. So a contract contains a constant variable which stores code (runtime or creation) of the contract it is being defined. Reported #16345
test/libsolidity/syntaxTests/constants/type_information_pure_assignment_error.sol
Outdated
Show resolved
Hide resolved
test/libsolidity/syntaxTests/constants/math_functions_pure_assignment_error.sol
Outdated
Show resolved
Hide resolved
test/libsolidity/syntaxTests/constants/type_information_pure_assignment_error.sol
Outdated
Show resolved
Hide resolved
7974cf9 to
9cdd7bb
Compare
9cdd7bb to
aee6051
Compare
| if ( | ||
| // This covers `bytes.concat` and `string.concat`. | ||
| tt->actualType()->category() == Type::Category::Array && | ||
| memberName == "concat" |
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.
It would be safer to check for FunctionType::Kind::StringConcat/FunctionType::Kind::BytesConcat rather than function name.
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 would also add an assert at the end of this function that for function types the annotation matches the result of FunctionType::isPure().
| function isEmptyCode() public pure returns (bool) { | ||
| return creationCode.length > 0 && runtimeCode.length > 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.
The name does not match the condition.
| function isEmptyCode() public pure returns (bool) { | |
| return creationCode.length > 0 && runtimeCode.length > 0; | |
| function nonEmptyCode() public pure returns (bool) { | |
| return creationCode.length > 0 && runtimeCode.length > 0; |
| bytes constant abcGlobal = bytes.concat( | ||
| hex"aaaa", | ||
| hex"bbbb", | ||
| hex"cccc" | ||
| ); |
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.
For completeness I'd also make one of the arguments a constant.
And in bytes_concat_pure_assignment_error.sol I'd add a call to a function that is marked pure.
| bytes constant abData = bytes.concat( | ||
| hex"aaaa", | ||
| hex"bbbb", | ||
| msg.data | ||
| ); |
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.
The args in these tests are pretty short, so I'd put them on a single line to make these it less verbose.
| bytes constant abData = bytes.concat( | |
| hex"aaaa", | |
| hex"bbbb", | |
| msg.data | |
| ); | |
| bytes constant abData = bytes.concat(hex"aaaa", hex"bbbb", msg.data); |
| uint256 k = 7; | ||
| uint256 constant amod = addmod(1, 8, k); | ||
| uint256 constant mmod = mulmod(1, 8, k); |
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 we have a variant of this test but with constant args?
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.
Same for math_functions_precompiles_pure_assignment_error.sol
| bytes32 constant sGlobal = sha256(hex"ffff"); | ||
| address constant addrGlobal = ecrecover("1234", 1, "0", abi.decode("", (bytes2))); |
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 add ripemd160() for completeness.
| bytes creationCodeB = type(B).creationCode; | ||
| bytes runtimeCodeB = type(B).runtimeCode; |
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.
These are not marked constant:
| bytes creationCodeB = type(B).creationCode; | |
| bytes runtimeCodeB = type(B).runtimeCode; | |
| bytes constant creationCodeB = type(B).creationCode; | |
| bytes constant runtimeCodeB = type(B).runtimeCode; |
And I'd add them at file level too.
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.
It would be good to use a more regular naming scheme for these tests. Checking if we already have tests covering something is always a challenge and this would make it a bit easier. Here's how I'd name these:
abi_decode_pure_assignment.sol -> assign_abi_decode_non_const_args.sol
abi_decode_pure_assignment_error.sol -> assign_abi_decode_const_args.sol
abi_encoding_constant_error.sol -> assign_abi_encoding_builtin_non_const_args.sol
abi_encode_call_pure_assignment.sol -> assign_abi_encode_const_args.sol
abi_encode_call_pure_assignment_error.sol -> assign_abi_encode_non_const_args.sol
block_and_tx_properties_pure_assignment_error.sol -> assign_block_tx_msg_property.sol
bytes_concat_pure_assignment.sol -> assign_bytes_concat_const_args.sol
bytes_concat_pure_assignment_error.sol -> assign_bytes_concat_non_const_args.sol
string_concat_pure_assignment.sol -> assign_string_concat_const_args.sol
string_concat_pure_assignment_error.sol -> assign_string_concat_non_const_args.sol
math_functions_opcodes_pure_assignment_error.sol -> assign_math_builtin_opcode_based_non_const_args.sol
math_functions_precompiles_pure_assignment_error.sol -> assign_math_builtin_precompile_based_non_const_args.sol
math_functions_pure_assignment.sol -> assign_math_builtin_const_args.sol
type_information_pure_assignment.sol -> assign_type_info.sol
General remarks:
- Instead of appending
_errorI'd rather have the test name say what exactly makes the test different. It makes it easier to see what the test is about just from the name and sometimes these errors are there only temporarily, because some features is not yet implemented. - Instead of the
assign_prefix I suggested above you could also group them by moving them into a subdir, e.g.initialization/. - The names of existing tests use
pureandconstantinterchangeably. That's because I think initiallypurewas meant to be a compile-time constant. With time they have diverged andpurewill likely remain its own thing. It's fine to stick to original naming if it's consistent, but otherwise we should distinguish these.
Initially reviewed here #16335
This PR fixes assignment to a constant variable of a result of string or bytes concatenation, if their arguments are values known in the compile-time.
Closes: #16188
Additionally