-
-
Notifications
You must be signed in to change notification settings - Fork 804
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
fix: guard against mutating code in non-mutable functions #3555
Changes from 6 commits
161928a
f112bee
acec274
c7c7d37
bf58e4e
da88fe4
199eece
65b5384
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
from vyper import ast as vy_ast | ||
from vyper.exceptions import StructureException, TypeCheckFailure | ||
from vyper.exceptions import StateAccessViolation, StructureException, TypeCheckFailure | ||
from vyper.semantics.analysis.utils import ( | ||
get_common_types, | ||
get_exact_type_from_node, | ||
get_expr_info, | ||
get_possible_types_from_node, | ||
) | ||
from vyper.semantics.types import TYPE_T, BoolT, EnumT, EventT, SArrayT, StructT, is_type_t | ||
from vyper.semantics.types.function import ContractFunctionT, MemberFunctionT | ||
from vyper.semantics.types.function import ContractFunctionT, MemberFunctionT, StateMutability | ||
Check notice Code scanning / CodeQL Cyclic import Note
Import of module
vyper.semantics.types.function Error loading related location Loading |
||
|
||
|
||
class _AnnotationVisitorBase: | ||
|
@@ -136,6 +137,23 @@ | |
self.visit(node.func) | ||
|
||
if isinstance(call_type, ContractFunctionT): | ||
if ( | ||
call_type.mutability > StateMutability.VIEW | ||
and self.func.mutability <= StateMutability.VIEW | ||
): | ||
raise StateAccessViolation( | ||
f"Cannot call a mutating function from a {self.func.mutability.value} function", | ||
node, | ||
) | ||
|
||
if ( | ||
self.func.mutability == StateMutability.PURE | ||
and call_type.mutability != StateMutability.PURE | ||
): | ||
raise StateAccessViolation( | ||
"Cannot call non-pure function from a pure function", node | ||
) | ||
|
||
# function calls | ||
if call_type.is_internal: | ||
self.func.called_functions.add(call_type) | ||
|
@@ -157,10 +175,30 @@ | |
): | ||
self.visit(value, arg_type) | ||
elif isinstance(call_type, MemberFunctionT): | ||
if call_type.is_modifying: | ||
# it's a dotted function call like dynarray.pop() | ||
expr_info = get_expr_info(node.func.value) | ||
expr_info.validate_modification(node, self.func.mutability) | ||
|
||
assert len(node.args) == len(call_type.arg_types) | ||
for arg, arg_type in zip(node.args, call_type.arg_types): | ||
self.visit(arg, arg_type) | ||
else: | ||
# note that mutability for`raw_call` is handled in its `build_IR` function | ||
mutable_builtins = ( | ||
"create_minimal_proxy_to", | ||
"create_copy_of", | ||
"create_from_blueprint", | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is an overlap here with #3546 (comment). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option here could be to check constancy of the context in |
||
if ( | ||
self.func.mutability <= StateMutability.VIEW | ||
and node.get("func.id") in mutable_builtins | ||
): | ||
raise StateAccessViolation( | ||
f"Cannot call a mutating builtin from a {self.func.mutability.value} function", | ||
node, | ||
) | ||
|
||
# builtin functions | ||
arg_types = call_type.infer_arg_types(node) | ||
for arg, arg_type in zip(node.args, arg_types): | ||
|
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 test now throws for its other issue of call violation, which is checked first in
visit_Expr
. Hence, I removed it as there are already tests for call violation in this file.