forked from vyperlang/vyper
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix[lang]: fix
uses
analysis for nonreentrant functions (vyperlang#…
…3927) `uses` analysis ignores nonreentrant functions, even though those that (implicitly) use state. this commit adds checks both for internally (called) and external (exported) modules misc/refactor: - factor out `uses_state()` util - rename `validate_functions` to more accurate `analyze_functions` - improve locality of exceptions thrown in check_module_uses
- Loading branch information
1 parent
7db4f87
commit bb1e03b
Showing
8 changed files
with
190 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
def test_export_nonreentrant(make_input_bundle, get_contract, tx_failed): | ||
lib1 = """ | ||
interface Foo: | ||
def foo() -> uint256: nonpayable | ||
implements: Foo | ||
@external | ||
@nonreentrant | ||
def foo() -> uint256: | ||
return 5 | ||
""" | ||
main = """ | ||
import lib1 | ||
initializes: lib1 | ||
exports: lib1.foo | ||
@external | ||
@nonreentrant | ||
def re_enter(): | ||
extcall lib1.Foo(self).foo() # should always throw | ||
@external | ||
def __default__(): | ||
# sanity: make sure we don't revert due to bad selector | ||
pass | ||
""" | ||
|
||
input_bundle = make_input_bundle({"lib1.vy": lib1}) | ||
|
||
c = get_contract(main, input_bundle=input_bundle) | ||
assert c.foo() == 5 | ||
with tx_failed(): | ||
c.re_enter() | ||
|
||
|
||
def test_internal_nonreentrant(make_input_bundle, get_contract, tx_failed): | ||
lib1 = """ | ||
interface Foo: | ||
def foo() -> uint256: nonpayable | ||
implements: Foo | ||
@external | ||
def foo() -> uint256: | ||
return self._safe_fn() | ||
@internal | ||
@nonreentrant | ||
def _safe_fn() -> uint256: | ||
return 10 | ||
""" | ||
main = """ | ||
import lib1 | ||
initializes: lib1 | ||
exports: lib1.foo | ||
@external | ||
@nonreentrant | ||
def re_enter(): | ||
extcall lib1.Foo(self).foo() # should always throw | ||
@external | ||
def __default__(): | ||
# sanity: make sure we don't revert due to bad selector | ||
pass | ||
""" | ||
|
||
input_bundle = make_input_bundle({"lib1.vy": lib1}) | ||
|
||
c = get_contract(main, input_bundle=input_bundle) | ||
assert c.foo() == 10 | ||
with tx_failed(): | ||
c.re_enter() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
NONREENTRANT_NOTE = ( | ||
"\n note that use of the `@nonreentrant` decorator is also considered state access" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.