diff --git a/configure.ac b/configure.ac index 6c9cfca58ed..0dd7a6d45bc 100755 --- a/configure.ac +++ b/configure.ac @@ -753,6 +753,7 @@ AC_CONFIG_FILES([ lib/erl/Makefile lib/go/Makefile lib/go/test/Makefile + lib/go/test/fuzz/Makefile lib/haxe/test/Makefile lib/java/Makefile lib/js/Makefile diff --git a/lib/go/Makefile.am b/lib/go/Makefile.am index 0dfa5fadca7..2971cfd24a0 100644 --- a/lib/go/Makefile.am +++ b/lib/go/Makefile.am @@ -20,7 +20,7 @@ SUBDIRS = . if WITH_TESTS -SUBDIRS += test +SUBDIRS += test test/fuzz endif install: diff --git a/lib/go/test/fuzz/Makefile.am b/lib/go/test/fuzz/Makefile.am new file mode 100644 index 00000000000..41f8b45b506 --- /dev/null +++ b/lib/go/test/fuzz/Makefile.am @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +gopathfuzz: $(THRIFT) fuzz.go + $(THRIFT) -r --gen go ../../../../tutorial/tutorial.thrift + GO111MODULE=on go mod init fuzz + GO111MODULE=on cd gen-go/shared && go mod init shared + GO111MODULE=on cd gen-go/tutorial && go mod init tutorial + GO111MODULE=on go mod edit -replace shared=./gen-go/shared + GO111MODULE=on go mod edit -replace tutorial=./gen-go/tutorial + GO111MODULE=on cd ../../../../lib/go/thrift && go mod init github.com/apache/thrift/lib/go/thrift + GO111MODULE=on go mod edit -replace github.com/apache/thrift/lib/go/thrift=../../../../lib/go/thrift + GO111MODULE=on go mod tidy + touch gopathfuzz + +check: gopathfuzz + go test -tags gofuzz + +clean-local: + $(RM) -r gopathfuzz gen-go + diff --git a/lib/go/test/fuzz/fuzz.go b/lib/go/test/fuzz/fuzz.go new file mode 100644 index 00000000000..388524ccc5e --- /dev/null +++ b/lib/go/test/fuzz/fuzz.go @@ -0,0 +1,143 @@ +// +build gofuzz + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package fuzz + +import ( + "context" + "fmt" + "shared" + "strconv" + "tutorial" + + "github.com/apache/thrift/lib/go/thrift" +) + +const nbFuzzedProtocols = 2 + +func fuzzChooseProtocol(d byte, t thrift.TTransport) thrift.TProtocol { + switch d % nbFuzzedProtocols { + default: + fallthrough + case 0: + return thrift.NewTBinaryProtocolFactoryConf(nil).GetProtocol(t) + case 1: + return thrift.NewTCompactProtocolFactoryConf(nil).GetProtocol(t) + } +} + +func Fuzz(data []byte) int { + if len(data) < 2 { + return 0 + } + inputTransport := thrift.NewTMemoryBuffer() + inputTransport.Buffer.Write(data[2:]) + outputTransport := thrift.NewTMemoryBuffer() + outputProtocol := fuzzChooseProtocol(data[0], outputTransport) + inputProtocol := fuzzChooseProtocol(data[1], inputTransport) + ctx := thrift.SetResponseHelper( + context.Background(), + thrift.TResponseHelper{ + THeaderResponseHelper: thrift.NewTHeaderResponseHelper(outputProtocol), + }, + ) + handler := NewCalculatorHandler() + processor := tutorial.NewCalculatorProcessor(handler) + ok := true + var err error + for ok { + ok, err = processor.Process(ctx, inputProtocol, outputProtocol) + if err != nil { + // Handle parse error + return 0 + } + res := make([]byte, 1024) + n, err := outputTransport.Buffer.Read(res) + fmt.Printf("lol %d %s %v\n", n, err, res) + } + return 1 +} + +type CalculatorHandler struct { + log map[int]*shared.SharedStruct +} + +func NewCalculatorHandler() *CalculatorHandler { + return &CalculatorHandler{log: make(map[int]*shared.SharedStruct)} +} + +func (p *CalculatorHandler) Ping(ctx context.Context) (err error) { + fmt.Print("ping()\n") + return nil +} + +func (p *CalculatorHandler) Add(ctx context.Context, num1 int32, num2 int32) (retval17 int32, err error) { + fmt.Print("add(", num1, ",", num2, ")\n") + return num1 + num2, nil +} + +func (p *CalculatorHandler) Calculate(ctx context.Context, logid int32, w *tutorial.Work) (val int32, err error) { + fmt.Print("calculate(", logid, ", {", w.Op, ",", w.Num1, ",", w.Num2, "})\n") + switch w.Op { + case tutorial.Operation_ADD: + val = w.Num1 + w.Num2 + break + case tutorial.Operation_SUBTRACT: + val = w.Num1 - w.Num2 + break + case tutorial.Operation_MULTIPLY: + val = w.Num1 * w.Num2 + break + case tutorial.Operation_DIVIDE: + if w.Num2 == 0 { + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Cannot divide by 0" + err = ouch + return + } + val = w.Num1 / w.Num2 + break + default: + ouch := tutorial.NewInvalidOperation() + ouch.WhatOp = int32(w.Op) + ouch.Why = "Unknown operation" + err = ouch + return + } + entry := shared.NewSharedStruct() + entry.Key = logid + entry.Value = strconv.Itoa(int(val)) + k := int(logid) + p.log[k] = entry + return val, err +} + +func (p *CalculatorHandler) GetStruct(ctx context.Context, key int32) (*shared.SharedStruct, error) { + fmt.Print("getStruct(", key, ")\n") + v, _ := p.log[int(key)] + return v, nil +} + +func (p *CalculatorHandler) Zip(ctx context.Context) (err error) { + fmt.Print("zip()\n") + return nil +} diff --git a/lib/go/test/fuzz/fuzz_test.go b/lib/go/test/fuzz/fuzz_test.go new file mode 100644 index 00000000000..2983e0ff3b3 --- /dev/null +++ b/lib/go/test/fuzz/fuzz_test.go @@ -0,0 +1,30 @@ +// +build gofuzz + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package fuzz + +import ( + "testing" +) + +func TestFuzz(t *testing.T) { + Fuzz([]byte{1, 2, 3}) +}