-
Notifications
You must be signed in to change notification settings - Fork 5.9k
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
Stricter check for "this" in constructor. #3875
Conversation
libsolidity/analysis/TypeChecker.cpp
Outdated
if (_function.isConstructor() && TypeType(type(*var)) == *m_scope->type()) | ||
m_errorReporter.typeError( | ||
var->location(), | ||
"Constructor arguments cannot have the contract itself as type." |
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.
My first hunch was this should be a bug as you did, but after further consideration it may make sense to support this.
There were some examples in the past of splitting/forking contracts, where the reference is to another contract of the same type.
I agree, this is not the way to fix it :) I think the condition in StaticAnalyzer.cpp:209 has to be tighter than it currently is. |
OK, I remembered talking about this with you and concluding that such arguments would be an error in general - that's why I went ahead and did it this way :-). Since there can only be one constructor per contract, how can a constructor with another contract of the same type ever be called in the first place :-)? I'm just wondering what such an example could look like... |
ok, that's a fair point, but we also have interfaces and stuff... |
I wouldn't restrict it in such a way. |
Alright! |
This should be valid:
And the the first create transaction can just pass an address 0 for the initial contract. |
Ah OK! I hadn't thought about that! |
@ekpyron can you just fix it here properly? :) |
@axic OK - my plan was to open a new PR once it's finished, but I might as well reuse this one :-). I'll be away for an hour now, though, so it'll take until afterwards. |
5961d20
to
c3dc67d
Compare
cd784db
to
61db349
Compare
61db349
to
bf12e8e
Compare
I think I need some clarification on this one. I'm not sure this can be properly fixed. Are there cases in which an occurrence of
The discussion in #1646 (comment) seems to indicate that this should be valid. If this shouldn't trigger a warning, then it might be tricky to warn about cases like this:
Recognizing that The original discussion in #583 is rather inconclusive as well... The current state of the PR warns about these cases:
But will already fail to warn for this case:
So currently I'm not sure - it doesn't seem that we can warn in all cases that warrant a warning, but I'm not sure which subset of them I should try to catch... |
bf12e8e
to
96cabbe
Compare
Sorry, I think this is still not a good solution. I'll improve it now and comment after I'm done. |
@@ -152,6 +156,8 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) | |||
{ | |||
bool const v050 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); | |||
|
|||
m_memberAccess = true; |
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.
While it is nice that we can catch (this).f()
using this mechanism, I think it would also generate an error on f(this).f()
, which should in general not be the case. Constructors cannot have nested non-constructor functions, but a member access expression can, so I don't think this can be solved by using stateful AST traversal.
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 was exactly the problem I was just thinking about. However, "f(this).f()" does not seem to trigger the warning - I just added a test for that.
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.
Just trying to think of a case in which this will in fact fail.
Otherwise I could just check for this
in the member access again - either while also checking for (this)
or while ignoring cases like (this)
...
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.
Actually I expected test/libsolidity/syntaxTests/parsing/constructor_allowed_this.sol
to cause a warning because of this, but as a matter of fact it doesn't...
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.
Ah, ok, now I got one that fails - I'll revert back to checking in member access.
} | ||
|
||
function x() pure internal { | ||
require(false); |
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 reduce the test case to its bare minimum.
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.
And perhaps also add a comment that this tests a former bug in the detection of this.f()
.
96cabbe
to
5cafdfa
Compare
2da1350
to
7abe92c
Compare
24a0284
to
d2e1d14
Compare
Now it should be fine - although IMO it's not particularly nice this way. I'm really starting to think that we should consider #3878. |
if (auto id = dynamic_cast<Identifier const*>(expr)) | ||
{ | ||
if (id->name() == "this") | ||
m_errorReporter.warning(id->location(), "\"this\" used in constructor."); |
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.
Perhaps we should also extend the message a little: \"this\" used in constructor. Note that external functions of a contract cannot be called while it is being constructed.
or something like that.
d2e1d14
to
be37e3a
Compare
Fixes #3843.
Fixes #3861.