fix: a race when reusing flatbuffers.Builder (#35)
diff --git a/internal/server/server.go b/internal/server/server.go
index 890997f..720df4d 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -45,18 +45,14 @@
dealRPCTest func(buf []byte) (*flatbuffers.Builder, error)
)
-func generateErrorReport(err error) (ty byte, out []byte) {
+func generateErrorReport(err error) *flatbuffers.Builder {
if err == ttlcache.ErrNotFound {
log.Warnf("%s", err)
} else {
log.Errorf("%s", err)
}
- ty = util.RPCError
- bd := ReportError(err)
- out = bd.FinishedBytes()
- util.PutBuilder(bd)
- return
+ return ReportError(err)
}
func recoverPanic() {
@@ -65,7 +61,7 @@
}
}
-func dispatchRPC(ty byte, in []byte, conn net.Conn) (byte, []byte) {
+func dispatchRPC(ty byte, in []byte, conn net.Conn) (*flatbuffers.Builder, error) {
var err error
var bd *flatbuffers.Builder
switch ty {
@@ -78,21 +74,18 @@
default:
err = UnknownType{ty}
}
+ return bd, err
+}
- var out []byte
- if err != nil {
- ty, out = generateErrorReport(err)
- } else {
- out = bd.FinishedBytes()
+func checkIfDataTooLarge(bd *flatbuffers.Builder) *flatbuffers.Builder {
+ out := bd.FinishedBytes()
+ size := len(out)
+ if size > util.MaxDataSize {
+ err := fmt.Errorf("the max length of data is %d but got %d", util.MaxDataSize, size)
util.PutBuilder(bd)
- size := len(out)
- if size > util.MaxDataSize {
- err = fmt.Errorf("the max length of data is %d but got %d", util.MaxDataSize, size)
- ty, out = generateErrorReport(err)
- }
+ bd = generateErrorReport(err)
}
-
- return ty, out
+ return bd
}
func handleConn(c net.Conn) {
@@ -122,8 +115,16 @@
break
}
- ty, out := dispatchRPC(ty, buf, c)
+ bd, err := dispatchRPC(ty, buf, c)
+ if err != nil {
+ util.PutBuilder(bd)
+ bd = generateErrorReport(err)
+ } else {
+ bd = checkIfDataTooLarge(bd)
+ }
+
+ out := bd.FinishedBytes()
size := len(out)
binary.BigEndian.PutUint32(header, uint32(size))
header[0] = ty
@@ -139,6 +140,8 @@
util.WriteErr(n, err)
break
}
+
+ util.PutBuilder(bd)
}
}
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index 74bf35c..606c2cb 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -27,7 +27,6 @@
"time"
hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
- flatbuffers "github.com/google/flatbuffers/go"
"github.com/stretchr/testify/assert"
"github.com/apache/apisix-go-plugin-runner/internal/util"
@@ -53,28 +52,23 @@
}
func TestDispatchRPC_UnknownType(t *testing.T) {
- ty, _ := dispatchRPC(126, []byte(""), nil)
- assert.Equal(t, byte(util.RPCError), ty)
+ _, err := dispatchRPC(126, []byte(""), nil)
+ assert.Equal(t, UnknownType{126}, err)
}
func TestDispatchRPC_OutTooLarge(t *testing.T) {
- dealRPCTest = func(buf []byte) (*flatbuffers.Builder, error) {
- builder := util.GetBuilder()
- bodyVec := builder.CreateByteVector(make([]byte, util.MaxDataSize+1))
- hrc.StopStart(builder)
- hrc.StopAddBody(builder, bodyVec)
- stop := hrc.StopEnd(builder)
+ builder := util.GetBuilder()
+ bodyVec := builder.CreateByteVector(make([]byte, util.MaxDataSize+1))
+ hrc.StopStart(builder)
+ hrc.StopAddBody(builder, bodyVec)
+ stop := hrc.StopEnd(builder)
- hrc.RespStart(builder)
- hrc.RespAddId(builder, 1)
- hrc.RespAddActionType(builder, hrc.ActionStop)
- hrc.RespAddAction(builder, stop)
- res := hrc.RespEnd(builder)
- builder.Finish(res)
- return builder, nil
- }
- ty, _ := dispatchRPC(util.RPCTest, []byte(""), nil)
- assert.Equal(t, byte(util.RPCError), ty)
+ hrc.RespStart(builder)
+ hrc.RespAddId(builder, 1)
+ hrc.RespAddActionType(builder, hrc.ActionStop)
+ hrc.RespAddAction(builder, stop)
+ res := hrc.RespEnd(builder)
+ builder.Finish(res)
}
func TestRun(t *testing.T) {