Skip to content
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: handle untyped constant expressions in append() #1177

Merged
merged 9 commits into from
Jan 10, 2024

Conversation

mvertes
Copy link
Contributor

@mvertes mvertes commented Sep 27, 2023

This is a particular case of Go append builtin where the array type is inferred from the first argument. We detect an untyped const passed as argument, then we convert it to the array type prior to proceed further. It fixes further consistency checks and value generation.

Fixes #1136, fixes #1149, fixes #1341.

Contributors' checklist...
  • Added new tests, or not needed, or not feasible
  • Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory
  • Updated the official documentation or not needed
  • No breaking changes were made, or a BREAKING CHANGE: xxx message was included in the description
  • Added references to related issues and PRs
  • Provided any useful hints for running manual tests
  • Added new benchmarks to generated graphs, if any. More info here.

This is a particular case of Go append builtin where the array
type is inferred from the first argument. We detect using untyped
nil as argument, then we convert it to the array type prior to
proceeed further. It fixes further consistency checks and value
generation.

Fixes gnolang#1136.
@mvertes mvertes requested review from jaekwon, moul and a team as code owners September 27, 2023 07:57
@github-actions github-actions bot added the 📦 🤖 gnovm Issues or PRs gnovm related label Sep 27, 2023
@codecov
Copy link

codecov bot commented Sep 27, 2023

Codecov Report

Attention: 5 lines in your changes are missing coverage. Please review.

Comparison is base (568a087) 56.08% compared to head (04614ec) 55.84%.

Files Patch % Lines
gnovm/pkg/gnolang/preprocess.go 83.33% 2 Missing and 1 partial ⚠️
gnovm/pkg/gnolang/values_conversions.go 33.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1177      +/-   ##
==========================================
- Coverage   56.08%   55.84%   -0.24%     
==========================================
  Files         432      431       -1     
  Lines       65989    65768     -221     
==========================================
- Hits        37007    36728     -279     
- Misses      26094    26166      +72     
+ Partials     2888     2874      -14     
Flag Coverage Δ
go-1.21.x ∅ <ø> (∅)
misc ∅ <ø> (∅)
misc-_test.genstd ∅ <ø> (∅)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mvertes mvertes marked this pull request as draft September 27, 2023 08:14
@mvertes
Copy link
Contributor Author

mvertes commented Sep 27, 2023

Seeing if I can make the fix even more generic and also handle any untyped constant value, as to fix also #1149.

@mvertes mvertes marked this pull request as ready for review September 27, 2023 10:27
@mvertes mvertes changed the title fix: append nil to an array was causing a panic fix: handle untyped constant expressions in append() Sep 27, 2023
@moul moul requested a review from piux2 October 2, 2023 15:48
Copy link
Member

@moul moul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, @piux2 can you make a complementary review, please?

@tbruyelle
Copy link
Contributor

Does that also fix the bug we had on gnochess #1170 ?

Note that to reproduce it, you need to broadcast multiple tx, so the current test system in tests/files cannot be used.

Copy link
Member

@thehowl thehowl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👏

gnovm/pkg/gnolang/preprocess.go Outdated Show resolved Hide resolved
@thehowl
Copy link
Member

thehowl commented Oct 4, 2023

Does that also fix the bug we had on gnochess #1170 ?

Not as far as I can see, alas. This is specifically tackling constant expressions in append; #1170 is about the internal pointers not being fixed with appends.

@piux2
Copy link
Contributor

piux2 commented Oct 5, 2023

@thehowl, @moul,

Issue #1136 and issue #1149 are rooted in different issues.

Regarding #1136:
In Go, it's not permissible to append a nil to concrete types like []int. In the test case discussed, error is a built-in interface type. In Go, the default zero value for an interface type is nil, so it's allowable to append a nil to a slice of type []error. However, the behavior described in issue #1149 is different. If one attempts to append a nil to []int, it should, and typically does, cause a panic. Notably, after this fix, this panic no longer occurs when appending a nil to []int.

For #1149:
As the error message hinted. The core of the problem lies in converting variadic generic type arguments into a slice before they are passed into the append function. It's important to note that this issue isn't exclusive to append but also impacts any function that accepts variadic generic type arguments.

We will need to dig more and fix it at the root.

@thehowl
Copy link
Member

thehowl commented Oct 5, 2023

In Go, it's not permissible to append a nil to concrete types like []int. In the test case discussed, error is a built-in interface type. In Go, the default zero value for an interface type is nil, so it's allowable to append a nil to a slice of type []error. However, the behavior described in issue #1149 is different. If one attempts to append a nil to []int, it should, and typically does, cause a panic. Notably, after this fix, this panic no longer occurs when appending a nil to []int.

I was surprised to find out you're right (because it seemed to me that this PR didn't special-case nil):

package main

func main() {
        var ints []int
        ints = append(ints, nil, nil)
        println(ints)
}

// Output: slice[(0 int),(0 int)]

This executes, albeit incorrectly. However, this is actually a phenomenon caused by a root issue: we allow converting nil to int (and presumably other types):

package main

func main() {
        println(int(nil))
}

// Output: 0

I think the approach @mvertes has used is correct (given append([]T, T...), attempt to convert the variadic args into T before appending). However, we suffer a different problem about nil, thus allowing to do what you mentioned (appending nil to a slice of ints).

As the error message hinted. The core of the problem lies in converting variadic generic type arguments into a slice before they are passed into the append function. It's important to note that this issue isn't exclusive to append but also impacts any function that accepts variadic generic type arguments.

This one, empirically, does not check out (for the last statement). Try this one, and playing out with changing it (from master):


func main() {
	var n []int
	x := 2
	vari(n, 1, x)
}

func vari(n []int, params ...interface{}) {}

It's append which is special in this case.

@piux2
Copy link
Contributor

piux2 commented Oct 5, 2023

Does that also fix the bug we had on gnochess #1170 ?

Note that to reproduce it, you need to broadcast multiple tx, so the current test system in tests/files cannot be used.

For issue #1170, the root cause is located in realm.go, the underlying problem arises from the underlying array of the slice not being marked as "dirty" during the persistence of a realm object when that object is assigned to itself. I'm still evaluating the issue to identify an optimal solution.

@piux2
Copy link
Contributor

piux2 commented Oct 5, 2023

@moul

LGTM, @piux2 can you make a complementary review, please?

Yes, done

@piux2
Copy link
Contributor

piux2 commented Oct 5, 2023

I think here is the right place to fix #1149

vargt = varg.T

and add following condition:

	+ if isUntyped(varg.T) {
        +   vargt =	defaultTypeOf(varg.T)
	+ }else{
			vargt = varg.T
	 + }

@piux2
Copy link
Contributor

piux2 commented Oct 5, 2023

We will have further discussion and update the changes

piux2
piux2 previously requested changes Oct 6, 2023
Copy link
Contributor

@piux2 piux2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will dig further

mvertes and others added 3 commits November 29, 2023 15:41
This is done in ConverTo, so hopefully it works both at parsing
and during execution, and for composite types.

Some additional test cases have been added too.
@mvertes
Copy link
Contributor Author

mvertes commented Nov 30, 2023

@piux2 I examined and tried your suggestion to apply vargt = defaultTypeOf(varg.T), and I finally decided to change ConvertTo instead, which is necessary anyway and allows to catch invalid conversions not only at preprocessing, but also during execution (if nil is passed as value to convert).

@thehowl
Copy link
Member

thehowl commented Dec 7, 2023

@mvertes, since you commented on #1347, can you add a test like the one in #1341 to verify that nil conversions now fail correctly when they should?

@zivkovicmilos
Copy link
Member

@piux2
Ping for unblocking this PR

@jaekwon
Copy link
Contributor

jaekwon commented Dec 21, 2023

LGTM

@github-actions github-actions bot added the 🧾 package/realm Tag used for new Realms or Packages. label Jan 10, 2024
@thehowl
Copy link
Member

thehowl commented Jan 10, 2024

@mvertes I've made a small commit to address the comment by Jae. Then I noticed a small chance for optimisation (re-using the result of Call), then I also fixed some tests that was failing on the CI :)

If the changes look good to you, please merge. The code's been reviewed by Jae, if there are further changes requested they can be made in a separate PR :)

@mvertes
Copy link
Contributor Author

mvertes commented Jan 10, 2024

@piux2 ping

@thehowl thehowl dismissed piux2’s stale review January 10, 2024 13:16

Jae reviewed and approved this. Agreed with Milos to merge it as it fixes a number of Gno issues. If you have further comments, feel free to open a new PR or issue

@thehowl thehowl merged commit 2a2dcdc into gnolang:master Jan 10, 2024
187 of 189 checks passed
@mvertes mvertes deleted the fix/append-nil branch January 10, 2024 16:44
@piux2
Copy link
Contributor

piux2 commented Jan 10, 2024

@piux2 ping

@mvertes sorry, I thought it was already approved

@thehowl thank you.

gfanton pushed a commit to moul/gno that referenced this pull request Jan 18, 2024
This is a particular case of Go append builtin where the array type is
inferred from the first argument. We detect an untyped const passed as
argument, then we convert it to the array type prior to proceed further.
It fixes further consistency checks and value generation.

Fixes gnolang#1136, fixes gnolang#1149, fixes gnolang#1341.

<!-- please provide a detailed description of the changes made in this
pull request. -->

<details><summary>Contributors' checklist...</summary>

- [x] Added new tests, or not needed, or not feasible
- [x] Provided an example (e.g. screenshot) to aid review or the PR is
self-explanatory
- [x] Updated the official documentation or not needed
- [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message
was included in the description
- [x] Added references to related issues and PRs
- [ ] Provided any useful hints for running manual tests
- [ ] Added new benchmarks to [generated
graphs](https://gnoland.github.io/benchmarks), if any. More info
[here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
</details>

---------

Co-authored-by: Morgan <[email protected]>
Co-authored-by: Morgan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 🤖 gnovm Issues or PRs gnovm related 🧾 package/realm Tag used for new Realms or Packages.
Projects
Status: 🚀 Needed for Launch
Archived in project
8 participants