-
-
Notifications
You must be signed in to change notification settings - Fork 788
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
Cannot post events after create an uninitialized local variable #1476
Comments
To prove that theory, could you move line 92 to just before line 80, and modify line 80 to be It does indeed seem strange to be encountering this behavior |
What's the syntax again? I tried |
You either have to type out all the zeros, use |
Yep, when explicitly setting |
Not sure why this creates exceptional behavior, but I agree it definitely shouldn't be doing that. |
I'm having trouble reproducing this failure. I checked out ethereum/consensus-specs@abe48cc , moved line 92 to be line 80 (put it just before the uninitialized The failure is because the ABIs don't match due to the gas estimates being different. That in itself is weird and I'm trying to understand what's going on there, but is that related to the issues you were having? My guess is not. |
@JustinDrake Do you have a link to a failing build job or something that would make it a bit clearer how things are failing for you? |
@davesque Can you also show the output of |
Alright, here's what I'm getting. And I'm guessing this is the error you're seeing:
|
Yep, that's the error! :) (Note that the error changes every time because there is some randomisation.) |
@JustinDrake Yeah, I did notice that. Thanks for the help. |
@JustinDrake does #1484 fix the issue for you? |
but also, uninitialized variables are not guaranteed to refer to zeroed memory. so maybe we should disallow declaring variables without initializing them. |
👍 this |
Or always set new variables to 0. I'm open to either TBH - let's discuss at next meeting? |
Agreed, but forcing the user to set is more explicit and clear and avoids this condition entirely. Could optimize out the write if it is provable that no read occurs before write. |
So uninitialised variables are not guaranteed for now to have default initial values as the documentation seems to suggest here: https://vyper.readthedocs.io/en/latest/types.html#initial-values? |
Yeah, it seems that was an oversight. |
@charles-cooper this feels like a bug, when is memory not zeroed/initialised ? |
I think after a call to a private function as you suspected in #1493 (comment). There could be something else going on but I inspected the IR and didn't see set to 0 for new variables that are declared after return from private. |
Yip we should fix that, for Basetypes it should be relatively easy. Dynamic types will be slightly more work, as we need zero the whole range. |
It doesn't seem like this is the right answer then. Shouldn't whatever solution we come up with avoid the need to set dynamic types, which will be needlessly expensive? |
It's quite of an edge case that I don't think it should be too much of a problem, defining large dynamic types in the EVM will always be costly. |
@jacqueswww I'm trying to remember if the zero by default behavior applies to the EVM memory in addition to the storage. If that were the case, wouldn't uninitialized variables already be zeroed assuming the memory counter is incremented to accommodate them? I'm poking through the spec right now trying to see if this is the case. I'm also a bit out of context here so feel free to correct me. |
Are memory positions re-used across the execution of a method call? If so, then I can understand the trouble. |
@davesque Yes that is true, but this occurs after a local call was made - which re-uses the same memory. |
@davesque just looking at the exception above further, @public
@constant
def get_deposit_root() -> bytes32:
node: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000
size: uint256 = self.deposit_count
for height in range(DEPOSIT_CONTRACT_TREE_DEPTH):
if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1`
node = sha256(concat(self.branch[height], node))
else:
node = sha256(concat(node, self.zero_hashes[height]))
size /= 2
return node This is the function that fails? Or is this the fixed code? |
@jacqueswww Yeah, it's a bit confusing to reproduce. I made a fork with a commit that shows the failure. Here's how you can access it: git clone https://github.com/davesque/eth2.0-specs/
cd eth2.0-specs
git checkout with-failure
make install_deposit_contract_test
make compile_deposit_contract
make test_deposit_contract The |
@jacqueswww Here's the actual commit that causes the failure: davesque/eth2.0-specs@1c2858f |
I think many of the people involved in this discussion are already aware of this, but for posterity here's a comment I just posted with more information about what I think is happening here: #1493 (comment) |
There might be something else going on here too because I'm not sure the frame of the private function in this issue is that large to overwrite callee memory. But I did notice that the newly declared variable is not zeroed in the IR as I mentioned above, and the fact that explicitly setting the new variable fixes the issue is pretty telling. |
The key is to make sure the memory is allocated and registered with the context variable BEFORE evaluating the expressions inside the event (in case any of them make internal calls) fixes vyperlang#1476
The key is to make sure the memory is allocated and registered with the context variable BEFORE evaluating the expressions inside the event (in case any of them make internal calls) fixes vyperlang#1476
Should be fixed in be42f18. The issue was that the buffer for the encoded data was allocated AFTER the code to call the internal functions was evaluated. So the code to save the current call frame knows nothing about the encoded buffer, and then the internal function is free to clobber the buffer. |
When working with the Eth2 deposit contract I noticed a strange behaviour which I presume is a compiler bug.
Notice that the tests pass in ethereum/consensus-specs@abe48cc (the command to run the tests is
make compile_deposit_contract; make test_deposit_contract
) but fail if you move line 92 (theDeposit
log) to line 80 the tests fail when nothing has really changed. I haven't had time to debug it but my guess would be that that it has something to do withzero_bytes32: bytes32
, possibly that junk is being written to it.The text was updated successfully, but these errors were encountered: