Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
Peter Lemenkov
f9a20c1edb Vyper ver. 0.4.1
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2025-03-03 09:37:02 +01:00
Peter Lemenkov
c492e40fd2 Fix for one more issue
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2025-02-27 15:52:15 +01:00
11 changed files with 21 additions and 384 deletions

2
.gitignore vendored
View file

@ -1 +1 @@
/vyper-0.4.0.tar.gz
/vyper-[0-9]*.[0-9]*.[0-9]*.tar.gz

View file

@ -1 +1 @@
SHA512 (vyper-0.4.0.tar.gz) = 0ad76740ba745a554ccbdc938a8f71a4df22bc9e459e645b128d1cfebcc54975e0941976874fc26196c9149c12e44bdb5d5be18ec2a9b0fecb31a2a9c530b98c
SHA512 (vyper-0.4.1.tar.gz) = 98d03ae6cd7d268b5292f52ac2b7a7b24e3250674a959afff1cc95ce17cde534416381c80e66d5a29c0b6e970557f5f6e52396e714abfd3c4bd745deb8a02cda

View file

@ -5,7 +5,7 @@ Subject: [PATCH] Use Cryptodomex
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
diff --git a/setup.py b/setup.py
index 6e48129c..e2b0688d 100644
index e6d4c576..28ba7ebd 100644
--- a/setup.py
+++ b/setup.py
@@ -92,7 +92,7 @@ setup(
@ -15,13 +15,13 @@ index 6e48129c..e2b0688d 100644
- "pycryptodome>=3.5.1,<4",
+ "pycryptodomex>=3.5.1,<4",
"packaging>=23.1,<24",
"lark>=1.0.0,<2",
"importlib-metadata",
"wheel",
diff --git a/vyper/utils.py b/vyper/utils.py
index 2b95485f..1968c281 100644
index d1327475..9e5f5863 100644
--- a/vyper/utils.py
+++ b/vyper/utils.py
@@ -184,7 +184,7 @@ decimal.setcontext(DecimalContextOverride(prec=78))
@@ -217,7 +217,7 @@ decimal.setcontext(DecimalContextOverride(prec=78))
try:

View file

@ -5,20 +5,21 @@ Subject: [PATCH] Ease version requirements
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
diff --git a/setup.py b/setup.py
index e2b0688d..82755981 100644
index 28ba7ebd..2dd2d9b9 100644
--- a/setup.py
+++ b/setup.py
@@ -93,11 +93,11 @@ setup(
@@ -93,12 +93,12 @@ setup(
"cbor2>=5.4.6,<6",
"asttokens>=2.0.5,<3",
"pycryptodomex>=3.5.1,<4",
- "packaging>=23.1,<24",
+ "packaging>=23.1",
"lark>=1.0.0,<2",
"importlib-metadata",
"wheel",
],
- setup_requires=["pytest-runner", "setuptools_scm>=7.1.0,<8.0.0"],
+ setup_requires=["pytest-runner", "setuptools_scm>=7.1.0"],
tests_require=extras_require["test"],
- setup_requires=["setuptools_scm>=7.1.0,<8.0.0"],
+ setup_requires=["setuptools_scm>=7.1.0"],
extras_require=extras_require,
entry_points={
"console_scripts": [

View file

@ -1,27 +1,19 @@
From: Peter Lemenkov <lemenkov@gmail.com>
Date: Thu, 25 Jul 2024 23:18:23 +0200
Subject: [PATCH] Lark should go to the main install section as it used not
only for tests
Subject: [PATCH] Relax lark dependency
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
diff --git a/setup.py b/setup.py
index 82755981..94477f03 100644
index 2dd2d9b9..0a3367ca 100644
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,6 @@ extras_require = {
@@ -15,7 +15,7 @@ extras_require = {
"pytest-split>=0.7.0,<1.0",
"eth_abi>=5.0.0,<6.0.0",
"py-evm>=0.10.1b1,<0.11",
- "lark==1.1.9",
+ "lark>=1.1.7",
"hypothesis[lark]>=6.0,<7.0",
"eth-stdlib==0.2.7",
"eth-account==0.12.2",
@@ -92,6 +91,7 @@ setup(
install_requires=[
"cbor2>=5.4.6,<6",
"asttokens>=2.0.5,<3",
+ "lark==1.1.9",
"pycryptodomex>=3.5.1,<4",
"packaging>=23.1",
"importlib-metadata",

View file

@ -1,19 +0,0 @@
From: Peter Lemenkov <lemenkov@gmail.com>
Date: Thu, 8 Aug 2024 20:33:53 +0200
Subject: [PATCH] Relax lark requirement (testing only anyway)
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
diff --git a/setup.py b/setup.py
index 94477f03..61cf2f76 100644
--- a/setup.py
+++ b/setup.py
@@ -91,7 +91,7 @@ setup(
install_requires=[
"cbor2>=5.4.6,<6",
"asttokens>=2.0.5,<3",
- "lark==1.1.9",
+ "lark>=1.1.7",
"pycryptodomex>=3.5.1,<4",
"packaging>=23.1",
"importlib-metadata",

View file

@ -1,51 +0,0 @@
From: Charles Cooper <cooper.charles.m@gmail.com>
Date: Sun, 23 Feb 2025 10:38:22 +0100
Subject: [PATCH] fix[lang]: define rounding mode for sqrt (#4486)
prior to this commit, the rounding mode for `sqrt()` is undefined,
which could be an issue for applications which use `sqrt()` to
determine boundary conditions. this commit ensures the result is
rounded down.
diff --git a/docs/built-in-functions.rst b/docs/built-in-functions.rst
index a0e424ad..6ac659bd 100644
--- a/docs/built-in-functions.rst
+++ b/docs/built-in-functions.rst
@@ -711,7 +711,7 @@ Math
.. py:function:: sqrt(d: decimal) -> decimal
- Return the square root of the provided decimal number, using the Babylonian square root algorithm.
+ Return the square root of the provided decimal number, using the Babylonian square root algorithm. The rounding mode is to round down to the nearest epsilon. For instance, ``sqrt(0.9999999998) == 0.9999999998``.
.. code-block:: vyper
diff --git a/tests/functional/codegen/types/numbers/test_sqrt.py b/tests/functional/codegen/types/numbers/test_sqrt.py
index cf62cecd..54b762c4 100644
--- a/tests/functional/codegen/types/numbers/test_sqrt.py
+++ b/tests/functional/codegen/types/numbers/test_sqrt.py
@@ -146,6 +146,10 @@ def test_sqrt_bounds(sqrt_contract, value):
)
@hypothesis.example(value=Decimal(SizeLimits.MAX_INT128))
@hypothesis.example(value=Decimal(0))
+# cf. GHSA-2p94-8669-xg86 for the following three examples:
+@hypothesis.example(value=Decimal("0.9999999998"))
+@hypothesis.example(value=Decimal("0.9999999997"))
+@hypothesis.example(value=Decimal("1.1000000000"))
def test_sqrt_valid_range(sqrt_contract, value):
vyper_sqrt = sqrt_contract.test(decimal_to_int(value))
actual_sqrt = decimal_sqrt(value)
diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py
index 672d9784..5c7e3a6a 100644
--- a/vyper/builtins/functions.py
+++ b/vyper/builtins/functions.py
@@ -2142,6 +2142,9 @@ else:
break
y = z
z = (x / z + z) / 2.0
+
+ if y < z:
+ z = y
"""
x_type = DecimalT()

View file

@ -1,73 +0,0 @@
From: Charles Cooper <cooper.charles.m@gmail.com>
Date: Sat, 22 Feb 2025 19:34:41 +0100
Subject: [PATCH] fix[codegen]: cache result of iter eval (#4488)
prior to this commit, multiple evaluation of a single expression is
possible in the iterator target of a for loop. while the iterator
expression cannot produce multiple writes, it can _consume_ side
effects produced in the loop body (e.g. read a storage variable
updated in the loop body) and thus lead to unexpected program
behavior. specifically, reads in iterators which contain an `IfExp`
(e.g. `for s: uint256 in ([read(), read()] if True else []))` would
issue one evaluation of the list `[read(), read()]` per loop iteration,
thus interleaving reads with writes in the loop body.
this commit fixes the issue by using `cache_when_complex` to enforce
evaluation of the iterator before entering the loop body.
this is incidentally also a performance fix, since it moves the
repeated evaluation into a one-time evaluation.
references:
- https://github.com/vyperlang/vyper/security/advisories/GHSA-h33q-mhmp-8p67
diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py
index 830f2f92..165252d5 100644
--- a/vyper/codegen/stmt.py
+++ b/vyper/codegen/stmt.py
@@ -267,20 +267,21 @@ class Stmt:
ret.append(make_setter(tmp_list, iter_list))
iter_list = tmp_list
- # set up the loop variable
- e = get_element_ptr(iter_list, i, array_bounds_check=False)
- body = ["seq", make_setter(loop_var, e), parse_body(self.stmt.body, self.context)]
-
- repeat_bound = iter_list.typ.count
- if isinstance(iter_list.typ, DArrayT):
- array_len = get_dyn_array_count(iter_list)
- else:
- array_len = repeat_bound
+ with iter_list.cache_when_complex("list_iter") as (b1, iter_list):
+ # set up the loop variable
+ e = get_element_ptr(iter_list, i, array_bounds_check=False)
+ body = ["seq", make_setter(loop_var, e), parse_body(self.stmt.body, self.context)]
+
+ repeat_bound = iter_list.typ.count
+ if isinstance(iter_list.typ, DArrayT):
+ array_len = get_dyn_array_count(iter_list)
+ else:
+ array_len = repeat_bound
- ret.append(["repeat", i, 0, array_len, repeat_bound, body])
+ ret.append(["repeat", i, 0, array_len, repeat_bound, body])
- del self.context.forvars[varname]
- return IRnode.from_list(ret)
+ del self.context.forvars[varname]
+ return b1.resolve(IRnode.from_list(ret))
def parse_AugAssign(self):
target = self._get_target(self.stmt.target)
diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py
index 26c6a4ef..909f5b7b 100644
--- a/vyper/semantics/analysis/local.py
+++ b/vyper/semantics/analysis/local.py
@@ -522,6 +522,7 @@ class FunctionAnalyzer(VyperNodeVisitorBase):
def _analyse_range_iter(self, iter_node, target_type):
# iteration via range()
if iter_node.get("func.id") != "range":
+ # CMC 2025-02-12 I think we can allow this actually
raise IteratorException("Cannot iterate over the result of a function call", iter_node)
_validate_range_call(iter_node)

View file

@ -1,210 +0,0 @@
From: Charles Cooper <cooper.charles.m@gmail.com>
Date: Sun, 23 Feb 2025 20:51:52 +0100
Subject: [PATCH] fix[codegen]: disable augassign with overlap (#4487)
in vyper, the behavior for AugAssign is to perform the bounds checks
only before evaluation of the rhs, rather than before-and-after. in
other words, the following code:
```vyper
def poc():
a: DynArray[uint256, 2] = [1, 2]
a[1] += a.pop()
```
is equivalent to:
```vyper
def poc():
a: DynArray[uint256, 2] = [1, 2]
a[1] += a[len(a) - 1]
a.pop()
```
rather than:
```vyper
def poc():
a: DynArray[uint256, 2] = [1, 2]
s: uint256 = a[1]
t: uint256 = a.pop()
a[1] = s + t # reverts due to oob access
```
this commit blocks the potentially missing bounds check by panicking
when there is a potential write on the rhs of an AugAssign which could
change the length on the lhs.
references:
- https://github.com/vyperlang/vyper/security/advisories/GHSA-4w26-8p97-f4jp
---------
Co-authored-by: cyberthirst <cyberthirst.eth@gmail.com>
diff --git a/tests/functional/codegen/features/test_assignment.py b/tests/functional/codegen/features/test_assignment.py
index eaafb527..53d02dfb 100644
--- a/tests/functional/codegen/features/test_assignment.py
+++ b/tests/functional/codegen/features/test_assignment.py
@@ -1,6 +1,6 @@
import pytest
-from vyper.exceptions import ImmutableViolation, InvalidType, TypeMismatch
+from vyper.exceptions import CodegenPanic, ImmutableViolation, InvalidType, TypeMismatch
def test_augassign(get_contract):
@@ -39,6 +39,135 @@ def augmod(x: int128, y: int128) -> int128:
print("Passed aug-assignment test")
+@pytest.mark.parametrize(
+ "source",
+ [
+ """
+@external
+def poc():
+ a: DynArray[uint256, 2] = [1, 2]
+ a[1] += a.pop()
+ """,
+ """
+a: DynArray[uint256, 2]
+
+def side_effect() -> uint256:
+ return self.a.pop()
+
+@external
+def poc():
+ self.a = [1, 2]
+ self.a[1] += self.side_effect()
+ """,
+ """
+a: DynArray[uint256, 2]
+
+def side_effect() -> uint256:
+ self.a = [1]
+ return 1
+
+@external
+def poc():
+ self.a = [1, 2]
+ self.a[1] += self.side_effect()
+ """,
+ """
+a: DynArray[uint256, 2]
+
+interface Foo:
+ def foo() -> uint256: nonpayable
+
+@external
+def foo() -> uint256:
+ return self.a.pop()
+
+@external
+def poc():
+ self.a = [1, 2]
+ # panics due to extcall
+ self.a[1] += extcall Foo(self).foo()
+ """,
+ ],
+)
+@pytest.mark.xfail(strict=True, raises=CodegenPanic)
+def test_augassign_oob(get_contract, tx_failed, source):
+ # xfail here (with panic):
+ c = get_contract(source)
+
+ # not reached until the panic is fixed
+ with tx_failed(c):
+ c.poc()
+
+
+@pytest.mark.parametrize(
+ "source",
+ [
+ """
+a: public(DynArray[uint256, 2])
+
+interface Foo:
+ def foo() -> uint256: view
+
+@external
+def foo() -> uint256:
+ return self.a[1]
+
+@external
+def entry() -> DynArray[uint256, 2]:
+ self.a = [1, 1]
+ # panics due to staticcall
+ self.a[1] += staticcall Foo(self).foo()
+ return self.a
+ """
+ ],
+)
+@pytest.mark.xfail(strict=True, raises=CodegenPanic)
+def test_augassign_rhs_references_lhs(get_contract, tx_failed, source):
+ # xfail here (with panic):
+ c = get_contract(source)
+
+ assert c.entry() == [1, 2]
+
+
+@pytest.mark.parametrize(
+ "source",
+ [
+ """
+@external
+def entry() -> DynArray[uint256, 2]:
+ a: DynArray[uint256, 2] = [1, 1]
+ a[1] += a[1]
+ return a
+ """,
+ """
+@external
+def entry() -> DynArray[uint256, 2]:
+ a: uint256 = 1
+ a += a
+ b: DynArray[uint256, 2] = [a, a]
+ b[0] -= b[0]
+ b[0] += b[1] // 2
+ return b
+ """,
+ """
+a: DynArray[uint256, 2]
+
+def read() -> uint256:
+ return self.a[1]
+
+@external
+def entry() -> DynArray[uint256, 2]:
+ self.a = [1, 1]
+ self.a[1] += self.read()
+ return self.a
+ """,
+ ],
+)
+def test_augassign_rhs_references_lhs2(get_contract, source):
+ c = get_contract(source)
+ assert c.entry() == [1, 2]
+
+
@pytest.mark.parametrize(
"typ,in_val,out_val",
[
diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py
index 165252d5..24391e27 100644
--- a/vyper/codegen/stmt.py
+++ b/vyper/codegen/stmt.py
@@ -293,6 +293,13 @@ class Stmt:
# single word load/stores are atomic.
raise TypeCheckFailure("unreachable")
+ for var in target.referenced_variables:
+ if var.typ._is_prim_word:
+ continue
+ # oob - GHSA-4w26-8p97-f4jp
+ if var in right.variable_writes or right.contains_risky_call:
+ raise CodegenPanic("unreachable")
+
with target.cache_when_complex("_loc") as (b, target):
left = IRnode.from_list(LOAD(target), typ=target.typ)
new_val = Expr.handle_binop(self.stmt.op, left, right, self.context)

View file

@ -1,8 +1,8 @@
%global git_commit e9db8d9f7486eae38f5b86531629019ad28f514e
%global git_commit 8a93dd27de503b0a3ace36d961a10c9ea4adee8b
Summary: Pythonic Smart Contract Language for the EVM
Name: vyper
Version: 0.4.0
Version: 0.4.1
Release: %autorelease
BuildArch: noarch
License: Apache-2.0
@ -10,12 +10,8 @@ URL: https://vyperlang.org
Source0: %{pypi_source %{name}}
Patch1: vyper-0001-Use-Cryptodomex.patch
Patch2: vyper-0002-Ease-version-requirements.patch
Patch3: vyper-0003-Lark-should-go-to-the-main-install-section-as-it-use.patch
Patch4: vyper-0004-Remove-unnecessary-shebang.patch
Patch5: vyper-0005-Relax-lark-requirement-testing-only-anyway.patch
Patch6: vyper-0006-fix-lang-define-rounding-mode-for-sqrt-4486.patch
Patch7: vyper-0007-fix-codegen-cache-result-of-iter-eval-4488.patch
Patch8: vyper-0008-fix-codegen-disable-augassign-with-overlap-4487.patch
Patch3: vyper-0003-Remove-unnecessary-shebang.patch
Patch4: vyper-0004-Relax-lark-dependency.patch
BuildRequires: git
BuildRequires: python3-cached_property
BuildRequires: python3-devel
@ -53,6 +49,7 @@ rm -f %{buildroot}/usr/vyper_git_commithash.txt
%files -f %{pyproject_files}
%doc README.md SECURITY.md
%{_bindir}/fang
%{_bindir}/venom
%{_bindir}/vyper
%{_bindir}/vyper-json