Skip to content

Commit

Permalink
test: fuzz gnovm/pkg/gnolang Machine.doOpEval for BasicLitExpr
Browse files Browse the repository at this point in the history
Fuzzing for BasicLitExpr and equivalence comparisons
for if those values parse in Go.

Updates #3087
  • Loading branch information
odeke-em committed Jan 10, 2025
1 parent 2438505 commit 1e50af3
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 0 deletions.
115 changes: 115 additions & 0 deletions gnovm/pkg/gnolang/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package gnolang

import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"

"github.com/cockroachdb/apd/v3"
)
Expand Down Expand Up @@ -87,3 +92,113 @@ func FuzzParseFile(f *testing.F) {
_, _ = ParseFile("a.go", goFileContents)
})
}

func FuzzDoOpEvalBaseConversion(f *testing.F) {
if testing.Short() {
f.Skip("Skipping in -short mode")
}

// 1. Add the seeds.
seeds := []*BasicLitExpr{
{Kind: INT, Value: "9223372036854775807"},
{Kind: INT, Value: "0"},
{Kind: INT, Value: "0777"},
{Kind: INT, Value: "0xDEADBEEF"},
{Kind: INT, Value: "0o123"},
{Kind: INT, Value: "0b111111111111111111111111111111111111111111111111111111111111111"},
{Kind: FLOAT, Value: "0.00001111"},
{Kind: FLOAT, Value: "9999.12"},
{Kind: STRING, Value: `"9999.12"`},
{Kind: STRING, Value: `"aaaaaaaaaaa "`},
{Kind: STRING, Value: `"🚨🌎"`},
}

for _, seed := range seeds {
blob, err := json.Marshal(seed)
if err != nil {
panic(err)
}
f.Add(blob)
}

// 2. Fuzz it.
f.Fuzz(func(t *testing.T, basicLitExprBlob []byte) {
expr := new(BasicLitExpr)
if err := json.Unmarshal(basicLitExprBlob, expr); err != nil {
return
}

m := NewMachine("test", nil)

defer func() {
r := recover()
if r == nil {
return
}

s := fmt.Sprintf("%s", r)
switch {
case strings.Contains(s, "unexpected lit kind"):
return

case strings.Contains(s, "unexpected decimal/float format"):
if strings.Contains(s, "/") {
return
}
fallthrough
case strings.Contains(s, "invalid integer constant"):
if containsAny(s, "+", "-", "*", "/", "%", "&", "|", "||") {
return
}
fallthrough
default:
if !basicLitExprIsValidGoValue(t, expr) {
return
}

if expr.Kind != STRING {
trimmed := strings.TrimSpace(expr.Value)
if trimmed != expr.Value {
expr.Value = trimmed
m := NewMachine("test", nil)
m.PushExpr(expr)
m.doOpEval()
_ = m.PopValue()
return
}
}

panic(r)
}
}()

m.PushExpr(expr)
m.doOpEval()
_ = m.PopValue()
})
}

func containsAny(s string, symbols ...string) bool {
for _, sym := range symbols {
if strings.Contains(s, sym) {
return true
}
}
return false
}

func basicLitExprIsValidGoValue(t *testing.T, lit *BasicLitExpr) bool {

Check failure on line 190 in gnovm/pkg/gnolang/fuzz_test.go

View workflow job for this annotation

GitHub Actions / Run GnoVM suite / Go Lint / lint

test helper function should start from t.Helper() (thelper)
tempDir := t.TempDir()
file := filepath.Join(tempDir, "basic_lit_check.go")
var craftedGo = []byte(fmt.Sprintf(`package main
const _ %s = %s
func main() {}`, strings.ToLower(lit.Kind.String()), lit.Value))
if err := os.WriteFile(file, craftedGo, 0755); err != nil {
panic(err)
}

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := exec.CommandContext(ctx, "go", "run", file).Run()
return err == nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("{\"Line\":0,\"Column\":0,\"Label\":\"\",\"Kind\":3,\"Value\":\"0/00001111\"}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("{}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
go test fuzz v1
[]byte("{\"Kind\":2}")

0 comments on commit 1e50af3

Please sign in to comment.