-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
use before assignment of calldata struct instance inside a function does not throw an error #15483
Comments
This is somewhat intentional as a deliberate workaround to allow complex initialization patterns. I.e. the following is correct in the sense that there can never be an uninitialized access, but it's in general infeasible to detect this at compile-time: contract C {
struct A {
uint256 x;
}
struct B {
A a1;
A a2;
}
function f(B calldata b, bool c) external pure returns (uint256) {
A calldata a;
if (c) {
a = b.a1;
}
if (!c) {
a = b.a2;
}
return a.x;
}
} Which is why deliberately assigning to self can be used to work around the detection, i.e. this works as deliberate workaround: contract C {
struct A {
uint256 x;
}
struct B {
A a1;
A a2;
}
function f(B calldata b, bool c) external pure returns (uint256) {
A calldata a;
a = a;
if (c) {
a = b.a1;
}
if (!c) {
a = b.a2;
}
return a.x;
}
} Now the question is whether allowing this mode of workaround is generally a good thing - the idea was that it's rather unlikely that an assignment to self happens unintentionally and is thus safe to allow for allowing otherwise valid patterns through analysis. But since this is a known workaround against this kind of analysis, we'd likely need to consider changing the behavior here a breaking change. |
I see. Thanks for the clarification. |
Not sure if this is specifically documented, but what happens for So e.g. for |
Following this understanding, I found an issue: contract C{
struct S {
int a;
}
S st;
function f(S calldata cd) public {
st = cd; // pass, S calldata -> S storage
true ? st : cd; // fail: True expression's type struct C.S storage pointer does not match false expression's type struct C.S calldata.
}
} Does it reveal the inconsistency of type checking? |
That's a tricky example :-). You can also see the following fail: contract C{
struct S {
int a;
}
S st;
function f(S calldata cd) public {
S storage sp = st;
sp = cd;
}
} If that passed, then Now that's the technical explanation in terms of the type system. But on a higher-level, it would be very weird behaviour if The only way to make |
Really thanks for your patient clarification. It helps a lot for my building the semantics model of Solidity to generate Solidity programs. |
Description
The following program is a trivially correct one. I copy data from calldata to memory.
Then I mutate this test program into the following:
This test program causes an error, saying that
This variable is of calldata pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
. This is understandable. calldata is used to receive data from other contracts. So the calldata in a function without initialization is empty and should be initialized first.I continue the mutation by initializing s2 first like the below and it passed the compilation.
Now I wonder if the compiler can find an incorrect initialization of a calldata slot. So I initialize the calldata slot with itself, an initialized calldata slot, to get the following program:
Interestingly, the above test program does not trigger an expected error with message such as
This variable is of calldata pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
but passed the compilation.Environment
Steps to Reproduce
Just compile the above programs and you will reproduce the compilation results.
The text was updated successfully, but these errors were encountered: