gnolang / gno

Gno: An interpreted, stack-based Go virtual machine to build succinct and composable apps + Gno.land: a blockchain for timeless code and fair open-source
https://gno.land/
Other
859 stars 348 forks source link

nil can be converted to invalid types (ie. int) #1341

Closed thehowl closed 6 months ago

thehowl commented 8 months ago

First discovered in https://github.com/gnolang/gno/pull/1177#issuecomment-1747914727 , I think I have forgotten to make an issue to track it separately.

Sample program:

package main

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

// Output: 0

int(nil) makes no sense and should not be accepted.

notJoon commented 8 months ago

I have written the following test:

package gnolang

func TestNilTypeConversion(t *testing.T) {
    m := NewMachine("test", nil)
    testCases := []struct {
        name string
        code string
    }{
        {
            name: "NilToInt",
            code: `package test
            func main(){
                println(int(nil))
            }`,
        },
       // converting to bool, and other types
    }

    for _, tc := range testCases {
        t.Run(tc.name, function(t *testing.T) {
            n := MustParseFile("main.go", tc.code)
            defer func() {
                if r := recover(); r != nil {
                    t.Logf("Recovered from panic as expected: %v", r)
                } else {
                    t.Errorf("Expected a panic for invalid type conversion")
                }
            }()
            m.RunFiles(n)
            m.RunMain()

            if err := m.CheckEmpty(); err != nil {
                t.Fatal(err)
            }
        })
    }
}

If the code is not changed, no error occurs and the test fails. However, if you make a panic in ConvertTo as below, the test passes.

    if tv.IsUndefined() {
+       panic(fmt.Sprintf(
+           "error: cannot convert undefined to %s",
+           t.String()))
-       tv.T = t
-       return
    }

It seems like the problem arises when a nil value is entered as undefined and then converted to a default type. My guess is, the issue could be resolved by preventing type conversion if tv.T is nil or modify the IsUndefined function.

But I'm still not sure, so I'll have to dig more 🤔🤔