Skip to content

Commit

Permalink
fix: arithmetic virus isn't applied to expressions involing string li…
Browse files Browse the repository at this point in the history
…terals anymore (#18)

arithmetic virus isn't applied to strings anymore

Note that this is only a partial fix (#17),
as it only works if the binary expression involves a string literal. Two string variables
will still cause an unwanted mutation.
  • Loading branch information
Marcel Schramm authored Aug 17, 2023
1 parent 957d080 commit 1255479
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
33 changes: 33 additions & 0 deletions viruses/arithmetic/arithmetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ func (v *Arithmetic) Incubate(node ast.Node, _ *types.Info) []*viruses.Infection
return nil
}

// Go overloaded the + operator, meaning is not just used for
// arithmetic operations, so it needs to be ignored for strings.
if isString(expression.X) || isString(expression.Y) {
return nil
}

originalOperation := expression.Op

mutatedOperation, matches := v.mutations[expression.Op]
Expand All @@ -48,3 +54,30 @@ func (v *Arithmetic) Incubate(node ast.Node, _ *types.Info) []*viruses.Infection
),
}
}

func isString(expr ast.Expr) bool {
switch expr := expr.(type) {
case *ast.Ident:
// We need to get the type here, however, the `types` parameter
// is explicitly set to `nil` upon function invocation.
case *ast.BasicLit:
// Strings only support concatenation (+)
if expr.Kind == token.STRING {
return true
}
case *ast.CallExpr:
if expr, isIdentifier := expr.Fun.(*ast.Ident); isIdentifier {
// Make sure we have a builtin.
// Technically, we could encounter something like this:
//
// func string(b []byte) int {
// return len(b)
// }
if expr.Name == "string" && expr.Obj == nil {
return true
}
}
}

return false
}
3 changes: 2 additions & 1 deletion viruses/arithmetic/arithmetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ func TestArithmetic(t *testing.T) {
"Arithmetic",
arithmetic.New(),
oozetesting.Mutations{
"no mutations": {"source.0.go", []string{}},
"no mutations": {"source.0.go", []string{}},
"no mutation of string concatenation": {"source.7.go", []string{}},
"one mutation + to -": {"source.1.go", []string{
"source.2.go",
}},
Expand Down
37 changes: 37 additions & 0 deletions viruses/arithmetic/testdata/source.7.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//!go:build testdata

package source

func hello0() string {
x := "hello"
return "/" + x
}

func hello1() string {
x := "hello"
return x + "/"
}

func hello3() string {
x := "hello"
y := []byte("/")
return x + string(y)
}

// FIXME This still fails
// func hello2() string {
// x := "hello"
// y := "/"
// return x + y
// }

// FIXME This still fails
// func toString(b []byte) string {
// return string(x)
// }

// func hello4() string {
// x := "hello"
// y := []byte{"/"}
// return hello + toString(y)
// }

0 comments on commit 1255479

Please sign in to comment.